From 205cfcba200b13af31c39e67127cb3c07d491702 Mon Sep 17 00:00:00 2001 From: klensy Date: Wed, 21 Feb 2024 12:18:59 +0300 Subject: [PATCH 01/39] llvm-wrapper: fix warning C4244 llvm-wrapper/RustWrapper.cpp(1234): warning C4244: '=': conversion from 'uint64_t' to 'unsigned int', possible loss of data nice consistency: uint64_t https://github.com/llvm/llvm-project/blob/6009708b4367171ccdbf4b5905cb6a803753fe18/llvm/include/llvm/IR/DiagnosticInfo.h#L172 but unsigned https://github.com/llvm/llvm-project/blob/6009708b4367171ccdbf4b5905cb6a803753fe18/llvm/include/llvm/IR/DiagnosticInfo.h#L1091 --- compiler/rustc_codegen_llvm/src/back/write.rs | 6 +++--- compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs | 4 ++-- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 2 +- compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 27cb0366f17d..08aab8498680 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -36,7 +36,7 @@ use rustc_span::InnerSpan; use rustc_target::spec::{CodeModel, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel}; use crate::llvm::diagnostic::OptimizationDiagnosticKind; -use libc::{c_char, c_int, c_uint, c_void, size_t}; +use libc::{c_char, c_int, c_void, size_t}; use std::ffi::CString; use std::fs; use std::io::{self, Write}; @@ -406,7 +406,7 @@ fn report_inline_asm( cgcx: &CodegenContext, msg: String, level: llvm::DiagnosticLevel, - mut cookie: c_uint, + mut cookie: u64, source: Option<(String, Vec)>, ) { // In LTO build we may get srcloc values from other crates which are invalid @@ -420,7 +420,7 @@ fn report_inline_asm( llvm::DiagnosticLevel::Warning => Level::Warning, llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note, }; - cgcx.diag_emitter.inline_asm_error(cookie as u32, msg, level, source); + cgcx.diag_emitter.inline_asm_error(cookie.try_into().unwrap(), msg, level, source); } unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void) { diff --git a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs index 06e846a2b45e..f9b28178ddb9 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs @@ -123,7 +123,7 @@ impl SrcMgrDiagnostic { #[derive(Clone)] pub struct InlineAsmDiagnostic { pub level: super::DiagnosticLevel, - pub cookie: c_uint, + pub cookie: u64, pub message: String, pub source: Option<(String, Vec)>, } @@ -149,7 +149,7 @@ impl InlineAsmDiagnostic { let smdiag = SrcMgrDiagnostic::unpack(super::LLVMRustGetSMDiagnostic(di, &mut cookie)); InlineAsmDiagnostic { level: smdiag.level, - cookie, + cookie: cookie.into(), message: smdiag.message, source: smdiag.source, } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index d0044086c616..90116b90478a 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2254,7 +2254,7 @@ extern "C" { pub fn LLVMRustUnpackInlineAsmDiagnostic<'a>( DI: &'a DiagnosticInfo, level_out: &mut DiagnosticLevel, - cookie_out: &mut c_uint, + cookie_out: &mut u64, message_out: &mut Option<&'a Twine>, ); diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index b45706fd1e5b..e645f25c8d4e 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1225,7 +1225,7 @@ enum class LLVMRustDiagnosticLevel { extern "C" void LLVMRustUnpackInlineAsmDiagnostic(LLVMDiagnosticInfoRef DI, LLVMRustDiagnosticLevel *LevelOut, - unsigned *CookieOut, + uint64_t *CookieOut, LLVMTwineRef *MessageOut) { // Undefined to call this not on an inline assembly diagnostic! llvm::DiagnosticInfoInlineAsm *IA = From 0ce966fd6415773698fd9f85a86ef49dd4225ecf Mon Sep 17 00:00:00 2001 From: klensy Date: Wed, 21 Feb 2024 13:13:50 +0300 Subject: [PATCH 02/39] llvm-wrapper: fix warning C4305 llvm-wrapper/ArchiveWrapper.cpp(70): warning C4305: 'argument': truncation from 'int' to 'bool' while in llvm 12 signature was static ErrorOr> getFile(const Twine &Filename, int64_t FileSize = -1, bool RequiresNullTerminator = true, bool IsVolatile = false); https://github.com/llvm/llvm-project/blame/fed41342a82f5a3a9201819a82bf7a48313e296b/llvm/include/llvm/Support/MemoryBuffer.h#L85-L87 in llvm 13 and later it was changed to static ErrorOr> getFile(const Twine &Filename, bool IsText = false, bool RequiresNullTerminator = true, bool IsVolatile = false); https://github.com/llvm/llvm-project/blame/75e33f71c2dae584b13a7d1186ae0a038ba98838/llvm/include/llvm/Support/MemoryBuffer.h#L86-L88 so code was interpreted as MemoryBuffer::getFile(Path, /*IsText*/true, /*RequiresNullTerminator=*/false), but now will be MemoryBuffer::getFile(Path, /*IsText*/false, /*RequiresNullTerminator=*/false). How that worked before? --- compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp index 54fdc84c77d2..40723ff9f5ef 100644 --- a/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp @@ -67,7 +67,7 @@ typedef RustArchiveIterator *LLVMRustArchiveIteratorRef; extern "C" LLVMRustArchiveRef LLVMRustOpenArchive(char *Path) { ErrorOr> BufOr = - MemoryBuffer::getFile(Path, -1, false); + MemoryBuffer::getFile(Path, /*IsText*/false, /*RequiresNullTerminator=*/false); if (!BufOr) { LLVMRustSetLastError(BufOr.getError().message().c_str()); return nullptr; From 0621fa55f98ce1ff9e7512d85f08dd22abafe0e6 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 19 Feb 2024 19:17:29 -0300 Subject: [PATCH 03/39] Always use WaitOnAddress on Win10+ --- library/std/src/sys/pal/windows/c.rs | 28 ++- library/std/src/sys/pal/windows/compat.rs | 11 +- .../std/src/sys/pal/windows/thread_parking.rs | 229 ++++++++++-------- 3 files changed, 158 insertions(+), 110 deletions(-) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 6b12d7db8b03..b2760fa2e12f 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -28,17 +28,14 @@ pub type SIZE_T = usize; pub type WORD = u16; pub type CHAR = c_char; pub type ULONG = c_ulong; -pub type ACCESS_MASK = DWORD; pub type LPCVOID = *const c_void; -pub type LPHANDLE = *mut HANDLE; pub type LPOVERLAPPED = *mut OVERLAPPED; pub type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES; pub type LPVOID = *mut c_void; pub type LPWCH = *mut WCHAR; pub type LPWSTR = *mut WCHAR; -pub type PLARGE_INTEGER = *mut c_longlong; pub type PSRWLOCK = *mut SRWLOCK; pub type socklen_t = c_int; @@ -345,6 +342,19 @@ compat_fn_with_fallback! { } } +#[cfg(not(target_vendor = "win7"))] +#[link(name = "synchronization")] +extern "system" { + pub fn WaitOnAddress( + address: *const c_void, + compareaddress: *const c_void, + addresssize: usize, + dwmilliseconds: u32, + ) -> BOOL; + pub fn WakeByAddressSingle(address: *const c_void); +} + +#[cfg(target_vendor = "win7")] compat_fn_optional! { crate::sys::compat::load_synch_functions(); pub fn WaitOnAddress( @@ -356,30 +366,34 @@ compat_fn_optional! { pub fn WakeByAddressSingle(address: *const ::core::ffi::c_void); } +#[cfg(any(target_vendor = "win7", target_vendor = "uwp"))] compat_fn_with_fallback! { pub static NTDLL: &CStr = c"ntdll"; + #[cfg(target_vendor = "win7")] pub fn NtCreateKeyedEvent( - KeyedEventHandle: LPHANDLE, - DesiredAccess: ACCESS_MASK, + KeyedEventHandle: *mut HANDLE, + DesiredAccess: DWORD, ObjectAttributes: LPVOID, Flags: ULONG ) -> NTSTATUS { panic!("keyed events not available") } + #[cfg(target_vendor = "win7")] pub fn NtReleaseKeyedEvent( EventHandle: HANDLE, Key: LPVOID, Alertable: BOOLEAN, - Timeout: PLARGE_INTEGER + Timeout: *mut c_longlong ) -> NTSTATUS { panic!("keyed events not available") } + #[cfg(target_vendor = "win7")] pub fn NtWaitForKeyedEvent( EventHandle: HANDLE, Key: LPVOID, Alertable: BOOLEAN, - Timeout: PLARGE_INTEGER + Timeout: *mut c_longlong ) -> NTSTATUS { panic!("keyed events not available") } diff --git a/library/std/src/sys/pal/windows/compat.rs b/library/std/src/sys/pal/windows/compat.rs index f60b3a2c700f..f5d57a28db69 100644 --- a/library/std/src/sys/pal/windows/compat.rs +++ b/library/std/src/sys/pal/windows/compat.rs @@ -21,7 +21,6 @@ use crate::ffi::{c_void, CStr}; use crate::ptr::NonNull; -use crate::sync::atomic::Ordering; use crate::sys::c; // This uses a static initializer to preload some imported functions. @@ -38,6 +37,7 @@ use crate::sys::c; // file an issue for discussion; currently we don't guarantee any functionality // before main. // See https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-initialization?view=msvc-170 +#[cfg(target_vendor = "win7")] #[used] #[link_section = ".CRT$XCT"] static INIT_TABLE_ENTRY: unsafe extern "C" fn() = init; @@ -52,6 +52,7 @@ static INIT_TABLE_ENTRY: unsafe extern "C" fn() = init; /// negative performance impact in practical situations. /// /// Currently we only preload `WaitOnAddress` and `WakeByAddressSingle`. +#[cfg(target_vendor = "win7")] unsafe extern "C" fn init() { // In an exe this code is executed before main() so is single threaded. // In a DLL the system's loader lock will be held thereby synchronizing @@ -183,6 +184,7 @@ macro_rules! compat_fn_with_fallback { func($($argname),*) } } + #[allow(unused)] $(#[$meta])* $vis use $symbol::call as $symbol; )*) @@ -191,6 +193,7 @@ macro_rules! compat_fn_with_fallback { /// Optionally loaded functions. /// /// Actual loading of the function defers to $load_functions. +#[cfg(target_vendor = "win7")] macro_rules! compat_fn_optional { ($load_functions:expr; $( @@ -218,13 +221,19 @@ macro_rules! compat_fn_optional { NonNull::new(PTR.load(Ordering::Relaxed)).map(|f| unsafe { mem::transmute(f) }) } } + #[inline] + pub unsafe extern "system" fn $symbol($($argname: $argtype),*) $(-> $rettype)? { + $symbol::option().unwrap()($($argname),*) + } )+ ) } /// Load all needed functions from "api-ms-win-core-synch-l1-2-0". +#[cfg(target_vendor = "win7")] pub(super) fn load_synch_functions() { fn try_load() -> Option<()> { + use crate::sync::atomic::Ordering; const MODULE_NAME: &CStr = c"api-ms-win-core-synch-l1-2-0"; const WAIT_ON_ADDRESS: &CStr = c"WaitOnAddress"; const WAKE_BY_ADDRESS_SINGLE: &CStr = c"WakeByAddressSingle"; diff --git a/library/std/src/sys/pal/windows/thread_parking.rs b/library/std/src/sys/pal/windows/thread_parking.rs index 343b530b15ef..439ff84fbf18 100644 --- a/library/std/src/sys/pal/windows/thread_parking.rs +++ b/library/std/src/sys/pal/windows/thread_parking.rs @@ -58,10 +58,9 @@ // [4]: Windows Internals, Part 1, ISBN 9780735671300 use crate::pin::Pin; -use crate::ptr; use crate::sync::atomic::{ - AtomicI8, AtomicPtr, - Ordering::{Acquire, Relaxed, Release}, + AtomicI8, + Ordering::{Acquire, Release}, }; use crate::sys::{c, dur2timeout}; use crate::time::Duration; @@ -111,26 +110,21 @@ impl Parker { return; } - if let Some(wait_on_address) = c::WaitOnAddress::option() { - loop { - // Wait for something to happen, assuming it's still set to PARKED. - wait_on_address(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, c::INFINITE); - // Change NOTIFIED=>EMPTY but leave PARKED alone. - if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire).is_ok() { - // Actually woken up by unpark(). - return; - } else { - // Spurious wake up. We loop to try again. - } + #[cfg(target_vendor = "win7")] + if c::WaitOnAddress::option().is_none() { + return keyed_events::park(self); + } + + loop { + // Wait for something to happen, assuming it's still set to PARKED. + c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, c::INFINITE); + // Change NOTIFIED=>EMPTY but leave PARKED alone. + if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire).is_ok() { + // Actually woken up by unpark(). + return; + } else { + // Spurious wake up. We loop to try again. } - } else { - // Wait for unpark() to produce this event. - c::NtWaitForKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut()); - // Set the state back to EMPTY (from either PARKED or NOTIFIED). - // Note that we don't just write EMPTY, but use swap() to also - // include an acquire-ordered read to synchronize with unpark()'s - // release-ordered write. - self.state.swap(EMPTY, Acquire); } } @@ -144,47 +138,23 @@ impl Parker { return; } - if let Some(wait_on_address) = c::WaitOnAddress::option() { - // Wait for something to happen, assuming it's still set to PARKED. - wait_on_address(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, dur2timeout(timeout)); - // Set the state back to EMPTY (from either PARKED or NOTIFIED). - // Note that we don't just write EMPTY, but use swap() to also - // include an acquire-ordered read to synchronize with unpark()'s - // release-ordered write. - if self.state.swap(EMPTY, Acquire) == NOTIFIED { - // Actually woken up by unpark(). - } else { - // Timeout or spurious wake up. - // We return either way, because we can't easily tell if it was the - // timeout or not. - } + #[cfg(target_vendor = "win7")] + if c::WaitOnAddress::option().is_none() { + return keyed_events::park_timeout(self, timeout); + } + + // Wait for something to happen, assuming it's still set to PARKED. + c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, dur2timeout(timeout)); + // Set the state back to EMPTY (from either PARKED or NOTIFIED). + // Note that we don't just write EMPTY, but use swap() to also + // include an acquire-ordered read to synchronize with unpark()'s + // release-ordered write. + if self.state.swap(EMPTY, Acquire) == NOTIFIED { + // Actually woken up by unpark(). } else { - // Need to wait for unpark() using NtWaitForKeyedEvent. - let handle = keyed_event_handle(); - - // NtWaitForKeyedEvent uses a unit of 100ns, and uses negative - // values to indicate a relative time on the monotonic clock. - // This is documented here for the underlying KeWaitForSingleObject function: - // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-kewaitforsingleobject - let mut timeout = match i64::try_from((timeout.as_nanos() + 99) / 100) { - Ok(t) => -t, - Err(_) => i64::MIN, - }; - - // Wait for unpark() to produce this event. - let unparked = - c::NtWaitForKeyedEvent(handle, self.ptr(), 0, &mut timeout) == c::STATUS_SUCCESS; - - // Set the state back to EMPTY (from either PARKED or NOTIFIED). - let prev_state = self.state.swap(EMPTY, Acquire); - - if !unparked && prev_state == NOTIFIED { - // We were awoken by a timeout, not by unpark(), but the state - // was set to NOTIFIED, which means we *just* missed an - // unpark(), which is now blocked on us to wait for it. - // Wait for it to consume the event and unblock that thread. - c::NtWaitForKeyedEvent(handle, self.ptr(), 0, ptr::null_mut()); - } + // Timeout or spurious wake up. + // We return either way, because we can't easily tell if it was the + // timeout or not. } } @@ -198,18 +168,11 @@ impl Parker { // with park(). if self.state.swap(NOTIFIED, Release) == PARKED { unsafe { - if let Some(wake_by_address_single) = c::WakeByAddressSingle::option() { - wake_by_address_single(self.ptr()); - } else { - // If we run NtReleaseKeyedEvent before the waiting thread runs - // NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up. - // If the waiting thread wakes up before we run NtReleaseKeyedEvent - // (e.g. due to a timeout), this blocks until we do wake up a thread. - // To prevent this thread from blocking indefinitely in that case, - // park_impl() will, after seeing the state set to NOTIFIED after - // waking up, call NtWaitForKeyedEvent again to unblock us. - c::NtReleaseKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut()); + #[cfg(target_vendor = "win7")] + if c::WakeByAddressSingle::option().is_none() { + return keyed_events::unpark(self); } + c::WakeByAddressSingle(self.ptr()); } } } @@ -219,35 +182,97 @@ impl Parker { } } -fn keyed_event_handle() -> c::HANDLE { - const INVALID: c::HANDLE = ptr::without_provenance_mut(!0); - static HANDLE: AtomicPtr = AtomicPtr::new(INVALID); - match HANDLE.load(Relaxed) { - INVALID => { - let mut handle = c::INVALID_HANDLE_VALUE; - unsafe { - match c::NtCreateKeyedEvent( - &mut handle, - c::GENERIC_READ | c::GENERIC_WRITE, - ptr::null_mut(), - 0, - ) { - c::STATUS_SUCCESS => {} - r => panic!("Unable to create keyed event handle: error {r}"), - } - } - match HANDLE.compare_exchange(INVALID, handle, Relaxed, Relaxed) { - Ok(_) => handle, - Err(h) => { - // Lost the race to another thread initializing HANDLE before we did. - // Closing our handle and using theirs instead. - unsafe { - c::CloseHandle(handle); - } - h - } - } +#[cfg(target_vendor = "win7")] +mod keyed_events { + use super::{Parker, EMPTY, NOTIFIED}; + use crate::sys::c; + use core::pin::Pin; + use core::ptr; + use core::sync::atomic::{ + AtomicPtr, + Ordering::{Acquire, Relaxed}, + }; + use core::time::Duration; + + pub unsafe fn park(parker: Pin<&Parker>) { + // Wait for unpark() to produce this event. + c::NtWaitForKeyedEvent(keyed_event_handle(), parker.ptr(), 0, ptr::null_mut()); + // Set the state back to EMPTY (from either PARKED or NOTIFIED). + // Note that we don't just write EMPTY, but use swap() to also + // include an acquire-ordered read to synchronize with unpark()'s + // release-ordered write. + parker.state.swap(EMPTY, Acquire); + return; + } + pub unsafe fn park_timeout(parker: Pin<&Parker>, timeout: Duration) { + // Need to wait for unpark() using NtWaitForKeyedEvent. + let handle = keyed_event_handle(); + + // NtWaitForKeyedEvent uses a unit of 100ns, and uses negative + // values to indicate a relative time on the monotonic clock. + // This is documented here for the underlying KeWaitForSingleObject function: + // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-kewaitforsingleobject + let mut timeout = match i64::try_from((timeout.as_nanos() + 99) / 100) { + Ok(t) => -t, + Err(_) => i64::MIN, + }; + + // Wait for unpark() to produce this event. + let unparked = + c::NtWaitForKeyedEvent(handle, parker.ptr(), 0, &mut timeout) == c::STATUS_SUCCESS; + + // Set the state back to EMPTY (from either PARKED or NOTIFIED). + let prev_state = parker.state.swap(EMPTY, Acquire); + + if !unparked && prev_state == NOTIFIED { + // We were awoken by a timeout, not by unpark(), but the state + // was set to NOTIFIED, which means we *just* missed an + // unpark(), which is now blocked on us to wait for it. + // Wait for it to consume the event and unblock that thread. + c::NtWaitForKeyedEvent(handle, parker.ptr(), 0, ptr::null_mut()); + } + } + pub unsafe fn unpark(parker: Pin<&Parker>) { + // If we run NtReleaseKeyedEvent before the waiting thread runs + // NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up. + // If the waiting thread wakes up before we run NtReleaseKeyedEvent + // (e.g. due to a timeout), this blocks until we do wake up a thread. + // To prevent this thread from blocking indefinitely in that case, + // park_impl() will, after seeing the state set to NOTIFIED after + // waking up, call NtWaitForKeyedEvent again to unblock us. + c::NtReleaseKeyedEvent(keyed_event_handle(), parker.ptr(), 0, ptr::null_mut()); + } + + fn keyed_event_handle() -> c::HANDLE { + const INVALID: c::HANDLE = ptr::without_provenance_mut(!0); + static HANDLE: AtomicPtr = AtomicPtr::new(INVALID); + match HANDLE.load(Relaxed) { + INVALID => { + let mut handle = c::INVALID_HANDLE_VALUE; + unsafe { + match c::NtCreateKeyedEvent( + &mut handle, + c::GENERIC_READ | c::GENERIC_WRITE, + ptr::null_mut(), + 0, + ) { + c::STATUS_SUCCESS => {} + r => panic!("Unable to create keyed event handle: error {r}"), + } + } + match HANDLE.compare_exchange(INVALID, handle, Relaxed, Relaxed) { + Ok(_) => handle, + Err(h) => { + // Lost the race to another thread initializing HANDLE before we did. + // Closing our handle and using theirs instead. + unsafe { + c::CloseHandle(handle); + } + h + } + } + } + handle => handle, } - handle => handle, } } From 36f298c93dcf339f787077b38dc6dd9b2a3bd285 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 5 Feb 2024 13:27:47 +1100 Subject: [PATCH 04/39] Add some simple meta-tests for the handling of `filecheck` flags --- tests/codegen/meta-filecheck/check-prefix.rs | 4 ++++ tests/codegen/meta-filecheck/msvc-prefix-bad.rs | 7 +++++++ tests/codegen/meta-filecheck/msvc-prefix-good.rs | 7 +++++++ tests/codegen/meta-filecheck/no-directives.rs | 5 +++++ tests/codegen/meta-filecheck/revision-prefix.rs | 8 ++++++++ 5 files changed, 31 insertions(+) create mode 100644 tests/codegen/meta-filecheck/check-prefix.rs create mode 100644 tests/codegen/meta-filecheck/msvc-prefix-bad.rs create mode 100644 tests/codegen/meta-filecheck/msvc-prefix-good.rs create mode 100644 tests/codegen/meta-filecheck/no-directives.rs create mode 100644 tests/codegen/meta-filecheck/revision-prefix.rs diff --git a/tests/codegen/meta-filecheck/check-prefix.rs b/tests/codegen/meta-filecheck/check-prefix.rs new file mode 100644 index 000000000000..98bec68627e5 --- /dev/null +++ b/tests/codegen/meta-filecheck/check-prefix.rs @@ -0,0 +1,4 @@ +// Simple test that uses the default CHECK prefix and should always succeed. + +// CHECK: main +fn main() {} diff --git a/tests/codegen/meta-filecheck/msvc-prefix-bad.rs b/tests/codegen/meta-filecheck/msvc-prefix-bad.rs new file mode 100644 index 000000000000..f9984c74e2a3 --- /dev/null +++ b/tests/codegen/meta-filecheck/msvc-prefix-bad.rs @@ -0,0 +1,7 @@ +// This is exactly like `msvc-prefix-good.rs`, except that it should always fail. + +//@ should-fail + +// MSVC: text that should not match +// NONMSVC: text that should not match +fn main() {} diff --git a/tests/codegen/meta-filecheck/msvc-prefix-good.rs b/tests/codegen/meta-filecheck/msvc-prefix-good.rs new file mode 100644 index 000000000000..580d20d54382 --- /dev/null +++ b/tests/codegen/meta-filecheck/msvc-prefix-good.rs @@ -0,0 +1,7 @@ +// One of MSVC or NONMSVC should always be defined, so this test should pass. + +// (one of these should always be present) + +// MSVC: main +// NONMSVC: main +fn main() {} diff --git a/tests/codegen/meta-filecheck/no-directives.rs b/tests/codegen/meta-filecheck/no-directives.rs new file mode 100644 index 000000000000..2cab263604ef --- /dev/null +++ b/tests/codegen/meta-filecheck/no-directives.rs @@ -0,0 +1,5 @@ +// A test that doesn't include any filecheck directives should fail. + +//@ should-fail + +fn main() {} diff --git a/tests/codegen/meta-filecheck/revision-prefix.rs b/tests/codegen/meta-filecheck/revision-prefix.rs new file mode 100644 index 000000000000..431066e3acc0 --- /dev/null +++ b/tests/codegen/meta-filecheck/revision-prefix.rs @@ -0,0 +1,8 @@ +// The current revision name is registered as a filecheck prefix. + +//@ revisions: GOOD BAD +//@ [BAD] should-fail + +// GOOD: main +// BAD: text that should not match +fn main() {} From 1e432dd9f4b165ac36db19082176ddf6a828d0ca Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 3 Feb 2024 11:06:59 +1100 Subject: [PATCH 05/39] Simplify existing code for setting `filecheck` flags This removes a version check for LLVM >=13, and specifies prefixes as a series of independent `--check-prefix` flags instead of a single `--check-prefixes`. --- src/tools/compiletest/src/runtest.rs | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 27a8079d893f..3c417f3161b2 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2906,23 +2906,29 @@ impl<'test> TestCx<'test> { fn verify_with_filecheck(&self, output: &Path) -> ProcRes { let mut filecheck = Command::new(self.config.llvm_filecheck.as_ref().unwrap()); filecheck.arg("--input-file").arg(output).arg(&self.testpaths.file); + // It would be more appropriate to make most of the arguments configurable through // a comment-attribute similar to `compile-flags`. For example, --check-prefixes is a very // useful flag. // // For now, though… - let prefix_for_target = - if self.config.target.contains("msvc") { "MSVC" } else { "NONMSVC" }; - let prefixes = if let Some(rev) = self.revision { - format!("CHECK,{},{}", prefix_for_target, rev) - } else { - format!("CHECK,{}", prefix_for_target) - }; - if self.config.llvm_version.unwrap_or(0) >= 130000 { - filecheck.args(&["--allow-unused-prefixes", "--check-prefixes", &prefixes]); - } else { - filecheck.args(&["--check-prefixes", &prefixes]); + + // Because we use custom prefixes, we also have to register the default prefix. + filecheck.arg("--check-prefix=CHECK"); + + // Some tests use the current revision name as a check prefix. + if let Some(rev) = self.revision { + filecheck.arg("--check-prefix").arg(rev); } + + // Some tests also expect either the MSVC or NONMSVC prefix to be defined. + let msvc_or_not = if self.config.target.contains("msvc") { "MSVC" } else { "NONMSVC" }; + filecheck.arg("--check-prefix").arg(msvc_or_not); + + // The filecheck tool normally fails if a prefix is defined but not used. + // However, we define several prefixes globally for all tests. + filecheck.arg("--allow-unused-prefixes"); + // Provide more context on failures. filecheck.args(&["--dump-input-context", "100"]); self.compose_and_run(filecheck, "", None, None) From baec3076dbc612433210b7ab3366736e445f8c30 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 3 Feb 2024 11:15:05 +1100 Subject: [PATCH 06/39] Allow tests to specify a `//@ filecheck-flags:` header Any flags specified here will be passed to LLVM's `filecheck` tool, in tests that use that tool. --- src/tools/compiletest/src/header.rs | 8 ++++++++ src/tools/compiletest/src/runtest.rs | 11 ++++++----- tests/codegen/meta-filecheck/filecheck-flags.rs | 8 ++++++++ 3 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 tests/codegen/meta-filecheck/filecheck-flags.rs diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index c76cba824a37..6de445a57830 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -197,6 +197,8 @@ pub struct TestProps { /// Extra flags to pass to `llvm-cov` when producing coverage reports. /// Only used by the "coverage-run" test mode. pub llvm_cov_flags: Vec, + /// Extra flags to pass to LLVM's `filecheck` tool, in tests that use it. + pub filecheck_flags: Vec, } mod directives { @@ -236,6 +238,7 @@ mod directives { pub const REMAP_SRC_BASE: &'static str = "remap-src-base"; pub const COMPARE_OUTPUT_LINES_BY_SUBSET: &'static str = "compare-output-lines-by-subset"; pub const LLVM_COV_FLAGS: &'static str = "llvm-cov-flags"; + pub const FILECHECK_FLAGS: &'static str = "filecheck-flags"; // This isn't a real directive, just one that is probably mistyped often pub const INCORRECT_COMPILER_FLAGS: &'static str = "compiler-flags"; } @@ -286,6 +289,7 @@ impl TestProps { mir_unit_test: None, remap_src_base: false, llvm_cov_flags: vec![], + filecheck_flags: vec![], } } @@ -542,6 +546,10 @@ impl TestProps { if let Some(flags) = config.parse_name_value_directive(ln, LLVM_COV_FLAGS) { self.llvm_cov_flags.extend(split_flags(&flags)); } + + if let Some(flags) = config.parse_name_value_directive(ln, FILECHECK_FLAGS) { + self.filecheck_flags.extend(split_flags(&flags)); + } }, ); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 3c417f3161b2..6e0a7e6909a2 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2907,11 +2907,8 @@ impl<'test> TestCx<'test> { let mut filecheck = Command::new(self.config.llvm_filecheck.as_ref().unwrap()); filecheck.arg("--input-file").arg(output).arg(&self.testpaths.file); - // It would be more appropriate to make most of the arguments configurable through - // a comment-attribute similar to `compile-flags`. For example, --check-prefixes is a very - // useful flag. - // - // For now, though… + // FIXME: Consider making some of these prefix flags opt-in per test, + // via `filecheck-flags` or by adding new header directives. // Because we use custom prefixes, we also have to register the default prefix. filecheck.arg("--check-prefix=CHECK"); @@ -2931,6 +2928,10 @@ impl<'test> TestCx<'test> { // Provide more context on failures. filecheck.args(&["--dump-input-context", "100"]); + + // Add custom flags supplied by the `filecheck-flags:` test header. + filecheck.args(&self.props.filecheck_flags); + self.compose_and_run(filecheck, "", None, None) } diff --git a/tests/codegen/meta-filecheck/filecheck-flags.rs b/tests/codegen/meta-filecheck/filecheck-flags.rs new file mode 100644 index 000000000000..8e451cf4fdc9 --- /dev/null +++ b/tests/codegen/meta-filecheck/filecheck-flags.rs @@ -0,0 +1,8 @@ +// Arguments provided via `filecheck-flags` should be passed to `filecheck`. + +//@ revisions: good bad +//@ [good] filecheck-flags: --check-prefix=CUSTOM +//@ [bad] should-fail + +// CUSTOM: main +fn main() {} From c1889b549b6a88b580362b6f7914c8feb3b2a669 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 3 Feb 2024 11:14:46 +1100 Subject: [PATCH 07/39] Move existing coverage codegen tests into a subdirectory This makes room for migrating over `tests/run-make/instrument-coverage`, without increasing the number of top-level items in the codegen test directory. --- .../codegen/{ => instrument-coverage}/instrument-coverage-off.rs | 0 tests/codegen/{ => instrument-coverage}/instrument-coverage.rs | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/codegen/{ => instrument-coverage}/instrument-coverage-off.rs (100%) rename tests/codegen/{ => instrument-coverage}/instrument-coverage.rs (100%) diff --git a/tests/codegen/instrument-coverage-off.rs b/tests/codegen/instrument-coverage/instrument-coverage-off.rs similarity index 100% rename from tests/codegen/instrument-coverage-off.rs rename to tests/codegen/instrument-coverage/instrument-coverage-off.rs diff --git a/tests/codegen/instrument-coverage.rs b/tests/codegen/instrument-coverage/instrument-coverage.rs similarity index 100% rename from tests/codegen/instrument-coverage.rs rename to tests/codegen/instrument-coverage/instrument-coverage.rs From 0c19c632abeafc444201d1485334df0b973cf28b Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 3 Feb 2024 11:55:32 +1100 Subject: [PATCH 08/39] Convert `tests/run-make/instrument-coverage` to an ordinary codegen test This test was already very close to being an ordinary codegen test, except that it needed some extra logic to set a few variables based on (target) platform characteristics. Now that we have support for `//@ filecheck-flags:`, we can instead set those variables using the normal test revisions mechanism. --- tests/codegen/instrument-coverage/testprog.rs | 121 ++++++++++++++++++ tests/run-make/coverage-llvmir/Makefile | 64 --------- .../coverage-llvmir/filecheck.testprog.txt | 50 -------- tests/run-make/coverage-llvmir/testprog.rs | 38 ------ 4 files changed, 121 insertions(+), 152 deletions(-) create mode 100644 tests/codegen/instrument-coverage/testprog.rs delete mode 100644 tests/run-make/coverage-llvmir/Makefile delete mode 100644 tests/run-make/coverage-llvmir/filecheck.testprog.txt delete mode 100644 tests/run-make/coverage-llvmir/testprog.rs diff --git a/tests/codegen/instrument-coverage/testprog.rs b/tests/codegen/instrument-coverage/testprog.rs new file mode 100644 index 000000000000..39cf52d2c330 --- /dev/null +++ b/tests/codegen/instrument-coverage/testprog.rs @@ -0,0 +1,121 @@ +//@ edition: 2021 +//@ needs-profiler-support +//@ compile-flags: -Cinstrument-coverage -Copt-level=0 +//@ filecheck-flags: '-DDEFINE_INTERNAL=define internal' +//@ revisions: LINUX DARWIN WINDOWS + +//@ [LINUX] only-linux +//@ [LINUX] filecheck-flags: -DINSTR_PROF_DATA=__llvm_prf_data +//@ [LINUX] filecheck-flags: -DINSTR_PROF_NAME=__llvm_prf_names +//@ [LINUX] filecheck-flags: -DINSTR_PROF_CNTS=__llvm_prf_cnts +//@ [LINUX] filecheck-flags: -DINSTR_PROF_COVMAP=__llvm_covmap +//@ [LINUX] filecheck-flags: -DINSTR_PROF_COVFUN=__llvm_covfun +//@ [LINUX] filecheck-flags: '-DCOMDAT_IF_SUPPORTED=, comdat' + +//@ [DARWIN] only-macos +//@ [DARWIN] filecheck-flags: -DINSTR_PROF_DATA=__DATA,__llvm_prf_data,regular,live_support +//@ [DARWIN] filecheck-flags: -DINSTR_PROF_NAME=__DATA,__llvm_prf_names +//@ [DARWIN] filecheck-flags: -DINSTR_PROF_CNTS=__DATA,__llvm_prf_cnts +//@ [DARWIN] filecheck-flags: -DINSTR_PROF_COVMAP=__LLVM_COV,__llvm_covmap +//@ [DARWIN] filecheck-flags: -DINSTR_PROF_COVFUN=__LLVM_COV,__llvm_covfun +//@ [DARWIN] filecheck-flags: -DCOMDAT_IF_SUPPORTED= + +//@ [WINDOWS] only-windows +//@ [WINDOWS] filecheck-flags: -DINSTR_PROF_DATA=.lprfd$M +//@ [WINDOWS] filecheck-flags: -DINSTR_PROF_NAME=.lprfn$M +//@ [WINDOWS] filecheck-flags: -DINSTR_PROF_CNTS=.lprfc$M +//@ [WINDOWS] filecheck-flags: -DINSTR_PROF_COVMAP=.lcovmap$M +//@ [WINDOWS] filecheck-flags: -DINSTR_PROF_COVFUN=.lcovfun$M +//@ [WINDOWS] filecheck-flags: '-DCOMDAT_IF_SUPPORTED=, comdat' + +// ignore-tidy-linelength + +pub fn will_be_called() -> &'static str { + let val = "called"; + println!("{}", val); + val +} + +pub fn will_not_be_called() -> bool { + println!("should not have been called"); + false +} + +pub fn print(left: &str, value: T, right: &str) +where + T: std::fmt::Display, +{ + println!("{}{}{}", left, value, right); +} + +pub fn wrap_with(inner: T, should_wrap: bool, wrapper: F) +where + F: FnOnce(&T) +{ + if should_wrap { + wrapper(&inner) + } +} + +fn main() { + let less = 1; + let more = 100; + + if less < more { + wrap_with(will_be_called(), less < more, |inner| print(" ***", inner, "*** ")); + wrap_with(will_be_called(), more < less, |inner| print(" ***", inner, "*** ")); + } else { + wrap_with(will_not_be_called(), true, |inner| print("wrapped result is: ", inner, "")); + } +} + +// Check for metadata, variables, declarations, and function definitions injected +// into LLVM IR when compiling with -Cinstrument-coverage. + +// WINDOWS: $__llvm_profile_runtime_user = comdat any + +// CHECK: @__llvm_coverage_mapping = private constant +// CHECK-SAME: section "[[INSTR_PROF_COVMAP]]", align 8 + +// CHECK: @__covrec_{{[A-F0-9]+}}u = linkonce_odr hidden constant +// CHECK-SAME: section "[[INSTR_PROF_COVFUN]]"[[COMDAT_IF_SUPPORTED]], align 8 + +// WINDOWS: @__llvm_profile_runtime = external{{.*}}global i32 + +// CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global +// CHECK-SAME: section "[[INSTR_PROF_CNTS]]"{{.*}}, align 8 + +// CHECK: @__profd__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global +// CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called +// CHECK-SAME: section "[[INSTR_PROF_DATA]]"{{.*}}, align 8 + +// CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main = {{private|internal}} global +// CHECK-SAME: section "[[INSTR_PROF_CNTS]]"{{.*}}, align 8 + +// CHECK: @__profd__R{{[a-zA-Z0-9_]+}}testprog4main = {{private|internal}} global +// CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main +// CHECK-SAME: section "[[INSTR_PROF_DATA]]"{{.*}}, align 8 + +// CHECK: @__llvm_prf_nm = private constant +// CHECK-SAME: section "[[INSTR_PROF_NAME]]", align 1 + +// CHECK: @llvm.used = appending global +// CHECK-SAME: @__llvm_coverage_mapping +// CHECK-SAME: @__llvm_prf_nm +// CHECK-SAME: section "llvm.metadata" + +// CHECK: [[DEFINE_INTERNAL]] { {{.*}} } @_R{{[a-zA-Z0-9_]+}}testprog14will_be_called() unnamed_addr #{{[0-9]+}} { +// CHECK-NEXT: start: +// CHECK-NOT: [[DEFINE_INTERNAL]] +// CHECK: atomicrmw add ptr +// CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called, + +// CHECK: declare void @llvm.instrprof.increment(ptr, i64, i32, i32) #[[LLVM_INSTRPROF_INCREMENT_ATTR:[0-9]+]] + +// WINDOWS: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() #[[LLVM_PROFILE_RUNTIME_USER_ATTR:[0-9]+]] comdat { +// WINDOWS-NEXT: %1 = load i32, ptr @__llvm_profile_runtime +// WINDOWS-NEXT: ret i32 %1 +// WINDOWS-NEXT: } + +// CHECK: attributes #[[LLVM_INSTRPROF_INCREMENT_ATTR]] = { nounwind } +// WINDOWS: attributes #[[LLVM_PROFILE_RUNTIME_USER_ATTR]] = { noinline } diff --git a/tests/run-make/coverage-llvmir/Makefile b/tests/run-make/coverage-llvmir/Makefile deleted file mode 100644 index be92f8ac8fc9..000000000000 --- a/tests/run-make/coverage-llvmir/Makefile +++ /dev/null @@ -1,64 +0,0 @@ -# needs-profiler-support - -# Rust coverage maps support LLVM Coverage Mapping Format versions 5 and 6, -# corresponding with LLVM versions 12 and 13, respectively. -# When upgrading LLVM versions, consider whether to enforce a minimum LLVM -# version during testing, with an additional directive at the top of this file -# that sets, for example: `min-llvm-version: 12.0` - -include ../tools.mk - -BASEDIR=../coverage-llvmir - -ifeq ($(UNAME),Darwin) - INSTR_PROF_DATA_SUFFIX=,regular,live_support - DATA_SECTION_PREFIX=__DATA, - LLVM_COV_SECTION_PREFIX=__LLVM_COV, - COMDAT_IF_SUPPORTED= -else - INSTR_PROF_DATA_SUFFIX= - DATA_SECTION_PREFIX= - LLVM_COV_SECTION_PREFIX= - COMDAT_IF_SUPPORTED=, comdat -endif - -DEFINE_INTERNAL=define internal - -ifdef IS_WINDOWS - LLVM_FILECHECK_OPTIONS=\ - -check-prefixes=CHECK,WINDOWS \ - -DDEFINE_INTERNAL='$(DEFINE_INTERNAL)' \ - -DCOMDAT_IF_SUPPORTED='$(COMDAT_IF_SUPPORTED)' \ - -DINSTR_PROF_DATA='.lprfd$$M' \ - -DINSTR_PROF_NAME='.lprfn$$M' \ - -DINSTR_PROF_CNTS='.lprfc$$M' \ - -DINSTR_PROF_VALS='.lprfv$$M' \ - -DINSTR_PROF_VNODES='.lprfnd$$M' \ - -DINSTR_PROF_COVMAP='.lcovmap$$M' \ - -DINSTR_PROF_COVFUN='.lcovfun$$M' \ - -DINSTR_PROF_ORDERFILE='.lorderfile$$M' -else - LLVM_FILECHECK_OPTIONS=\ - -check-prefixes=CHECK \ - -DDEFINE_INTERNAL='$(DEFINE_INTERNAL)' \ - -DCOMDAT_IF_SUPPORTED='$(COMDAT_IF_SUPPORTED)' \ - -DINSTR_PROF_DATA='$(DATA_SECTION_PREFIX)__llvm_prf_data$(INSTR_PROF_DATA_SUFFIX)' \ - -DINSTR_PROF_NAME='$(DATA_SECTION_PREFIX)__llvm_prf_names' \ - -DINSTR_PROF_CNTS='$(DATA_SECTION_PREFIX)__llvm_prf_cnts' \ - -DINSTR_PROF_VALS='$(DATA_SECTION_PREFIX)__llvm_prf_vals' \ - -DINSTR_PROF_VNODES='$(DATA_SECTION_PREFIX)__llvm_prf_vnds' \ - -DINSTR_PROF_COVMAP='$(LLVM_COV_SECTION_PREFIX)__llvm_covmap' \ - -DINSTR_PROF_COVFUN='$(LLVM_COV_SECTION_PREFIX)__llvm_covfun' \ - -DINSTR_PROF_ORDERFILE='$(DATA_SECTION_PREFIX)__llvm_orderfile' -endif - -all: test_llvm_ir - -test_llvm_ir: - # Compile the test program with non-experimental coverage instrumentation, and generate LLVM IR - $(RUSTC) $(BASEDIR)/testprog.rs \ - -Cinstrument-coverage \ - --emit=llvm-ir - - cat "$(TMPDIR)"/testprog.ll | \ - "$(LLVM_FILECHECK)" $(BASEDIR)/filecheck.testprog.txt $(LLVM_FILECHECK_OPTIONS) diff --git a/tests/run-make/coverage-llvmir/filecheck.testprog.txt b/tests/run-make/coverage-llvmir/filecheck.testprog.txt deleted file mode 100644 index 8ab18da21a20..000000000000 --- a/tests/run-make/coverage-llvmir/filecheck.testprog.txt +++ /dev/null @@ -1,50 +0,0 @@ -# Check for metadata, variables, declarations, and function definitions injected -# into LLVM IR when compiling with -Cinstrument-coverage. - -WINDOWS: $__llvm_profile_runtime_user = comdat any - -CHECK: @__llvm_coverage_mapping = private constant -CHECK-SAME: section "[[INSTR_PROF_COVMAP]]", align 8 - -CHECK: @__covrec_{{[A-F0-9]+}}u = linkonce_odr hidden constant -CHECK-SAME: section "[[INSTR_PROF_COVFUN]]"[[COMDAT_IF_SUPPORTED]], align 8 - -WINDOWS: @__llvm_profile_runtime = external{{.*}}global i32 - -CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global -CHECK-SAME: section "[[INSTR_PROF_CNTS]]"{{.*}}, align 8 - -CHECK: @__profd__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global -CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called -CHECK-SAME: section "[[INSTR_PROF_DATA]]"{{.*}}, align 8 - -CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main = {{private|internal}} global -CHECK-SAME: section "[[INSTR_PROF_CNTS]]"{{.*}}, align 8 - -CHECK: @__profd__R{{[a-zA-Z0-9_]+}}testprog4main = {{private|internal}} global -CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main -CHECK-SAME: section "[[INSTR_PROF_DATA]]"{{.*}}, align 8 - -CHECK: @__llvm_prf_nm = private constant -CHECK-SAME: section "[[INSTR_PROF_NAME]]", align 1 - -CHECK: @llvm.used = appending global -CHECK-SAME: @__llvm_coverage_mapping -CHECK-SAME: @__llvm_prf_nm -CHECK-SAME: section "llvm.metadata" - -CHECK: [[DEFINE_INTERNAL]] { {{.*}} } @_R{{[a-zA-Z0-9_]+}}testprog14will_be_called() unnamed_addr #{{[0-9]+}} { -CHECK-NEXT: start: -CHECK-NOT: [[DEFINE_INTERNAL]] -CHECK: atomicrmw add ptr -CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called, - -CHECK: declare void @llvm.instrprof.increment(ptr, i64, i32, i32) #[[LLVM_INSTRPROF_INCREMENT_ATTR:[0-9]+]] - -WINDOWS: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() #[[LLVM_PROFILE_RUNTIME_USER_ATTR:[0-9]+]] comdat { -WINDOWS-NEXT: %1 = load i32, ptr @__llvm_profile_runtime -WINDOWS-NEXT: ret i32 %1 -WINDOWS-NEXT: } - -CHECK: attributes #[[LLVM_INSTRPROF_INCREMENT_ATTR]] = { nounwind } -WINDOWS: attributes #[[LLVM_PROFILE_RUNTIME_USER_ATTR]] = { noinline } diff --git a/tests/run-make/coverage-llvmir/testprog.rs b/tests/run-make/coverage-llvmir/testprog.rs deleted file mode 100644 index 358c25677ae1..000000000000 --- a/tests/run-make/coverage-llvmir/testprog.rs +++ /dev/null @@ -1,38 +0,0 @@ -pub fn will_be_called() -> &'static str { - let val = "called"; - println!("{}", val); - val -} - -pub fn will_not_be_called() -> bool { - println!("should not have been called"); - false -} - -pub fn print(left: &str, value: T, right: &str) -where - T: std::fmt::Display, -{ - println!("{}{}{}", left, value, right); -} - -pub fn wrap_with(inner: T, should_wrap: bool, wrapper: F) -where - F: FnOnce(&T) -{ - if should_wrap { - wrapper(&inner) - } -} - -fn main() { - let less = 1; - let more = 100; - - if less < more { - wrap_with(will_be_called(), less < more, |inner| print(" ***", inner, "*** ")); - wrap_with(will_be_called(), more < less, |inner| print(" ***", inner, "*** ")); - } else { - wrap_with(will_not_be_called(), true, |inner| print("wrapped result is: ", inner, "")); - } -} From e56cc8408d67afe5d58cdd4311ecc97ed44f14aa Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 5 Feb 2024 11:55:20 +1100 Subject: [PATCH 09/39] Remove unhelpful `DEFINE_INTERNAL` from filecheck flags This define was copied over from the run-make version of the test, but doesn't seem to serve any useful purpose. --- tests/codegen/instrument-coverage/testprog.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/codegen/instrument-coverage/testprog.rs b/tests/codegen/instrument-coverage/testprog.rs index 39cf52d2c330..b352cbdb7557 100644 --- a/tests/codegen/instrument-coverage/testprog.rs +++ b/tests/codegen/instrument-coverage/testprog.rs @@ -1,7 +1,6 @@ //@ edition: 2021 //@ needs-profiler-support //@ compile-flags: -Cinstrument-coverage -Copt-level=0 -//@ filecheck-flags: '-DDEFINE_INTERNAL=define internal' //@ revisions: LINUX DARWIN WINDOWS //@ [LINUX] only-linux @@ -104,9 +103,9 @@ fn main() { // CHECK-SAME: @__llvm_prf_nm // CHECK-SAME: section "llvm.metadata" -// CHECK: [[DEFINE_INTERNAL]] { {{.*}} } @_R{{[a-zA-Z0-9_]+}}testprog14will_be_called() unnamed_addr #{{[0-9]+}} { +// CHECK: define internal { {{.*}} } @_R{{[a-zA-Z0-9_]+}}testprog14will_be_called() unnamed_addr #{{[0-9]+}} { // CHECK-NEXT: start: -// CHECK-NOT: [[DEFINE_INTERNAL]] +// CHECK-NOT: define internal // CHECK: atomicrmw add ptr // CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called, From ccf789b674b696eaf99f28ab605d1a8e3279d1d0 Mon Sep 17 00:00:00 2001 From: surechen Date: Fri, 23 Feb 2024 17:23:01 +0800 Subject: [PATCH 10/39] By changing some attributes to only_local, reducing encoding attributes in the crate metadate. Thank you. This is part of changing attributes to only_local. I hope get your opinion whether I should split into multiple PRs, or submit in one. According to [try to not rely on attributes from extern crates](https://github.com/rust-lang/compiler-team/issues/505) and lcnr's guidance. --- compiler/rustc_feature/src/builtin_attrs.rs | 64 +++++++++++++++------ 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 99875ec54054..55fe80c7aefd 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -278,25 +278,35 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ungated!(cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ..."), DuplicatesOk), // Testing: - ungated!(ignore, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing), + ungated!( + ignore, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, + @only_local: true, + ), ungated!( should_panic, Normal, template!(Word, List: r#"expected = "reason""#, NameValueStr: "reason"), FutureWarnFollowing, + @only_local: true, ), // FIXME(Centril): This can be used on stable but shouldn't. - ungated!(reexport_test_harness_main, CrateLevel, template!(NameValueStr: "name"), ErrorFollowing), + ungated!( + reexport_test_harness_main, CrateLevel, template!(NameValueStr: "name"), ErrorFollowing, + @only_local: true, + ), // Macros: ungated!(automatically_derived, Normal, template!(Word), WarnFollowing), - ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ..."), WarnFollowingWordOnly), - ungated!(macro_escape, Normal, template!(Word), WarnFollowing), // Deprecated synonym for `macro_use`. - ungated!(macro_export, Normal, template!(Word, List: "local_inner_macros"), WarnFollowing), - ungated!(proc_macro, Normal, template!(Word), ErrorFollowing), ungated!( - proc_macro_derive, Normal, - template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)"), ErrorFollowing, + macro_use, Normal, template!(Word, List: "name1, name2, ..."), WarnFollowingWordOnly, + @only_local: true, ), - ungated!(proc_macro_attribute, Normal, template!(Word), ErrorFollowing), + ungated!(macro_escape, Normal, template!(Word), WarnFollowing, @only_local: true), // Deprecated synonym for `macro_use`. + ungated!(macro_export, Normal, template!(Word, List: "local_inner_macros"), WarnFollowing), + ungated!(proc_macro, Normal, template!(Word), ErrorFollowing, @only_local: true), + ungated!( + proc_macro_derive, Normal, template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)"), + ErrorFollowing, @only_local: true, + ), + ungated!(proc_macro_attribute, Normal, template!(Word), ErrorFollowing, @only_local: true), // Lints: ungated!( @@ -309,7 +319,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), gated!( expect, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk, - lint_reasons, experimental!(expect) + @only_local: true, lint_reasons, experimental!(expect) ), ungated!( forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), @@ -335,32 +345,48 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), // Crate properties: - ungated!(crate_name, CrateLevel, template!(NameValueStr: "name"), FutureWarnFollowing), - ungated!(crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), DuplicatesOk), + ungated!( + crate_name, CrateLevel, template!(NameValueStr: "name"), FutureWarnFollowing, + @only_local: true, + ), + ungated!( + crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), DuplicatesOk, + @only_local: true, + ), // crate_id is deprecated - ungated!(crate_id, CrateLevel, template!(NameValueStr: "ignored"), FutureWarnFollowing), + ungated!( + crate_id, CrateLevel, template!(NameValueStr: "ignored"), FutureWarnFollowing, + @only_local: true, + ), // ABI, linking, symbols, and FFI ungated!( link, Normal, template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated""#), DuplicatesOk, + @only_local: true, ), ungated!(link_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), - ungated!(no_link, Normal, template!(Word), WarnFollowing), + ungated!(no_link, Normal, template!(Word), WarnFollowing, @only_local: true), ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, @only_local: true), - ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), - ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), + ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, @only_local: true), + ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, @only_local: true), ungated!(no_mangle, Normal, template!(Word), WarnFollowing, @only_local: true), ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, @only_local: true), ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding), // Limits: - ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing), - ungated!(type_length_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing), + ungated!( + recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing, + @only_local: true + ), + ungated!( + type_length_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing, + @only_local: true + ), gated!( move_size_limit, CrateLevel, template!(NameValueStr: "N"), ErrorFollowing, - large_assignments, experimental!(move_size_limit) + @only_local: true, large_assignments, experimental!(move_size_limit) ), // Entry point: From f5b9eaf18f3486feaf6bf765409449e37b38f9d2 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 24 Feb 2024 11:19:14 +0100 Subject: [PATCH 11/39] Don't unnecessarily change `SIGPIPE` disposition in unix_sigpipe tests In `auxiliary/sigpipe-utils.rs`, all we want to know is the current `SIGPIPE` disposition. We should not change it. So use `libc::sigaction` instead of `libc::signal`. That way we can also remove the code that restores it. --- .../unix_sigpipe/auxiliary/sigpipe-utils.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/ui/attributes/unix_sigpipe/auxiliary/sigpipe-utils.rs b/tests/ui/attributes/unix_sigpipe/auxiliary/sigpipe-utils.rs index 74fbae0350e4..3d93d50ca3fb 100644 --- a/tests/ui/attributes/unix_sigpipe/auxiliary/sigpipe-utils.rs +++ b/tests/ui/attributes/unix_sigpipe/auxiliary/sigpipe-utils.rs @@ -17,17 +17,17 @@ pub fn assert_sigpipe_handler(expected_handler: SignalHandler) { target_os = "android", )))] { - let prev = unsafe { libc::signal(libc::SIGPIPE, libc::SIG_IGN) }; + let actual = unsafe { + let mut actual: libc::sigaction = std::mem::zeroed(); + libc::sigaction(libc::SIGPIPE, std::ptr::null(), &mut actual); + actual.sa_sigaction + }; let expected = match expected_handler { SignalHandler::Ignore => libc::SIG_IGN, SignalHandler::Default => libc::SIG_DFL, }; - assert_eq!(prev, expected, "expected sigpipe value matches actual value"); - // Unlikely to matter, but restore the old value anyway - unsafe { - libc::signal(libc::SIGPIPE, prev); - }; + assert_eq!(actual, expected, "actual and expected SIGPIPE disposition differs"); } } From cc3df0af7ba25a9a7bc82dac52e4b0fbb9d9713a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 23 Feb 2024 18:26:39 +0100 Subject: [PATCH 12/39] remove platform-intrinsics ABI; make SIMD intrinsics be regular intrinsics --- .../example/float-minmax-pass.rs | 4 +- .../src/error_codes/E0511.md | 8 +- compiler/rustc_feature/src/removed.rs | 3 + compiler/rustc_feature/src/unstable.rs | 2 - .../rustc_hir_analysis/src/check/check.rs | 11 -- .../rustc_hir_analysis/src/check/intrinsic.rs | 170 ++++++++---------- compiler/rustc_hir_analysis/src/check/mod.rs | 2 +- compiler/rustc_hir_analysis/src/collect.rs | 5 +- compiler/rustc_hir_typeck/src/coercion.rs | 6 +- compiler/rustc_lint/src/types.rs | 5 +- compiler/rustc_metadata/src/native_libs.rs | 2 +- compiler/rustc_middle/src/ty/layout.rs | 1 - compiler/rustc_middle/src/ty/util.rs | 2 +- .../src/ffi_unwind_calls.rs | 1 - compiler/rustc_passes/src/check_attr.rs | 4 +- compiler/rustc_passes/src/stability.rs | 5 +- .../rustc_smir/src/rustc_internal/internal.rs | 1 - .../rustc_smir/src/rustc_smir/convert/ty.rs | 1 - compiler/rustc_target/src/spec/abi/mod.rs | 15 +- compiler/rustc_target/src/spec/mod.rs | 1 - compiler/rustc_ty_utils/src/abi.rs | 15 +- compiler/stable_mir/src/ty.rs | 1 - library/core/src/intrinsics/simd.rs | 80 ++++++++- library/core/src/lib.rs | 2 +- library/std/src/lib.rs | 2 +- 25 files changed, 179 insertions(+), 170 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs b/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs index 80a2776ca1e2..eebd77083ec6 100644 --- a/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs +++ b/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs @@ -4,14 +4,14 @@ // Test that the simd_f{min,max} intrinsics produce the correct results. -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] struct f32x4(pub f32, pub f32, pub f32, pub f32); -extern "platform-intrinsic" { +extern "intrinsic" { fn simd_fmin(x: T, y: T) -> T; fn simd_fmax(x: T, y: T) -> T; } diff --git a/compiler/rustc_error_codes/src/error_codes/E0511.md b/compiler/rustc_error_codes/src/error_codes/E0511.md index 5351a685eb51..681f4e611c32 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0511.md +++ b/compiler/rustc_error_codes/src/error_codes/E0511.md @@ -3,9 +3,9 @@ Invalid monomorphization of an intrinsic function was used. Erroneous code example: ```compile_fail,E0511 -#![feature(platform_intrinsics)] +#![feature(intrinsics)] -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_add(a: T, b: T) -> T; } @@ -19,13 +19,13 @@ The generic type has to be a SIMD type. Example: ``` #![feature(repr_simd)] -#![feature(platform_intrinsics)] +#![feature(intrinsics)] #[repr(simd)] #[derive(Copy, Clone)] struct i32x2(i32, i32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_add(a: T, b: T) -> T; } diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 008c59e1be3d..05bb74807326 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -156,6 +156,9 @@ declare_features! ( Some("removed in favor of `#![feature(marker_trait_attr)]`")), (removed, panic_implementation, "1.28.0", Some(44489), Some("subsumed by `#[panic_handler]`")), + /// Allows `extern "platform-intrinsic" { ... }`. + (removed, platform_intrinsics, "1.4.0", Some(27731), + Some("SIMD intrinsics use the regular intrinsics ABI now")), /// Allows using `#![plugin(myplugin)]`. (removed, plugin, "1.75.0", Some(29597), Some("plugins are no longer supported")), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 93c183a65ef3..eb107e6ef3fa 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -259,8 +259,6 @@ declare_features! ( (internal, needs_panic_runtime, "1.10.0", Some(32837)), /// Allows using the `#![panic_runtime]` attribute. (internal, panic_runtime, "1.10.0", Some(32837)), - /// Allows `extern "platform-intrinsic" { ... }`. - (internal, platform_intrinsics, "1.4.0", Some(27731)), /// Allows using `#[rustc_allow_const_fn_unstable]`. /// This is an attribute on `const fn` for the same /// purpose as `#[allow_internal_unstable]`. diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index deabb9c37385..3d9aa428c743 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -612,17 +612,6 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { } } - Abi::PlatformIntrinsic => { - for item in items { - intrinsic::check_platform_intrinsic_type( - tcx, - item.id.owner_id.def_id, - item.span, - item.ident.name, - ); - } - } - _ => { for item in items { let def_id = item.id.owner_id.def_id; diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index d7277b22c841..f4b601f58b95 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -510,6 +510,77 @@ pub fn check_intrinsic_type( sym::debug_assertions => (0, 1, Vec::new(), tcx.types.bool), + sym::simd_eq + | sym::simd_ne + | sym::simd_lt + | sym::simd_le + | sym::simd_gt + | sym::simd_ge => (2, 0, vec![param(0), param(0)], param(1)), + sym::simd_add + | sym::simd_sub + | sym::simd_mul + | sym::simd_rem + | sym::simd_div + | sym::simd_shl + | sym::simd_shr + | sym::simd_and + | sym::simd_or + | sym::simd_xor + | sym::simd_fmin + | sym::simd_fmax + | sym::simd_fpow + | sym::simd_saturating_add + | sym::simd_saturating_sub => (1, 0, vec![param(0), param(0)], param(0)), + sym::simd_arith_offset => (2, 0, vec![param(0), param(1)], param(0)), + sym::simd_neg + | sym::simd_bswap + | sym::simd_bitreverse + | sym::simd_ctlz + | sym::simd_cttz + | sym::simd_fsqrt + | sym::simd_fsin + | sym::simd_fcos + | sym::simd_fexp + | sym::simd_fexp2 + | sym::simd_flog2 + | sym::simd_flog10 + | sym::simd_flog + | sym::simd_fabs + | sym::simd_ceil + | sym::simd_floor + | sym::simd_round + | sym::simd_trunc => (1, 0, vec![param(0)], param(0)), + sym::simd_fpowi => (1, 0, vec![param(0), tcx.types.i32], param(0)), + sym::simd_fma => (1, 0, vec![param(0), param(0), param(0)], param(0)), + sym::simd_gather => (3, 0, vec![param(0), param(1), param(2)], param(0)), + sym::simd_masked_load => (3, 0, vec![param(0), param(1), param(2)], param(2)), + sym::simd_masked_store => (3, 0, vec![param(0), param(1), param(2)], Ty::new_unit(tcx)), + sym::simd_scatter => (3, 0, vec![param(0), param(1), param(2)], Ty::new_unit(tcx)), + sym::simd_insert => (2, 0, vec![param(0), tcx.types.u32, param(1)], param(0)), + sym::simd_extract => (2, 0, vec![param(0), tcx.types.u32], param(1)), + sym::simd_cast + | sym::simd_as + | sym::simd_cast_ptr + | sym::simd_expose_addr + | sym::simd_from_exposed_addr => (2, 0, vec![param(0)], param(1)), + sym::simd_bitmask => (2, 0, vec![param(0)], param(1)), + sym::simd_select | sym::simd_select_bitmask => { + (2, 0, vec![param(0), param(1), param(1)], param(1)) + } + sym::simd_reduce_all | sym::simd_reduce_any => (1, 0, vec![param(0)], tcx.types.bool), + sym::simd_reduce_add_ordered | sym::simd_reduce_mul_ordered => { + (2, 0, vec![param(0), param(1)], param(1)) + } + sym::simd_reduce_add_unordered + | sym::simd_reduce_mul_unordered + | sym::simd_reduce_and + | sym::simd_reduce_or + | sym::simd_reduce_xor + | sym::simd_reduce_min + | sym::simd_reduce_max => (2, 0, vec![param(0)], param(1)), + sym::simd_shuffle => (3, 0, vec![param(0), param(0), param(1)], param(2)), + sym::simd_shuffle_generic => (2, 1, vec![param(0), param(0)], param(1)), + other => { tcx.dcx().emit_err(UnrecognizedIntrinsicFunction { span, name: other }); return; @@ -521,102 +592,3 @@ pub fn check_intrinsic_type( let sig = ty::Binder::bind_with_vars(sig, bound_vars); equate_intrinsic_type(tcx, span, intrinsic_id, n_tps, n_lts, n_cts, sig) } - -/// Type-check `extern "platform-intrinsic" { ... }` functions. -pub fn check_platform_intrinsic_type( - tcx: TyCtxt<'_>, - intrinsic_id: LocalDefId, - span: Span, - name: Symbol, -) { - let generics = tcx.generics_of(intrinsic_id); - let param = |n| { - if let Some(&ty::GenericParamDef { - name, kind: ty::GenericParamDefKind::Type { .. }, .. - }) = generics.opt_param_at(n as usize, tcx) - { - Ty::new_param(tcx, n, name) - } else { - Ty::new_error_with_message(tcx, span, "expected param") - } - }; - - let (n_tps, n_cts, inputs, output) = match name { - sym::simd_eq | sym::simd_ne | sym::simd_lt | sym::simd_le | sym::simd_gt | sym::simd_ge => { - (2, 0, vec![param(0), param(0)], param(1)) - } - sym::simd_add - | sym::simd_sub - | sym::simd_mul - | sym::simd_rem - | sym::simd_div - | sym::simd_shl - | sym::simd_shr - | sym::simd_and - | sym::simd_or - | sym::simd_xor - | sym::simd_fmin - | sym::simd_fmax - | sym::simd_fpow - | sym::simd_saturating_add - | sym::simd_saturating_sub => (1, 0, vec![param(0), param(0)], param(0)), - sym::simd_arith_offset => (2, 0, vec![param(0), param(1)], param(0)), - sym::simd_neg - | sym::simd_bswap - | sym::simd_bitreverse - | sym::simd_ctlz - | sym::simd_cttz - | sym::simd_fsqrt - | sym::simd_fsin - | sym::simd_fcos - | sym::simd_fexp - | sym::simd_fexp2 - | sym::simd_flog2 - | sym::simd_flog10 - | sym::simd_flog - | sym::simd_fabs - | sym::simd_ceil - | sym::simd_floor - | sym::simd_round - | sym::simd_trunc => (1, 0, vec![param(0)], param(0)), - sym::simd_fpowi => (1, 0, vec![param(0), tcx.types.i32], param(0)), - sym::simd_fma => (1, 0, vec![param(0), param(0), param(0)], param(0)), - sym::simd_gather => (3, 0, vec![param(0), param(1), param(2)], param(0)), - sym::simd_masked_load => (3, 0, vec![param(0), param(1), param(2)], param(2)), - sym::simd_masked_store => (3, 0, vec![param(0), param(1), param(2)], Ty::new_unit(tcx)), - sym::simd_scatter => (3, 0, vec![param(0), param(1), param(2)], Ty::new_unit(tcx)), - sym::simd_insert => (2, 0, vec![param(0), tcx.types.u32, param(1)], param(0)), - sym::simd_extract => (2, 0, vec![param(0), tcx.types.u32], param(1)), - sym::simd_cast - | sym::simd_as - | sym::simd_cast_ptr - | sym::simd_expose_addr - | sym::simd_from_exposed_addr => (2, 0, vec![param(0)], param(1)), - sym::simd_bitmask => (2, 0, vec![param(0)], param(1)), - sym::simd_select | sym::simd_select_bitmask => { - (2, 0, vec![param(0), param(1), param(1)], param(1)) - } - sym::simd_reduce_all | sym::simd_reduce_any => (1, 0, vec![param(0)], tcx.types.bool), - sym::simd_reduce_add_ordered | sym::simd_reduce_mul_ordered => { - (2, 0, vec![param(0), param(1)], param(1)) - } - sym::simd_reduce_add_unordered - | sym::simd_reduce_mul_unordered - | sym::simd_reduce_and - | sym::simd_reduce_or - | sym::simd_reduce_xor - | sym::simd_reduce_min - | sym::simd_reduce_max => (2, 0, vec![param(0)], param(1)), - sym::simd_shuffle => (3, 0, vec![param(0), param(0), param(1)], param(2)), - sym::simd_shuffle_generic => (2, 1, vec![param(0), param(0)], param(1)), - _ => { - let msg = format!("unrecognized platform-specific intrinsic function: `{name}`"); - tcx.dcx().span_err(span, msg); - return; - } - }; - - let sig = tcx.mk_fn_sig(inputs, output, false, hir::Unsafety::Unsafe, Abi::PlatformIntrinsic); - let sig = ty::Binder::dummy(sig); - equate_intrinsic_type(tcx, span, intrinsic_id, n_tps, 0, n_cts, sig) -} diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 36a92a4cf7cc..24280dbf0b3c 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -142,7 +142,7 @@ fn get_owner_return_paths( /// as they must always be defined by the compiler. // FIXME: Move this to a more appropriate place. pub fn forbid_intrinsic_abi(tcx: TyCtxt<'_>, sp: Span, abi: Abi) { - if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi { + if let Abi::RustIntrinsic = abi { tcx.dcx().span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block"); } } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index e9c9ec6ba53f..126766ce278b 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1677,10 +1677,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( // Feature gate SIMD types in FFI, since I am not sure that the // ABIs are handled at all correctly. -huonw - if abi != abi::Abi::RustIntrinsic - && abi != abi::Abi::PlatformIntrinsic - && !tcx.features().simd_ffi - { + if abi != abi::Abi::RustIntrinsic && !tcx.features().simd_ffi { let check = |ast_ty: &hir::Ty<'_>, ty: Ty<'_>| { if ty.is_simd() { let snip = tcx diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 9f6175eac135..1d1f58c6332f 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1173,11 +1173,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if let (Some(a_sig), Some(b_sig)) = (a_sig, b_sig) { // Intrinsics are not coercible to function pointers. - if a_sig.abi() == Abi::RustIntrinsic - || a_sig.abi() == Abi::PlatformIntrinsic - || b_sig.abi() == Abi::RustIntrinsic - || b_sig.abi() == Abi::PlatformIntrinsic - { + if a_sig.abi() == Abi::RustIntrinsic || b_sig.abi() == Abi::RustIntrinsic { return Err(TypeError::IntrinsicCast); } // The signature must match. diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index e4ebae2a9732..2ea891ce04d0 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1587,10 +1587,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } fn is_internal_abi(&self, abi: SpecAbi) -> bool { - matches!( - abi, - SpecAbi::Rust | SpecAbi::RustCall | SpecAbi::RustIntrinsic | SpecAbi::PlatformIntrinsic - ) + matches!(abi, SpecAbi::Rust | SpecAbi::RustCall | SpecAbi::RustIntrinsic) } /// Find any fn-ptr types with external ABIs in `ty`. diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 5e20a03bbc0c..cdcc586b09e7 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -99,7 +99,7 @@ impl<'tcx> Collector<'tcx> { let sess = self.tcx.sess; - if matches!(abi, Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic) { + if matches!(abi, Abi::Rust | Abi::RustIntrinsic) { return; } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index c1e33fe114fb..38aca3326d3b 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1244,7 +1244,6 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option, abi: SpecAbi) -> | RiscvInterruptS | CCmseNonSecureCall | Wasm - | PlatformIntrinsic | Unadjusted => false, Rust | RustCall | RustCold | RustIntrinsic => { tcx.sess.panic_strategy() == PanicStrategy::Unwind diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 72a1905c147a..5ead620927cd 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1643,7 +1643,7 @@ pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool { /// Determines whether an item is an intrinsic by Abi. or by whether it has a `rustc_intrinsic` attribute pub fn intrinsic(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { - if matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic) + if matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic) || tcx.has_attr(def_id, sym::rustc_intrinsic) { Some(tcx.item_name(def_id.into())) diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs index 663abbece851..0dc06524c794 100644 --- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -34,7 +34,6 @@ fn abi_can_unwind(abi: Abi) -> bool { | CCmseNonSecureCall | Wasm | RustIntrinsic - | PlatformIntrinsic | Unadjusted => false, Rust | RustCall | RustCold => true, } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d8ae82d11bcf..194533047d4a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1389,7 +1389,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if target == Target::ForeignMod && let hir::Node::Item(item) = self.tcx.hir_node(hir_id) && let Item { kind: ItemKind::ForeignMod { abi, .. }, .. } = item - && !matches!(abi, Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic) + && !matches!(abi, Abi::Rust | Abi::RustIntrinsic) { return; } @@ -2071,7 +2071,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ) -> bool { if let Target::ForeignFn = target && let hir::Node::Item(Item { - kind: ItemKind::ForeignMod { abi: Abi::RustIntrinsic | Abi::PlatformIntrinsic, .. }, + kind: ItemKind::ForeignMod { abi: Abi::RustIntrinsic, .. }, .. }) = self.tcx.parent_hir_node(hir_id) { diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 19272b52b32e..05c833cdfb65 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -173,10 +173,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { // If the current node is a function, has const stability attributes and if it doesn not have an intrinsic ABI, // check if the function/method is const or the parent impl block is const if let (Some(const_span), Some(fn_sig)) = (const_span, fn_sig) { - if fn_sig.header.abi != Abi::RustIntrinsic - && fn_sig.header.abi != Abi::PlatformIntrinsic - && !fn_sig.header.is_const() - { + if fn_sig.header.abi != Abi::RustIntrinsic && !fn_sig.header.is_const() { if !self.in_trait_impl || (self.in_trait_impl && !self.tcx.is_const_fn_raw(def_id.to_def_id())) { diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index 6bbfcff5e87c..2cc9bc31873a 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -457,7 +457,6 @@ impl RustcInternal for Abi { Abi::System { unwind } => rustc_target::spec::abi::Abi::System { unwind }, Abi::RustIntrinsic => rustc_target::spec::abi::Abi::RustIntrinsic, Abi::RustCall => rustc_target::spec::abi::Abi::RustCall, - Abi::PlatformIntrinsic => rustc_target::spec::abi::Abi::PlatformIntrinsic, Abi::Unadjusted => rustc_target::spec::abi::Abi::Unadjusted, Abi::RustCold => rustc_target::spec::abi::Abi::RustCold, Abi::RiscvInterruptM => rustc_target::spec::abi::Abi::RiscvInterruptM, diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 29081418200e..a066b9ed3aa2 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -833,7 +833,6 @@ impl<'tcx> Stable<'tcx> for rustc_target::spec::abi::Abi { abi::Abi::System { unwind } => Abi::System { unwind }, abi::Abi::RustIntrinsic => Abi::RustIntrinsic, abi::Abi::RustCall => Abi::RustCall, - abi::Abi::PlatformIntrinsic => Abi::PlatformIntrinsic, abi::Abi::Unadjusted => Abi::Unadjusted, abi::Abi::RustCold => Abi::RustCold, abi::Abi::RiscvInterruptM => Abi::RiscvInterruptM, diff --git a/compiler/rustc_target/src/spec/abi/mod.rs b/compiler/rustc_target/src/spec/abi/mod.rs index 6231787bb9fd..388e76d83e24 100644 --- a/compiler/rustc_target/src/spec/abi/mod.rs +++ b/compiler/rustc_target/src/spec/abi/mod.rs @@ -54,7 +54,6 @@ pub enum Abi { }, RustIntrinsic, RustCall, - PlatformIntrinsic, Unadjusted, /// For things unlikely to be called, where reducing register pressure in /// `extern "Rust"` callers is worth paying extra cost in the callee. @@ -129,7 +128,6 @@ const AbiDatas: &[AbiData] = &[ AbiData { abi: Abi::System { unwind: true }, name: "system-unwind" }, AbiData { abi: Abi::RustIntrinsic, name: "rust-intrinsic" }, AbiData { abi: Abi::RustCall, name: "rust-call" }, - AbiData { abi: Abi::PlatformIntrinsic, name: "platform-intrinsic" }, AbiData { abi: Abi::Unadjusted, name: "unadjusted" }, AbiData { abi: Abi::RustCold, name: "rust-cold" }, AbiData { abi: Abi::RiscvInterruptM, name: "riscv-interrupt-m" }, @@ -199,10 +197,6 @@ pub fn is_stable(name: &str) -> Result<(), AbiDisabled> { feature: sym::intrinsics, explain: "intrinsics are subject to change", }), - "platform-intrinsic" => Err(AbiDisabled::Unstable { - feature: sym::platform_intrinsics, - explain: "platform intrinsics are experimental and possibly buggy", - }), "vectorcall" => Err(AbiDisabled::Unstable { feature: sym::abi_vectorcall, explain: "vectorcall is experimental and subject to change", @@ -299,11 +293,10 @@ impl Abi { System { unwind: true } => 28, RustIntrinsic => 29, RustCall => 30, - PlatformIntrinsic => 31, - Unadjusted => 32, - RustCold => 33, - RiscvInterruptM => 34, - RiscvInterruptS => 35, + Unadjusted => 31, + RustCold => 32, + RiscvInterruptM => 33, + RiscvInterruptS => 34, }; debug_assert!( AbiDatas diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index d04bcb2d78aa..084a8b9db81e 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2448,7 +2448,6 @@ impl Target { | System { .. } | RustIntrinsic | RustCall - | PlatformIntrinsic | Unadjusted | Cdecl { .. } | RustCold => true, diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 638c9a53d22a..43042dbd3664 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -312,7 +312,7 @@ fn fn_sig_for_fn_abi<'tcx>( fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi, c_variadic: bool) -> Conv { use rustc_target::spec::abi::Abi::*; match tcx.sess.target.adjust_abi(abi, c_variadic) { - RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust, + RustIntrinsic | Rust | RustCall => Conv::Rust, // This is intentionally not using `Conv::Cold`, as that has to preserve // even SIMD registers, which is generally not a good trade-off. @@ -605,7 +605,7 @@ fn fn_abi_new_uncached<'tcx>( let linux_powerpc_gnu_like = target.os == "linux" && target.arch == "powerpc" && target_env_gnu_like; use SpecAbi::*; - let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall); + let rust_abi = matches!(sig.abi, RustIntrinsic | Rust | RustCall); let is_drop_in_place = fn_def_id.is_some() && fn_def_id == cx.tcx.lang_items().drop_in_place_fn(); @@ -713,11 +713,7 @@ fn fn_abi_adjust_for_abi<'tcx>( return Ok(()); } - if abi == SpecAbi::Rust - || abi == SpecAbi::RustCall - || abi == SpecAbi::RustIntrinsic - || abi == SpecAbi::PlatformIntrinsic - { + if abi == SpecAbi::Rust || abi == SpecAbi::RustCall || abi == SpecAbi::RustIntrinsic { // Look up the deduced parameter attributes for this function, if we have its def ID and // we're optimizing in non-incremental mode. We'll tag its parameters with those attributes // as appropriate. @@ -753,12 +749,11 @@ fn fn_abi_adjust_for_abi<'tcx>( // target feature sets. Some more information about this // issue can be found in #44367. // - // Note that the platform intrinsic ABI is exempt here as + // Note that the intrinsic ABI is exempt here as // that's how we connect up to LLVM and it's unstable // anyway, we control all calls to it in libstd. Abi::Vector { .. } - if abi != SpecAbi::PlatformIntrinsic - && cx.tcx.sess.target.simd_types_indirect => + if abi != SpecAbi::RustIntrinsic && cx.tcx.sess.target.simd_types_indirect => { arg.make_indirect(); return; diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 658e8aa28b54..ed4a4290246b 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -906,7 +906,6 @@ pub enum Abi { System { unwind: bool }, RustIntrinsic, RustCall, - PlatformIntrinsic, Unadjusted, RustCold, RiscvInterruptM, diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index d8a1ad778d75..2eaca3b6fe4d 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -2,7 +2,11 @@ //! //! In this module, a "vector" is any `repr(simd)` type. -extern "platform-intrinsic" { +// Temporary macro while we switch the ABI from "platform-intrinsics" to "intrinsics". +#[rustfmt::skip] +macro_rules! declare_intrinsics { +($abi:tt) => { +extern $abi { /// Insert an element into a vector, returning the updated vector. /// /// `T` must be a vector with element type `U`. @@ -10,6 +14,7 @@ extern "platform-intrinsic" { /// # Safety /// /// `idx` must be in-bounds of the vector. + #[rustc_nounwind] pub fn simd_insert(x: T, idx: u32, val: U) -> T; /// Extract an element from a vector. @@ -19,21 +24,25 @@ extern "platform-intrinsic" { /// # Safety /// /// `idx` must be in-bounds of the vector. + #[rustc_nounwind] pub fn simd_extract(x: T, idx: u32) -> U; /// Add two simd vectors elementwise. /// /// `T` must be a vector of integer or floating point primitive types. + #[rustc_nounwind] pub fn simd_add(x: T, y: T) -> T; /// Subtract `rhs` from `lhs` elementwise. /// /// `T` must be a vector of integer or floating point primitive types. + #[rustc_nounwind] pub fn simd_sub(lhs: T, rhs: T) -> T; /// Multiply two simd vectors elementwise. /// /// `T` must be a vector of integer or floating point primitive types. + #[rustc_nounwind] pub fn simd_mul(x: T, y: T) -> T; /// Divide `lhs` by `rhs` elementwise. @@ -43,6 +52,7 @@ extern "platform-intrinsic" { /// # Safety /// For integers, `rhs` must not contain any zero elements. /// Additionally for signed integers, `::MIN / -1` is undefined behavior. + #[rustc_nounwind] pub fn simd_div(lhs: T, rhs: T) -> T; /// Remainder of two vectors elementwise @@ -52,6 +62,7 @@ extern "platform-intrinsic" { /// # Safety /// For integers, `rhs` must not contain any zero elements. /// Additionally for signed integers, `::MIN / -1` is undefined behavior. + #[rustc_nounwind] pub fn simd_rem(lhs: T, rhs: T) -> T; /// Elementwise vector left shift, with UB on overflow. @@ -63,6 +74,7 @@ extern "platform-intrinsic" { /// # Safety /// /// Each element of `rhs` must be less than `::BITS`. + #[rustc_nounwind] pub fn simd_shl(lhs: T, rhs: T) -> T; /// Elementwise vector right shift, with UB on overflow. @@ -74,21 +86,25 @@ extern "platform-intrinsic" { /// # Safety /// /// Each element of `rhs` must be less than `::BITS`. + #[rustc_nounwind] pub fn simd_shr(lhs: T, rhs: T) -> T; /// Elementwise vector "and". /// /// `T` must be a vector of integer primitive types. + #[rustc_nounwind] pub fn simd_and(x: T, y: T) -> T; /// Elementwise vector "or". /// /// `T` must be a vector of integer primitive types. + #[rustc_nounwind] pub fn simd_or(x: T, y: T) -> T; /// Elementwise vector "exclusive or". /// /// `T` must be a vector of integer primitive types. + #[rustc_nounwind] pub fn simd_xor(x: T, y: T) -> T; /// Numerically cast a vector, elementwise. @@ -109,6 +125,7 @@ extern "platform-intrinsic" { /// * Not be `NaN` /// * Not be infinite /// * Be representable in the return type, after truncating off its fractional part + #[rustc_nounwind] pub fn simd_cast(x: T) -> U; /// Numerically cast a vector, elementwise. @@ -122,6 +139,7 @@ extern "platform-intrinsic" { /// When casting floats to integers, the result is truncated. /// When casting integers to floats, the result is rounded. /// Otherwise, truncates or extends the value, maintaining the sign for signed integers. + #[rustc_nounwind] pub fn simd_as(x: T) -> U; /// Elementwise negation of a vector. @@ -129,11 +147,13 @@ extern "platform-intrinsic" { /// `T` must be a vector of integer or floating-point primitive types. /// /// Rust panics for `-::Min` due to overflow, but it is not UB with this intrinsic. + #[rustc_nounwind] pub fn simd_neg(x: T) -> T; /// Elementwise absolute value of a vector. /// /// `T` must be a vector of floating-point primitive types. + #[rustc_nounwind] pub fn simd_fabs(x: T) -> T; /// Elementwise minimum of a vector. @@ -141,6 +161,7 @@ extern "platform-intrinsic" { /// `T` must be a vector of floating-point primitive types. /// /// Follows IEEE-754 `minNum` semantics. + #[rustc_nounwind] pub fn simd_fmin(x: T, y: T) -> T; /// Elementwise maximum of a vector. @@ -148,6 +169,7 @@ extern "platform-intrinsic" { /// `T` must be a vector of floating-point primitive types. /// /// Follows IEEE-754 `maxNum` semantics. + #[rustc_nounwind] pub fn simd_fmax(x: T, y: T) -> T; /// Tests elementwise equality of two vectors. @@ -157,6 +179,7 @@ extern "platform-intrinsic" { /// `U` must be a vector of integers with the same number of elements and element size as `T`. /// /// Returns `0` for false and `!0` for true. + #[rustc_nounwind] pub fn simd_eq(x: T, y: T) -> U; /// Tests elementwise inequality equality of two vectors. @@ -166,6 +189,7 @@ extern "platform-intrinsic" { /// `U` must be a vector of integers with the same number of elements and element size as `T`. /// /// Returns `0` for false and `!0` for true. + #[rustc_nounwind] pub fn simd_ne(x: T, y: T) -> U; /// Tests if `x` is less than `y`, elementwise. @@ -175,6 +199,7 @@ extern "platform-intrinsic" { /// `U` must be a vector of integers with the same number of elements and element size as `T`. /// /// Returns `0` for false and `!0` for true. + #[rustc_nounwind] pub fn simd_lt(x: T, y: T) -> U; /// Tests if `x` is less than or equal to `y`, elementwise. @@ -184,6 +209,7 @@ extern "platform-intrinsic" { /// `U` must be a vector of integers with the same number of elements and element size as `T`. /// /// Returns `0` for false and `!0` for true. + #[rustc_nounwind] pub fn simd_le(x: T, y: T) -> U; /// Tests if `x` is greater than `y`, elementwise. @@ -193,6 +219,7 @@ extern "platform-intrinsic" { /// `U` must be a vector of integers with the same number of elements and element size as `T`. /// /// Returns `0` for false and `!0` for true. + #[rustc_nounwind] pub fn simd_gt(x: T, y: T) -> U; /// Tests if `x` is greater than or equal to `y`, elementwise. @@ -202,6 +229,7 @@ extern "platform-intrinsic" { /// `U` must be a vector of integers with the same number of elements and element size as `T`. /// /// Returns `0` for false and `!0` for true. + #[rustc_nounwind] pub fn simd_ge(x: T, y: T) -> U; /// Shuffle two vectors by const indices. @@ -216,6 +244,7 @@ extern "platform-intrinsic" { /// Returns a new vector such that element `i` is selected from `xy[idx[i]]`, where `xy` /// is the concatenation of `x` and `y`. It is a compile-time error if `idx[i]` is out-of-bounds /// of `xy`. + #[rustc_nounwind] pub fn simd_shuffle(x: T, y: T, idx: U) -> V; /// Shuffle two vectors by const indices. @@ -227,6 +256,7 @@ extern "platform-intrinsic" { /// Returns a new vector such that element `i` is selected from `xy[IDX[i]]`, where `xy` /// is the concatenation of `x` and `y`. It is a compile-time error if `IDX[i]` is out-of-bounds /// of `xy`. + #[rustc_nounwind] pub fn simd_shuffle_generic(x: T, y: T) -> U; /// Read a vector of pointers. @@ -249,6 +279,7 @@ extern "platform-intrinsic" { /// type). /// /// `mask` must only contain `0` or `!0` values. + #[rustc_nounwind] pub fn simd_gather(val: T, ptr: U, mask: V) -> T; /// Write to a vector of pointers. @@ -271,6 +302,7 @@ extern "platform-intrinsic" { /// type). /// /// `mask` must only contain `0` or `!0` values. + #[rustc_nounwind] pub fn simd_scatter(val: T, ptr: U, mask: V); /// Read a vector of pointers. @@ -292,6 +324,7 @@ extern "platform-intrinsic" { /// type). /// /// `mask` must only contain `0` or `!0` values. + #[rustc_nounwind] pub fn simd_masked_load(mask: V, ptr: U, val: T) -> T; /// Write to a vector of pointers. @@ -312,11 +345,13 @@ extern "platform-intrinsic" { /// type). /// /// `mask` must only contain `0` or `!0` values. + #[rustc_nounwind] pub fn simd_masked_store(mask: V, ptr: U, val: T); /// Add two simd vectors elementwise, with saturation. /// /// `T` must be a vector of integer primitive types. + #[rustc_nounwind] pub fn simd_saturating_add(x: T, y: T) -> T; /// Subtract two simd vectors elementwise, with saturation. @@ -324,6 +359,7 @@ extern "platform-intrinsic" { /// `T` must be a vector of integer primitive types. /// /// Subtract `rhs` from `lhs`. + #[rustc_nounwind] pub fn simd_saturating_sub(lhs: T, rhs: T) -> T; /// Add elements within a vector from left to right. @@ -333,6 +369,7 @@ extern "platform-intrinsic" { /// `U` must be the element type of `T`. /// /// Starting with the value `y`, add the elements of `x` and accumulate. + #[rustc_nounwind] pub fn simd_reduce_add_ordered(x: T, y: U) -> U; /// Add elements within a vector in arbitrary order. May also be re-associated with @@ -341,6 +378,7 @@ extern "platform-intrinsic" { /// `T` must be a vector of integer or floating-point primitive types. /// /// `U` must be the element type of `T`. + #[rustc_nounwind] pub fn simd_reduce_add_unordered(x: T) -> U; /// Multiply elements within a vector from left to right. @@ -350,6 +388,7 @@ extern "platform-intrinsic" { /// `U` must be the element type of `T`. /// /// Starting with the value `y`, multiply the elements of `x` and accumulate. + #[rustc_nounwind] pub fn simd_reduce_mul_ordered(x: T, y: U) -> U; /// Add elements within a vector in arbitrary order. May also be re-associated with @@ -358,6 +397,7 @@ extern "platform-intrinsic" { /// `T` must be a vector of integer or floating-point primitive types. /// /// `U` must be the element type of `T`. + #[rustc_nounwind] pub fn simd_reduce_mul_unordered(x: T) -> U; /// Check if all mask values are true. @@ -366,6 +406,7 @@ extern "platform-intrinsic" { /// /// # Safety /// `x` must contain only `0` or `!0`. + #[rustc_nounwind] pub fn simd_reduce_all(x: T) -> bool; /// Check if all mask values are true. @@ -374,6 +415,7 @@ extern "platform-intrinsic" { /// /// # Safety /// `x` must contain only `0` or `!0`. + #[rustc_nounwind] pub fn simd_reduce_any(x: T) -> bool; /// Return the maximum element of a vector. @@ -383,6 +425,7 @@ extern "platform-intrinsic" { /// `U` must be the element type of `T`. /// /// For floating-point values, uses IEEE-754 `maxNum`. + #[rustc_nounwind] pub fn simd_reduce_max(x: T) -> U; /// Return the minimum element of a vector. @@ -392,6 +435,7 @@ extern "platform-intrinsic" { /// `U` must be the element type of `T`. /// /// For floating-point values, uses IEEE-754 `minNum`. + #[rustc_nounwind] pub fn simd_reduce_min(x: T) -> U; /// Logical "and" all elements together. @@ -399,6 +443,7 @@ extern "platform-intrinsic" { /// `T` must be a vector of integer or floating-point primitive types. /// /// `U` must be the element type of `T`. + #[rustc_nounwind] pub fn simd_reduce_and(x: T) -> U; /// Logical "or" all elements together. @@ -406,6 +451,7 @@ extern "platform-intrinsic" { /// `T` must be a vector of integer or floating-point primitive types. /// /// `U` must be the element type of `T`. + #[rustc_nounwind] pub fn simd_reduce_or(x: T) -> U; /// Logical "exclusive or" all elements together. @@ -413,6 +459,7 @@ extern "platform-intrinsic" { /// `T` must be a vector of integer or floating-point primitive types. /// /// `U` must be the element type of `T`. + #[rustc_nounwind] pub fn simd_reduce_xor(x: T) -> U; /// Truncate an integer vector to a bitmask. @@ -441,6 +488,7 @@ extern "platform-intrinsic" { /// /// # Safety /// `x` must contain only `0` and `!0`. + #[rustc_nounwind] pub fn simd_bitmask(x: T) -> U; /// Select elements from a mask. @@ -455,6 +503,7 @@ extern "platform-intrinsic" { /// /// # Safety /// `mask` must only contain `0` and `!0`. + #[rustc_nounwind] pub fn simd_select(mask: M, if_true: T, if_false: T) -> T; /// Select elements from a bitmask. @@ -471,6 +520,7 @@ extern "platform-intrinsic" { /// /// # Safety /// Padding bits must be all zero. + #[rustc_nounwind] pub fn simd_select_bitmask(m: M, yes: T, no: T) -> T; /// Elementwise calculates the offset from a pointer vector, potentially wrapping. @@ -480,11 +530,13 @@ extern "platform-intrinsic" { /// `U` must be a vector of `isize` or `usize` with the same number of elements as `T`. /// /// Operates as if by `::wrapping_offset`. + #[rustc_nounwind] pub fn simd_arith_offset(ptr: T, offset: U) -> T; /// Cast a vector of pointers. /// /// `T` and `U` must be vectors of pointers with the same number of elements. + #[rustc_nounwind] pub fn simd_cast_ptr(ptr: T) -> U; /// Expose a vector of pointers as a vector of addresses. @@ -492,6 +544,7 @@ extern "platform-intrinsic" { /// `T` must be a vector of pointers. /// /// `U` must be a vector of `usize` with the same length as `T`. + #[rustc_nounwind] pub fn simd_expose_addr(ptr: T) -> U; /// Create a vector of pointers from a vector of addresses. @@ -499,92 +552,117 @@ extern "platform-intrinsic" { /// `T` must be a vector of `usize`. /// /// `U` must be a vector of pointers, with the same length as `T`. + #[rustc_nounwind] pub fn simd_from_exposed_addr(addr: T) -> U; /// Swap bytes of each element. /// /// `T` must be a vector of integers. + #[rustc_nounwind] pub fn simd_bswap(x: T) -> T; /// Reverse bits of each element. /// /// `T` must be a vector of integers. + #[rustc_nounwind] pub fn simd_bitreverse(x: T) -> T; /// Count the leading zeros of each element. /// /// `T` must be a vector of integers. + #[rustc_nounwind] pub fn simd_ctlz(x: T) -> T; /// Count the trailing zeros of each element. /// /// `T` must be a vector of integers. + #[rustc_nounwind] pub fn simd_cttz(x: T) -> T; /// Round up each element to the next highest integer-valued float. /// /// `T` must be a vector of floats. + #[rustc_nounwind] pub fn simd_ceil(x: T) -> T; /// Round down each element to the next lowest integer-valued float. /// /// `T` must be a vector of floats. + #[rustc_nounwind] pub fn simd_floor(x: T) -> T; /// Round each element to the closest integer-valued float. /// Ties are resolved by rounding away from 0. /// /// `T` must be a vector of floats. + #[rustc_nounwind] pub fn simd_round(x: T) -> T; /// Return the integer part of each element as an integer-valued float. /// In other words, non-integer values are truncated towards zero. /// /// `T` must be a vector of floats. + #[rustc_nounwind] pub fn simd_trunc(x: T) -> T; /// Takes the square root of each element. /// /// `T` must be a vector of floats. + #[rustc_nounwind] pub fn simd_fsqrt(x: T) -> T; /// Computes `(x*y) + z` for each element, but without any intermediate rounding. /// /// `T` must be a vector of floats. + #[rustc_nounwind] pub fn simd_fma(x: T, y: T, z: T) -> T; // Computes the sine of each element. /// /// `T` must be a vector of floats. + #[rustc_nounwind] pub fn simd_fsin(a: T) -> T; // Computes the cosine of each element. /// /// `T` must be a vector of floats. + #[rustc_nounwind] pub fn simd_fcos(a: T) -> T; // Computes the exponential function of each element. /// /// `T` must be a vector of floats. + #[rustc_nounwind] pub fn simd_fexp(a: T) -> T; // Computes 2 raised to the power of each element. /// /// `T` must be a vector of floats. + #[rustc_nounwind] pub fn simd_fexp2(a: T) -> T; // Computes the base 10 logarithm of each element. /// /// `T` must be a vector of floats. + #[rustc_nounwind] pub fn simd_flog10(a: T) -> T; // Computes the base 2 logarithm of each element. /// /// `T` must be a vector of floats. + #[rustc_nounwind] pub fn simd_flog2(a: T) -> T; // Computes the natural logarithm of each element. /// /// `T` must be a vector of floats. + #[rustc_nounwind] pub fn simd_flog(a: T) -> T; } +} +} + +#[cfg(bootstrap)] +declare_intrinsics!("platform-intrinsic"); +#[cfg(not(bootstrap))] +declare_intrinsics!("rust-intrinsic"); diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 49cead680e33..7b735d48bdfc 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -202,6 +202,7 @@ // // Language features: // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(platform_intrinsics))] #![feature(abi_unadjusted)] #![feature(adt_const_params)] #![feature(allow_internal_unsafe)] @@ -246,7 +247,6 @@ #![feature(never_type)] #![feature(no_core)] #![feature(no_sanitize)] -#![feature(platform_intrinsics)] #![feature(prelude_import)] #![feature(repr_simd)] #![feature(rustc_allow_const_fn_unstable)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index c6cd2c6786ad..288cce3aa085 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -270,6 +270,7 @@ // // Language features: // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(platform_intrinsics))] #![feature(alloc_error_handler)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] @@ -301,7 +302,6 @@ #![feature(negative_impls)] #![feature(never_type)] #![feature(no_sanitize)] -#![feature(platform_intrinsics)] #![feature(prelude_import)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] From c1d0e489e564049eae866d6beb5b192c36b3b835 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 23 Feb 2024 18:36:24 +0100 Subject: [PATCH 13/39] fix use of platform_intrinsics in tests --- .../example/float-minmax-pass.rs | 7 +- .../tests/fail/intrinsics/simd-div-by-zero.rs | 6 +- .../fail/intrinsics/simd-div-overflow.rs | 6 +- .../intrinsics/simd-reduce-invalid-bool.rs | 6 +- .../tests/fail/intrinsics/simd-rem-by-zero.rs | 6 +- .../intrinsics/simd-select-bitmask-invalid.rs | 6 +- .../intrinsics/simd-select-invalid-bool.rs | 6 +- .../tests/fail/intrinsics/simd-shl-too-far.rs | 6 +- .../tests/fail/intrinsics/simd-shr-too-far.rs | 6 +- src/tools/miri/tests/pass/float_nan.rs | 8 +- .../miri/tests/pass/portable-simd-ptrs.rs | 2 +- src/tools/miri/tests/pass/portable-simd.rs | 10 +- .../pass/simd-intrinsic-generic-elements.rs | 2 +- tests/codegen/issues/issue-84268.rs | 4 +- .../simd-intrinsic-float-abs.rs | 4 +- .../simd-intrinsic-float-ceil.rs | 4 +- .../simd-intrinsic-float-cos.rs | 4 +- .../simd-intrinsic-float-exp.rs | 4 +- .../simd-intrinsic-float-exp2.rs | 4 +- .../simd-intrinsic-float-floor.rs | 4 +- .../simd-intrinsic-float-fma.rs | 4 +- .../simd-intrinsic-float-fsqrt.rs | 4 +- .../simd-intrinsic-float-log.rs | 4 +- .../simd-intrinsic-float-log10.rs | 4 +- .../simd-intrinsic-float-log2.rs | 4 +- .../simd-intrinsic-float-minmax.rs | 4 +- .../simd-intrinsic-float-pow.rs | 4 +- .../simd-intrinsic-float-powi.rs | 4 +- .../simd-intrinsic-float-sin.rs | 4 +- ...intrinsic-generic-arithmetic-saturating.rs | 4 +- .../simd-intrinsic-generic-bitmask.rs | 4 +- .../simd-intrinsic-generic-gather.rs | 4 +- .../simd-intrinsic-generic-masked-load.rs | 4 +- .../simd-intrinsic-generic-masked-store.rs | 4 +- .../simd-intrinsic-generic-scatter.rs | 4 +- .../simd-intrinsic-generic-select.rs | 4 +- .../simd-intrinsic-transmute-array.rs | 2 +- tests/codegen/simd/simd_arith_offset.rs | 4 +- tests/incremental/issue-61530.rs | 4 +- .../consts/const-eval/simd/insert_extract.rs | 4 +- tests/ui/error-codes/E0511.rs | 4 +- tests/ui/feature-gates/feature-gate-abi.rs | 13 +- .../ui/feature-gates/feature-gate-abi.stderr | 138 +++++++++--------- .../instance-doesnt-depend-on-type.rs | 2 +- .../bad-intrinsic-monomorphization.rs | 4 +- tests/ui/simd/array-trait.rs | 4 +- tests/ui/simd/array-type.rs | 4 +- tests/ui/simd/generics.rs | 4 +- tests/ui/simd/intrinsic/float-math-pass.rs | 4 +- tests/ui/simd/intrinsic/float-minmax-pass.rs | 7 +- .../ui/simd/intrinsic/generic-arithmetic-2.rs | 4 +- .../simd/intrinsic/generic-arithmetic-pass.rs | 4 +- .../generic-arithmetic-saturating-2.rs | 4 +- .../generic-arithmetic-saturating-pass.rs | 4 +- tests/ui/simd/intrinsic/generic-as.rs | 4 +- .../ui/simd/intrinsic/generic-bitmask-pass.rs | 4 +- tests/ui/simd/intrinsic/generic-bitmask.rs | 4 +- tests/ui/simd/intrinsic/generic-bswap-byte.rs | 4 +- tests/ui/simd/intrinsic/generic-cast-pass.rs | 4 +- .../intrinsic/generic-cast-pointer-width.rs | 4 +- tests/ui/simd/intrinsic/generic-cast.rs | 4 +- .../simd/intrinsic/generic-comparison-pass.rs | 4 +- tests/ui/simd/intrinsic/generic-comparison.rs | 4 +- .../simd/intrinsic/generic-elements-pass.rs | 4 +- tests/ui/simd/intrinsic/generic-elements.rs | 4 +- .../ui/simd/intrinsic/generic-gather-pass.rs | 4 +- .../simd/intrinsic/generic-reduction-pass.rs | 4 +- tests/ui/simd/intrinsic/generic-reduction.rs | 4 +- .../ui/simd/intrinsic/generic-select-pass.rs | 4 +- tests/ui/simd/intrinsic/generic-select.rs | 4 +- tests/ui/simd/intrinsic/generic-shuffle.rs | 4 +- .../simd/intrinsic/inlining-issue67557-ice.rs | 4 +- .../ui/simd/intrinsic/inlining-issue67557.rs | 4 +- tests/ui/simd/intrinsic/issue-85855.rs | 4 +- tests/ui/simd/intrinsic/ptr-cast.rs | 4 +- tests/ui/simd/issue-105439.rs | 4 +- tests/ui/simd/issue-39720.rs | 4 +- tests/ui/simd/issue-85915-simd-ptrs.rs | 4 +- tests/ui/simd/issue-89193.rs | 4 +- tests/ui/simd/masked-load-store-build-fail.rs | 4 +- tests/ui/simd/masked-load-store-check-fail.rs | 4 +- tests/ui/simd/masked-load-store.rs | 4 +- tests/ui/simd/monomorphize-shuffle-index.rs | 4 +- tests/ui/simd/repr_packed.rs | 4 +- tests/ui/simd/shuffle.rs | 4 +- tests/ui/simd/simd-bitmask.rs | 4 +- .../type-generic-monomorphisation-empty.rs | 2 +- ...type-generic-monomorphisation-oversized.rs | 2 +- ...e-generic-monomorphisation-power-of-two.rs | 2 +- .../ui/simd/type-generic-monomorphisation.rs | 2 +- 90 files changed, 239 insertions(+), 280 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs b/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs index eebd77083ec6..a71217a554b5 100644 --- a/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs +++ b/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs @@ -4,17 +4,14 @@ // Test that the simd_f{min,max} intrinsics produce the correct results. -#![feature(repr_simd, intrinsics)] +#![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] struct f32x4(pub f32, pub f32, pub f32, pub f32); -extern "intrinsic" { - fn simd_fmin(x: T, y: T) -> T; - fn simd_fmax(x: T, y: T) -> T; -} +use std::intrinsics::simd::*; fn main() { let x = f32x4(1.0, 2.0, 3.0, 4.0); diff --git a/src/tools/miri/tests/fail/intrinsics/simd-div-by-zero.rs b/src/tools/miri/tests/fail/intrinsics/simd-div-by-zero.rs index 5fa6f69d0059..ba474332b811 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-div-by-zero.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-div-by-zero.rs @@ -1,8 +1,6 @@ -#![feature(platform_intrinsics, repr_simd)] +#![feature(core_intrinsics, repr_simd)] -extern "platform-intrinsic" { - pub(crate) fn simd_div(x: T, y: T) -> T; -} +use std::intrinsics::simd::simd_div; #[repr(simd)] #[allow(non_camel_case_types)] diff --git a/src/tools/miri/tests/fail/intrinsics/simd-div-overflow.rs b/src/tools/miri/tests/fail/intrinsics/simd-div-overflow.rs index 57712b1b836b..d01e41de0e4b 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-div-overflow.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-div-overflow.rs @@ -1,8 +1,6 @@ -#![feature(platform_intrinsics, repr_simd)] +#![feature(core_intrinsics, repr_simd)] -extern "platform-intrinsic" { - pub(crate) fn simd_div(x: T, y: T) -> T; -} +use std::intrinsics::simd::simd_div; #[repr(simd)] #[allow(non_camel_case_types)] diff --git a/src/tools/miri/tests/fail/intrinsics/simd-reduce-invalid-bool.rs b/src/tools/miri/tests/fail/intrinsics/simd-reduce-invalid-bool.rs index 354f8213120a..a194f0dd18aa 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-reduce-invalid-bool.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-reduce-invalid-bool.rs @@ -1,8 +1,6 @@ -#![feature(platform_intrinsics, repr_simd)] +#![feature(core_intrinsics, repr_simd)] -extern "platform-intrinsic" { - pub(crate) fn simd_reduce_any(x: T) -> bool; -} +use std::intrinsics::simd::simd_reduce_any; #[repr(simd)] #[allow(non_camel_case_types)] diff --git a/src/tools/miri/tests/fail/intrinsics/simd-rem-by-zero.rs b/src/tools/miri/tests/fail/intrinsics/simd-rem-by-zero.rs index 625889bb67b5..cd1e4b8162b3 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-rem-by-zero.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-rem-by-zero.rs @@ -1,8 +1,6 @@ -#![feature(platform_intrinsics, repr_simd)] +#![feature(core_intrinsics, repr_simd)] -extern "platform-intrinsic" { - pub(crate) fn simd_rem(x: T, y: T) -> T; -} +use std::intrinsics::simd::simd_rem; #[repr(simd)] #[allow(non_camel_case_types)] diff --git a/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.rs b/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.rs index 8a3895ac14cf..96802fae49c2 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.rs @@ -1,8 +1,6 @@ -#![feature(platform_intrinsics, repr_simd)] +#![feature(core_intrinsics, repr_simd)] -extern "platform-intrinsic" { - fn simd_select_bitmask(m: M, yes: T, no: T) -> T; -} +use std::intrinsics::simd::simd_select_bitmask; #[repr(simd)] #[allow(non_camel_case_types)] diff --git a/src/tools/miri/tests/fail/intrinsics/simd-select-invalid-bool.rs b/src/tools/miri/tests/fail/intrinsics/simd-select-invalid-bool.rs index 7f7ee3af4951..388fb2e2a84a 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-select-invalid-bool.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-select-invalid-bool.rs @@ -1,8 +1,6 @@ -#![feature(platform_intrinsics, repr_simd)] +#![feature(core_intrinsics, repr_simd)] -extern "platform-intrinsic" { - fn simd_select(m: M, yes: T, no: T) -> T; -} +use std::intrinsics::simd::simd_select; #[repr(simd)] #[allow(non_camel_case_types)] diff --git a/src/tools/miri/tests/fail/intrinsics/simd-shl-too-far.rs b/src/tools/miri/tests/fail/intrinsics/simd-shl-too-far.rs index 5c517c17b3a4..8a49c8403ae3 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-shl-too-far.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-shl-too-far.rs @@ -1,8 +1,6 @@ -#![feature(platform_intrinsics, repr_simd)] +#![feature(core_intrinsics, repr_simd)] -extern "platform-intrinsic" { - pub(crate) fn simd_shl(x: T, y: T) -> T; -} +use std::intrinsics::simd::simd_shl; #[repr(simd)] #[allow(non_camel_case_types)] diff --git a/src/tools/miri/tests/fail/intrinsics/simd-shr-too-far.rs b/src/tools/miri/tests/fail/intrinsics/simd-shr-too-far.rs index 5f1475a67781..433998cbde66 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-shr-too-far.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-shr-too-far.rs @@ -1,8 +1,6 @@ -#![feature(platform_intrinsics, repr_simd)] +#![feature(core_intrinsics, repr_simd)] -extern "platform-intrinsic" { - pub(crate) fn simd_shr(x: T, y: T) -> T; -} +use std::intrinsics::simd::simd_shr; #[repr(simd)] #[allow(non_camel_case_types)] diff --git a/src/tools/miri/tests/pass/float_nan.rs b/src/tools/miri/tests/pass/float_nan.rs index 4bfd12245ef1..cadbbd58af59 100644 --- a/src/tools/miri/tests/pass/float_nan.rs +++ b/src/tools/miri/tests/pass/float_nan.rs @@ -1,4 +1,4 @@ -#![feature(float_gamma, portable_simd, core_intrinsics, platform_intrinsics)] +#![feature(float_gamma, portable_simd, core_intrinsics)] use std::collections::HashSet; use std::fmt; use std::hash::Hash; @@ -525,12 +525,6 @@ fn test_simd() { use std::intrinsics::simd::*; use std::simd::*; - extern "platform-intrinsic" { - fn simd_fsqrt(x: T) -> T; - fn simd_ceil(x: T) -> T; - fn simd_fma(x: T, y: T, z: T) -> T; - } - let nan = F32::nan(Neg, Quiet, 0).as_f32(); check_all_outcomes( HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), diff --git a/src/tools/miri/tests/pass/portable-simd-ptrs.rs b/src/tools/miri/tests/pass/portable-simd-ptrs.rs index a73b1d03cfa5..70ba5636c600 100644 --- a/src/tools/miri/tests/pass/portable-simd-ptrs.rs +++ b/src/tools/miri/tests/pass/portable-simd-ptrs.rs @@ -1,6 +1,6 @@ // Separate test without strict provenance //@compile-flags: -Zmiri-permissive-provenance -#![feature(portable_simd, platform_intrinsics)] +#![feature(portable_simd)] use std::ptr; use std::simd::prelude::*; diff --git a/src/tools/miri/tests/pass/portable-simd.rs b/src/tools/miri/tests/pass/portable-simd.rs index 57d0b6a87b22..193b77800837 100644 --- a/src/tools/miri/tests/pass/portable-simd.rs +++ b/src/tools/miri/tests/pass/portable-simd.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-strict-provenance -#![feature(portable_simd, platform_intrinsics, adt_const_params, inline_const, core_intrinsics)] +#![feature(portable_simd, adt_const_params, inline_const, core_intrinsics)] #![allow(incomplete_features, internal_features)] use std::intrinsics::simd as intrinsics; use std::ptr; @@ -216,10 +216,7 @@ fn simd_ops_i32() { } fn simd_mask() { - extern "platform-intrinsic" { - pub(crate) fn simd_bitmask(x: T) -> U; - pub(crate) fn simd_select_bitmask(m: M, yes: T, no: T) -> T; - } + use std::intrinsics::simd::*; let intmask = Mask::from_int(i32x4::from_array([0, -1, 0, 0])); assert_eq!(intmask, Mask::from_array([false, true, false, false])); @@ -497,9 +494,6 @@ fn simd_round() { fn simd_intrinsics() { use intrinsics::*; - extern "platform-intrinsic" { - fn simd_shuffle_generic(x: T, y: T) -> U; - } unsafe { // Make sure simd_eq returns all-1 for `true` diff --git a/src/tools/miri/tests/pass/simd-intrinsic-generic-elements.rs b/src/tools/miri/tests/pass/simd-intrinsic-generic-elements.rs index 5958357c8b7b..4a87f8c3ca72 100644 --- a/src/tools/miri/tests/pass/simd-intrinsic-generic-elements.rs +++ b/src/tools/miri/tests/pass/simd-intrinsic-generic-elements.rs @@ -1,4 +1,4 @@ -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd)] #[repr(simd)] #[derive(Copy, Clone, Debug, PartialEq)] diff --git a/tests/codegen/issues/issue-84268.rs b/tests/codegen/issues/issue-84268.rs index 379ee4f13f64..1e3950609b33 100644 --- a/tests/codegen/issues/issue-84268.rs +++ b/tests/codegen/issues/issue-84268.rs @@ -1,7 +1,7 @@ //@ compile-flags: -O --crate-type=rlib -#![feature(platform_intrinsics, repr_simd)] +#![feature(intrinsics, repr_simd)] -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_fabs(x: T) -> T; fn simd_eq(x: T, y: T) -> U; } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs index 3eb1c9d40515..f8efb678f76e 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs @@ -2,7 +2,7 @@ #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -25,7 +25,7 @@ pub struct f32x16(pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_fabs(x: T) -> T; } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs index 05c2c0f6d044..a3ebec174b67 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs @@ -2,7 +2,7 @@ #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -25,7 +25,7 @@ pub struct f32x16(pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_ceil(x: T) -> T; } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs index 8b51e76a515c..00f97eef6f0c 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs @@ -2,7 +2,7 @@ #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -25,7 +25,7 @@ pub struct f32x16(pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_fcos(x: T) -> T; } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs index 370bacdaee98..48c1a8ec489d 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs @@ -2,7 +2,7 @@ #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -25,7 +25,7 @@ pub struct f32x16(pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_fexp(x: T) -> T; } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs index 888ec6ec42cf..23c38d816215 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs @@ -2,7 +2,7 @@ #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -25,7 +25,7 @@ pub struct f32x16(pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_fexp2(x: T) -> T; } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs index b15d89a15b27..978f263031ac 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs @@ -2,7 +2,7 @@ #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -25,7 +25,7 @@ pub struct f32x16(pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_floor(x: T) -> T; } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs index 16017526c34a..200d67180265 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs @@ -2,7 +2,7 @@ #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -25,7 +25,7 @@ pub struct f32x16(pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_fma(x: T, b: T, c: T) -> T; } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs index 9e0f7edd62b7..f70de3e27536 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs @@ -2,7 +2,7 @@ #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -25,7 +25,7 @@ pub struct f32x16(pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_fsqrt(x: T) -> T; } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log.rs index 0324411c91bd..c0edd3ea48fc 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log.rs @@ -2,7 +2,7 @@ #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -25,7 +25,7 @@ pub struct f32x16(pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_flog(x: T) -> T; } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs index e7e2b0838cc2..766307f47ed3 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs @@ -2,7 +2,7 @@ #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -25,7 +25,7 @@ pub struct f32x16(pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_flog10(x: T) -> T; } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs index 912e15c6a1d8..90c5918c33ea 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs @@ -2,7 +2,7 @@ #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -25,7 +25,7 @@ pub struct f32x16(pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_flog2(x: T) -> T; } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs index ad297952916c..d949112bae76 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs @@ -2,14 +2,14 @@ #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] pub struct f32x4(pub f32, pub f32, pub f32, pub f32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_fmin(x: T, y: T) -> T; fn simd_fmax(x: T, y: T) -> T; } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-pow.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-pow.rs index 1ae983ca20b8..21641c80d313 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-pow.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-pow.rs @@ -2,7 +2,7 @@ #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -25,7 +25,7 @@ pub struct f32x16(pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_fpow(x: T, b: T) -> T; } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-powi.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-powi.rs index 638b78b2d72a..3985bdd50df7 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-powi.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-powi.rs @@ -2,7 +2,7 @@ #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -25,7 +25,7 @@ pub struct f32x16(pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_fpowi(x: T, b: i32) -> T; } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs index c0caedb74987..f6978e32df72 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs @@ -2,7 +2,7 @@ #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -25,7 +25,7 @@ pub struct f32x16(pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32, pub f32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_fsin(x: T) -> T; } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs index 1426b439c443..809f9a32226f 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs @@ -3,7 +3,7 @@ #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #![deny(unused)] @@ -111,7 +111,7 @@ #[repr(simd)] #[derive(Copy, Clone)] pub struct u128x2(u128, u128); #[repr(simd)] #[derive(Copy, Clone)] pub struct u128x4(u128, u128, u128, u128); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_saturating_add(x: T, y: T) -> T; fn simd_saturating_sub(x: T, y: T) -> T; } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs index 43012dece622..44a4c52d64a8 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs @@ -3,7 +3,7 @@ #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -22,7 +22,7 @@ pub struct i8x16( ); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_bitmask(x: T) -> U; } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs index 29d9e4018e0d..863a9606c7e9 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs @@ -4,7 +4,7 @@ #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -15,7 +15,7 @@ pub struct Vec2(pub T, pub T); #[derive(Copy, Clone, PartialEq, Debug)] pub struct Vec4(pub T, pub T, pub T, pub T); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_gather(value: T, pointers: P, mask: M) -> T; } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs index 7c48f7d5120e..b41c42810aaf 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs @@ -2,7 +2,7 @@ #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -13,7 +13,7 @@ pub struct Vec2(pub T, pub T); #[derive(Copy, Clone, PartialEq, Debug)] pub struct Vec4(pub T, pub T, pub T, pub T); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_masked_load(mask: M, pointer: P, values: T) -> T; } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs index 366592ba3f1e..066392bcde68 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs @@ -2,7 +2,7 @@ #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -13,7 +13,7 @@ pub struct Vec2(pub T, pub T); #[derive(Copy, Clone, PartialEq, Debug)] pub struct Vec4(pub T, pub T, pub T, pub T); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_masked_store(mask: M, pointer: P, values: T) -> (); } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs index ccfedb31dc57..e85bd61c7f83 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs @@ -4,7 +4,7 @@ #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -15,7 +15,7 @@ pub struct Vec2(pub T, pub T); #[derive(Copy, Clone, PartialEq, Debug)] pub struct Vec4(pub T, pub T, pub T, pub T); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_scatter(value: T, pointers: P, mask: M); } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs index 903bd3f4dc60..05d2bf627ef1 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs @@ -2,7 +2,7 @@ #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #[allow(non_camel_case_types)] #[repr(simd)] @@ -17,7 +17,7 @@ pub struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32); #[derive(Copy, Clone, PartialEq, Debug)] pub struct b8x4(pub i8, pub i8, pub i8, pub i8); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_select(x: T, a: U, b: U) -> U; fn simd_select_bitmask(x: T, a: U, b: U) -> U; } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs index c92ae4163ae5..488be2a8629d 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs @@ -3,7 +3,7 @@ #![crate_type = "lib"] #![allow(non_camel_case_types)] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![feature(inline_const)] #[repr(simd)] diff --git a/tests/codegen/simd/simd_arith_offset.rs b/tests/codegen/simd/simd_arith_offset.rs index 9f1ef27053e6..e14fce1d4187 100644 --- a/tests/codegen/simd/simd_arith_offset.rs +++ b/tests/codegen/simd/simd_arith_offset.rs @@ -3,9 +3,9 @@ // #![crate_type = "lib"] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] -extern "platform-intrinsic" { +extern "rust-intrinsic" { pub(crate) fn simd_arith_offset(ptrs: T, offsets: U) -> T; } diff --git a/tests/incremental/issue-61530.rs b/tests/incremental/issue-61530.rs index 0197beb48d8c..e4ee8ccbc4bd 100644 --- a/tests/incremental/issue-61530.rs +++ b/tests/incremental/issue-61530.rs @@ -1,11 +1,11 @@ -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] //@ revisions:rpass1 rpass2 #[repr(simd)] struct I32x2(i32, i32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_shuffle(x: T, y: T, idx: I) -> U; } diff --git a/tests/ui/consts/const-eval/simd/insert_extract.rs b/tests/ui/consts/const-eval/simd/insert_extract.rs index c0113904edf0..fc7dbd5a41c3 100644 --- a/tests/ui/consts/const-eval/simd/insert_extract.rs +++ b/tests/ui/consts/const-eval/simd/insert_extract.rs @@ -1,6 +1,6 @@ //@ run-pass #![feature(repr_simd)] -#![feature(platform_intrinsics)] +#![feature(intrinsics)] #![feature(staged_api)] #![stable(feature = "foo", since = "1.3.37")] #![allow(non_camel_case_types)] @@ -11,7 +11,7 @@ #[repr(simd)] struct i8x1_arr([i8; 1]); #[repr(simd)] struct f32x4([f32; 4]); -extern "platform-intrinsic" { +extern "rust-intrinsic" { #[rustc_const_stable(feature = "foo", since = "1.3.37")] fn simd_insert(x: T, idx: u32, val: U) -> T; #[rustc_const_stable(feature = "foo", since = "1.3.37")] diff --git a/tests/ui/error-codes/E0511.rs b/tests/ui/error-codes/E0511.rs index 8c79bcf5a672..81656c710882 100644 --- a/tests/ui/error-codes/E0511.rs +++ b/tests/ui/error-codes/E0511.rs @@ -1,8 +1,8 @@ //@ build-fail -#![feature(platform_intrinsics)] +#![feature(intrinsics)] -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_add(a: T, b: T) -> T; } diff --git a/tests/ui/feature-gates/feature-gate-abi.rs b/tests/ui/feature-gates/feature-gate-abi.rs index 02568b4778b9..1c3a732a497f 100644 --- a/tests/ui/feature-gates/feature-gate-abi.rs +++ b/tests/ui/feature-gates/feature-gate-abi.rs @@ -1,5 +1,4 @@ // gate-test-intrinsics -// gate-test-platform_intrinsics //@ compile-flags: --crate-type=rlib #![feature(no_core, lang_items)] @@ -15,7 +14,7 @@ trait Tuple { } extern "rust-intrinsic" fn f1() {} //~ ERROR intrinsics are subject to change //~^ ERROR intrinsic must be in //~| ERROR unrecognized intrinsic function: `f1` -extern "platform-intrinsic" fn f2() {} //~ ERROR platform intrinsics are experimental +extern "rust-intrinsic" fn f2() {} //~ ERROR intrinsics are subject to change //~^ ERROR intrinsic must be in //~| ERROR unrecognized intrinsic function: `f2` extern "rust-call" fn f4(_: ()) {} //~ ERROR rust-call ABI is subject to change @@ -24,7 +23,7 @@ extern "rust-call" fn f4(_: ()) {} //~ ERROR rust-call ABI is subject to change trait Tr { extern "rust-intrinsic" fn m1(); //~ ERROR intrinsics are subject to change //~^ ERROR intrinsic must be in - extern "platform-intrinsic" fn m2(); //~ ERROR platform intrinsics are experimental + extern "rust-intrinsic" fn m2(); //~ ERROR intrinsics are subject to change //~^ ERROR intrinsic must be in extern "rust-call" fn m4(_: ()); //~ ERROR rust-call ABI is subject to change @@ -37,7 +36,7 @@ struct S; impl Tr for S { extern "rust-intrinsic" fn m1() {} //~ ERROR intrinsics are subject to change //~^ ERROR intrinsic must be in - extern "platform-intrinsic" fn m2() {} //~ ERROR platform intrinsics are experimental + extern "rust-intrinsic" fn m2() {} //~ ERROR intrinsics are subject to change //~^ ERROR intrinsic must be in extern "rust-call" fn m4(_: ()) {} //~ ERROR rust-call ABI is subject to change } @@ -46,17 +45,17 @@ impl Tr for S { impl S { extern "rust-intrinsic" fn im1() {} //~ ERROR intrinsics are subject to change //~^ ERROR intrinsic must be in - extern "platform-intrinsic" fn im2() {} //~ ERROR platform intrinsics are experimental + extern "rust-intrinsic" fn im2() {} //~ ERROR intrinsics are subject to change //~^ ERROR intrinsic must be in extern "rust-call" fn im4(_: ()) {} //~ ERROR rust-call ABI is subject to change } // Function pointer types type A1 = extern "rust-intrinsic" fn(); //~ ERROR intrinsics are subject to change -type A2 = extern "platform-intrinsic" fn(); //~ ERROR platform intrinsics are experimental +type A2 = extern "rust-intrinsic" fn(); //~ ERROR intrinsics are subject to change type A4 = extern "rust-call" fn(_: ()); //~ ERROR rust-call ABI is subject to change // Foreign modules extern "rust-intrinsic" {} //~ ERROR intrinsics are subject to change -extern "platform-intrinsic" {} //~ ERROR platform intrinsics are experimental +extern "rust-intrinsic" {} //~ ERROR intrinsics are subject to change extern "rust-call" {} //~ ERROR rust-call ABI is subject to change diff --git a/tests/ui/feature-gates/feature-gate-abi.stderr b/tests/ui/feature-gates/feature-gate-abi.stderr index 3fd1e1189abc..c28cd05a96ad 100644 --- a/tests/ui/feature-gates/feature-gate-abi.stderr +++ b/tests/ui/feature-gates/feature-gate-abi.stderr @@ -1,5 +1,5 @@ error[E0658]: intrinsics are subject to change - --> $DIR/feature-gate-abi.rs:15:8 + --> $DIR/feature-gate-abi.rs:14:8 | LL | extern "rust-intrinsic" fn f1() {} | ^^^^^^^^^^^^^^^^ @@ -7,18 +7,17 @@ LL | extern "rust-intrinsic" fn f1() {} = help: add `#![feature(intrinsics)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: platform intrinsics are experimental and possibly buggy - --> $DIR/feature-gate-abi.rs:18:8 +error[E0658]: intrinsics are subject to change + --> $DIR/feature-gate-abi.rs:17:8 | -LL | extern "platform-intrinsic" fn f2() {} - | ^^^^^^^^^^^^^^^^^^^^ +LL | extern "rust-intrinsic" fn f2() {} + | ^^^^^^^^^^^^^^^^ | - = note: see issue #27731 for more information - = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable + = help: add `#![feature(intrinsics)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-abi.rs:21:8 + --> $DIR/feature-gate-abi.rs:20:8 | LL | extern "rust-call" fn f4(_: ()) {} | ^^^^^^^^^^^ @@ -28,7 +27,7 @@ LL | extern "rust-call" fn f4(_: ()) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: intrinsics are subject to change - --> $DIR/feature-gate-abi.rs:25:12 + --> $DIR/feature-gate-abi.rs:24:12 | LL | extern "rust-intrinsic" fn m1(); | ^^^^^^^^^^^^^^^^ @@ -36,18 +35,17 @@ LL | extern "rust-intrinsic" fn m1(); = help: add `#![feature(intrinsics)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: platform intrinsics are experimental and possibly buggy - --> $DIR/feature-gate-abi.rs:27:12 +error[E0658]: intrinsics are subject to change + --> $DIR/feature-gate-abi.rs:26:12 | -LL | extern "platform-intrinsic" fn m2(); - | ^^^^^^^^^^^^^^^^^^^^ +LL | extern "rust-intrinsic" fn m2(); + | ^^^^^^^^^^^^^^^^ | - = note: see issue #27731 for more information - = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable + = help: add `#![feature(intrinsics)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-abi.rs:29:12 + --> $DIR/feature-gate-abi.rs:28:12 | LL | extern "rust-call" fn m4(_: ()); | ^^^^^^^^^^^ @@ -57,7 +55,7 @@ LL | extern "rust-call" fn m4(_: ()); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-abi.rs:31:12 + --> $DIR/feature-gate-abi.rs:30:12 | LL | extern "rust-call" fn dm4(_: ()) {} | ^^^^^^^^^^^ @@ -67,7 +65,7 @@ LL | extern "rust-call" fn dm4(_: ()) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: intrinsics are subject to change - --> $DIR/feature-gate-abi.rs:38:12 + --> $DIR/feature-gate-abi.rs:37:12 | LL | extern "rust-intrinsic" fn m1() {} | ^^^^^^^^^^^^^^^^ @@ -75,18 +73,17 @@ LL | extern "rust-intrinsic" fn m1() {} = help: add `#![feature(intrinsics)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: platform intrinsics are experimental and possibly buggy - --> $DIR/feature-gate-abi.rs:40:12 +error[E0658]: intrinsics are subject to change + --> $DIR/feature-gate-abi.rs:39:12 | -LL | extern "platform-intrinsic" fn m2() {} - | ^^^^^^^^^^^^^^^^^^^^ +LL | extern "rust-intrinsic" fn m2() {} + | ^^^^^^^^^^^^^^^^ | - = note: see issue #27731 for more information - = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable + = help: add `#![feature(intrinsics)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-abi.rs:42:12 + --> $DIR/feature-gate-abi.rs:41:12 | LL | extern "rust-call" fn m4(_: ()) {} | ^^^^^^^^^^^ @@ -96,7 +93,7 @@ LL | extern "rust-call" fn m4(_: ()) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: intrinsics are subject to change - --> $DIR/feature-gate-abi.rs:47:12 + --> $DIR/feature-gate-abi.rs:46:12 | LL | extern "rust-intrinsic" fn im1() {} | ^^^^^^^^^^^^^^^^ @@ -104,18 +101,17 @@ LL | extern "rust-intrinsic" fn im1() {} = help: add `#![feature(intrinsics)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: platform intrinsics are experimental and possibly buggy - --> $DIR/feature-gate-abi.rs:49:12 +error[E0658]: intrinsics are subject to change + --> $DIR/feature-gate-abi.rs:48:12 | -LL | extern "platform-intrinsic" fn im2() {} - | ^^^^^^^^^^^^^^^^^^^^ +LL | extern "rust-intrinsic" fn im2() {} + | ^^^^^^^^^^^^^^^^ | - = note: see issue #27731 for more information - = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable + = help: add `#![feature(intrinsics)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-abi.rs:51:12 + --> $DIR/feature-gate-abi.rs:50:12 | LL | extern "rust-call" fn im4(_: ()) {} | ^^^^^^^^^^^ @@ -125,7 +121,7 @@ LL | extern "rust-call" fn im4(_: ()) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: intrinsics are subject to change - --> $DIR/feature-gate-abi.rs:55:18 + --> $DIR/feature-gate-abi.rs:54:18 | LL | type A1 = extern "rust-intrinsic" fn(); | ^^^^^^^^^^^^^^^^ @@ -133,18 +129,17 @@ LL | type A1 = extern "rust-intrinsic" fn(); = help: add `#![feature(intrinsics)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: platform intrinsics are experimental and possibly buggy - --> $DIR/feature-gate-abi.rs:56:18 +error[E0658]: intrinsics are subject to change + --> $DIR/feature-gate-abi.rs:55:18 | -LL | type A2 = extern "platform-intrinsic" fn(); - | ^^^^^^^^^^^^^^^^^^^^ +LL | type A2 = extern "rust-intrinsic" fn(); + | ^^^^^^^^^^^^^^^^ | - = note: see issue #27731 for more information - = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable + = help: add `#![feature(intrinsics)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-abi.rs:57:18 + --> $DIR/feature-gate-abi.rs:56:18 | LL | type A4 = extern "rust-call" fn(_: ()); | ^^^^^^^^^^^ @@ -153,6 +148,15 @@ LL | type A4 = extern "rust-call" fn(_: ()); = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: intrinsics are subject to change + --> $DIR/feature-gate-abi.rs:59:8 + | +LL | extern "rust-intrinsic" {} + | ^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(intrinsics)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: intrinsics are subject to change --> $DIR/feature-gate-abi.rs:60:8 | @@ -162,18 +166,8 @@ LL | extern "rust-intrinsic" {} = help: add `#![feature(intrinsics)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: platform intrinsics are experimental and possibly buggy - --> $DIR/feature-gate-abi.rs:61:8 - | -LL | extern "platform-intrinsic" {} - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #27731 for more information - = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-abi.rs:62:8 + --> $DIR/feature-gate-abi.rs:61:8 | LL | extern "rust-call" {} | ^^^^^^^^^^^ @@ -183,7 +177,7 @@ LL | extern "rust-call" {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0093]: unrecognized intrinsic function: `f1` - --> $DIR/feature-gate-abi.rs:15:28 + --> $DIR/feature-gate-abi.rs:14:28 | LL | extern "rust-intrinsic" fn f1() {} | ^^ unrecognized intrinsic @@ -191,60 +185,60 @@ LL | extern "rust-intrinsic" fn f1() {} = help: if you're adding an intrinsic, be sure to update `check_intrinsic_type` error[E0093]: unrecognized intrinsic function: `f2` - --> $DIR/feature-gate-abi.rs:18:32 + --> $DIR/feature-gate-abi.rs:17:28 | -LL | extern "platform-intrinsic" fn f2() {} - | ^^ unrecognized intrinsic +LL | extern "rust-intrinsic" fn f2() {} + | ^^ unrecognized intrinsic | = help: if you're adding an intrinsic, be sure to update `check_intrinsic_type` error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/feature-gate-abi.rs:25:32 + --> $DIR/feature-gate-abi.rs:24:32 | LL | extern "rust-intrinsic" fn m1(); | ^^ error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/feature-gate-abi.rs:27:36 + --> $DIR/feature-gate-abi.rs:26:32 | -LL | extern "platform-intrinsic" fn m2(); - | ^^ +LL | extern "rust-intrinsic" fn m2(); + | ^^ error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/feature-gate-abi.rs:15:33 + --> $DIR/feature-gate-abi.rs:14:33 | LL | extern "rust-intrinsic" fn f1() {} | ^^ error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/feature-gate-abi.rs:18:37 + --> $DIR/feature-gate-abi.rs:17:33 | -LL | extern "platform-intrinsic" fn f2() {} - | ^^ +LL | extern "rust-intrinsic" fn f2() {} + | ^^ error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/feature-gate-abi.rs:38:37 + --> $DIR/feature-gate-abi.rs:37:37 | LL | extern "rust-intrinsic" fn m1() {} | ^^ error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/feature-gate-abi.rs:40:41 + --> $DIR/feature-gate-abi.rs:39:37 | -LL | extern "platform-intrinsic" fn m2() {} - | ^^ +LL | extern "rust-intrinsic" fn m2() {} + | ^^ error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/feature-gate-abi.rs:47:38 + --> $DIR/feature-gate-abi.rs:46:38 | LL | extern "rust-intrinsic" fn im1() {} | ^^ error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/feature-gate-abi.rs:49:42 + --> $DIR/feature-gate-abi.rs:48:38 | -LL | extern "platform-intrinsic" fn im2() {} - | ^^ +LL | extern "rust-intrinsic" fn im2() {} + | ^^ error: aborting due to 29 previous errors diff --git a/tests/ui/inline-const/instance-doesnt-depend-on-type.rs b/tests/ui/inline-const/instance-doesnt-depend-on-type.rs index 17208a230883..e69106a43af4 100644 --- a/tests/ui/inline-const/instance-doesnt-depend-on-type.rs +++ b/tests/ui/inline-const/instance-doesnt-depend-on-type.rs @@ -6,5 +6,5 @@ fn main() { const { core::mem::transmute:: }; // Don't resolve the instance of this inline constant to be an intrinsic, - // even if the type of the constant is `extern "intrinsic" fn(u8) -> u8`. + // even if the type of the constant is `extern "rust-intrinsic" fn(u8) -> u8`. } diff --git a/tests/ui/intrinsics/bad-intrinsic-monomorphization.rs b/tests/ui/intrinsics/bad-intrinsic-monomorphization.rs index a9c92f23cdd0..fa9cbe4400ce 100644 --- a/tests/ui/intrinsics/bad-intrinsic-monomorphization.rs +++ b/tests/ui/intrinsics/bad-intrinsic-monomorphization.rs @@ -1,13 +1,13 @@ //@ build-fail -#![feature(repr_simd, platform_intrinsics, core_intrinsics)] +#![feature(repr_simd, intrinsics, core_intrinsics)] #![allow(warnings)] #![crate_type = "rlib"] // Bad monomorphizations could previously cause LLVM asserts even though the // error was caught in the compiler. -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_add(x: T, y: T) -> T; } diff --git a/tests/ui/simd/array-trait.rs b/tests/ui/simd/array-trait.rs index 55fec7a3948b..d2f246a2146c 100644 --- a/tests/ui/simd/array-trait.rs +++ b/tests/ui/simd/array-trait.rs @@ -4,7 +4,7 @@ //@ pretty-expanded FIXME #23616 -#![feature(repr_simd, platform_intrinsics, generic_const_exprs)] +#![feature(repr_simd, intrinsics, generic_const_exprs)] #![allow(non_camel_case_types, incomplete_features)] pub trait Simd { @@ -25,7 +25,7 @@ pub struct T([S::Lane; S::SIZE]); //~| ERROR SIMD vector element type should be a primitive scalar //~| ERROR unconstrained generic constant -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_insert(x: T, idx: u32, y: E) -> T; fn simd_extract(x: T, idx: u32) -> E; } diff --git a/tests/ui/simd/array-type.rs b/tests/ui/simd/array-type.rs index 0864c3e7418d..4063dcd703cd 100644 --- a/tests/ui/simd/array-type.rs +++ b/tests/ui/simd/array-type.rs @@ -3,7 +3,7 @@ //@ pretty-expanded FIXME #23616 -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #[repr(simd)] #[derive(Copy, Clone)] @@ -13,7 +13,7 @@ struct S([i32; 4]); #[derive(Copy, Clone)] struct T([i32; N]); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_insert(x: T, idx: u32, y: E) -> T; fn simd_extract(x: T, idx: u32) -> E; } diff --git a/tests/ui/simd/generics.rs b/tests/ui/simd/generics.rs index 9b54de809ed1..bd048b19ca88 100644 --- a/tests/ui/simd/generics.rs +++ b/tests/ui/simd/generics.rs @@ -1,6 +1,6 @@ //@ run-pass #![allow(non_camel_case_types)] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] use std::ops; @@ -21,7 +21,7 @@ struct B([T; 4]); struct C([T; N]); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_add(x: T, y: T) -> T; } diff --git a/tests/ui/simd/intrinsic/float-math-pass.rs b/tests/ui/simd/intrinsic/float-math-pass.rs index c1ba50a910b1..ea31e2a7c570 100644 --- a/tests/ui/simd/intrinsic/float-math-pass.rs +++ b/tests/ui/simd/intrinsic/float-math-pass.rs @@ -8,14 +8,14 @@ // Test that the simd floating-point math intrinsics produce correct results. -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] struct f32x4(pub f32, pub f32, pub f32, pub f32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_fsqrt(x: T) -> T; fn simd_fabs(x: T) -> T; fn simd_fsin(x: T) -> T; diff --git a/tests/ui/simd/intrinsic/float-minmax-pass.rs b/tests/ui/simd/intrinsic/float-minmax-pass.rs index a773c79dbe9d..d6cbcd4e05a6 100644 --- a/tests/ui/simd/intrinsic/float-minmax-pass.rs +++ b/tests/ui/simd/intrinsic/float-minmax-pass.rs @@ -3,17 +3,14 @@ // Test that the simd_f{min,max} intrinsics produce the correct results. -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] struct f32x4(pub f32, pub f32, pub f32, pub f32); -extern "platform-intrinsic" { - fn simd_fmin(x: T, y: T) -> T; - fn simd_fmax(x: T, y: T) -> T; -} +use std::intrinsics::simd::*; fn main() { let x = f32x4(1.0, 2.0, 3.0, 4.0); diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-2.rs b/tests/ui/simd/intrinsic/generic-arithmetic-2.rs index b337a77c24c3..4ad98d567113 100644 --- a/tests/ui/simd/intrinsic/generic-arithmetic-2.rs +++ b/tests/ui/simd/intrinsic/generic-arithmetic-2.rs @@ -1,6 +1,6 @@ //@ build-fail -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] #[derive(Copy, Clone)] @@ -14,7 +14,7 @@ pub struct u32x4(pub u32, pub u32, pub u32, pub u32); #[derive(Copy, Clone)] pub struct f32x4(pub f32, pub f32, pub f32, pub f32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_add(x: T, y: T) -> T; fn simd_sub(x: T, y: T) -> T; fn simd_mul(x: T, y: T) -> T; diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs index fa54228bbcfb..33143b1f7b53 100644 --- a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs +++ b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs @@ -1,7 +1,7 @@ //@ run-pass #![allow(non_camel_case_types)] //@ ignore-emscripten FIXME(#45351) hits an LLVM assert -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #[repr(simd)] #[derive(Copy, Clone)] @@ -31,7 +31,7 @@ macro_rules! all_eq_ { }}; } -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_add(x: T, y: T) -> T; fn simd_sub(x: T, y: T) -> T; fn simd_mul(x: T, y: T) -> T; diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-saturating-2.rs b/tests/ui/simd/intrinsic/generic-arithmetic-saturating-2.rs index b31a604cb14c..36be8cc62a8c 100644 --- a/tests/ui/simd/intrinsic/generic-arithmetic-saturating-2.rs +++ b/tests/ui/simd/intrinsic/generic-arithmetic-saturating-2.rs @@ -1,6 +1,6 @@ //@ build-fail //@ ignore-emscripten -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] #[derive(Copy, Clone)] @@ -14,7 +14,7 @@ pub struct x4(pub T, pub T, pub T, pub T); #[derive(Copy, Clone)] pub struct f32x4(pub f32, pub f32, pub f32, pub f32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_saturating_add(x: T, y: T) -> T; fn simd_saturating_sub(x: T, y: T) -> T; } diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs b/tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs index 1a4ba3659c1d..deee9c2ac41e 100644 --- a/tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs +++ b/tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs @@ -2,7 +2,7 @@ //@ ignore-emscripten #![allow(non_camel_case_types)] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] @@ -12,7 +12,7 @@ struct u32x4(pub u32, pub u32, pub u32, pub u32); #[derive(Copy, Clone)] struct I32([i32; N]); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_saturating_add(x: T, y: T) -> T; fn simd_saturating_sub(x: T, y: T) -> T; } diff --git a/tests/ui/simd/intrinsic/generic-as.rs b/tests/ui/simd/intrinsic/generic-as.rs index 807cd927734d..e97bf12c1447 100644 --- a/tests/ui/simd/intrinsic/generic-as.rs +++ b/tests/ui/simd/intrinsic/generic-as.rs @@ -1,8 +1,8 @@ //@ run-pass -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_as(x: T) -> U; } diff --git a/tests/ui/simd/intrinsic/generic-bitmask-pass.rs b/tests/ui/simd/intrinsic/generic-bitmask-pass.rs index 3063a0a4a3af..5c6a07876e35 100644 --- a/tests/ui/simd/intrinsic/generic-bitmask-pass.rs +++ b/tests/ui/simd/intrinsic/generic-bitmask-pass.rs @@ -6,7 +6,7 @@ // Test that the simd_bitmask intrinsic produces correct results. -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #[allow(non_camel_case_types)] #[repr(simd)] @@ -21,7 +21,7 @@ struct u8x4(pub u8, pub u8, pub u8, pub u8); #[derive(Copy, Clone, PartialEq, Debug)] struct Tx4(pub T, pub T, pub T, pub T); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_bitmask(x: T) -> U; } diff --git a/tests/ui/simd/intrinsic/generic-bitmask.rs b/tests/ui/simd/intrinsic/generic-bitmask.rs index f1bda34a85ed..29b9279c370f 100644 --- a/tests/ui/simd/intrinsic/generic-bitmask.rs +++ b/tests/ui/simd/intrinsic/generic-bitmask.rs @@ -3,7 +3,7 @@ // Test that the simd_bitmask intrinsic produces ok-ish error // messages when misused. -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -30,7 +30,7 @@ struct u8x32([u8; 32]); #[derive(Copy, Clone)] struct u8x64([u8; 64]); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_bitmask(x: T) -> U; } diff --git a/tests/ui/simd/intrinsic/generic-bswap-byte.rs b/tests/ui/simd/intrinsic/generic-bswap-byte.rs index d86db6601b23..f1702538165d 100644 --- a/tests/ui/simd/intrinsic/generic-bswap-byte.rs +++ b/tests/ui/simd/intrinsic/generic-bswap-byte.rs @@ -1,5 +1,5 @@ //@ run-pass -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -10,7 +10,7 @@ struct i8x4([i8; 4]); #[derive(Copy, Clone)] struct u8x4([u8; 4]); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_bswap(x: T) -> T; } diff --git a/tests/ui/simd/intrinsic/generic-cast-pass.rs b/tests/ui/simd/intrinsic/generic-cast-pass.rs index 24ec910f5343..e0319a6461ad 100644 --- a/tests/ui/simd/intrinsic/generic-cast-pass.rs +++ b/tests/ui/simd/intrinsic/generic-cast-pass.rs @@ -1,9 +1,9 @@ //@ run-pass //@ ignore-emscripten FIXME(#45351) hits an LLVM assert -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_cast(x: T) -> U; } diff --git a/tests/ui/simd/intrinsic/generic-cast-pointer-width.rs b/tests/ui/simd/intrinsic/generic-cast-pointer-width.rs index ade52086bc42..1c09a9fbf3bf 100644 --- a/tests/ui/simd/intrinsic/generic-cast-pointer-width.rs +++ b/tests/ui/simd/intrinsic/generic-cast-pointer-width.rs @@ -1,7 +1,7 @@ //@ run-pass -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_cast(x: T) -> U; } diff --git a/tests/ui/simd/intrinsic/generic-cast.rs b/tests/ui/simd/intrinsic/generic-cast.rs index 9488d9a42ab7..f3fdbe3403f7 100644 --- a/tests/ui/simd/intrinsic/generic-cast.rs +++ b/tests/ui/simd/intrinsic/generic-cast.rs @@ -1,6 +1,6 @@ //@ build-fail -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #[repr(simd)] #[derive(Copy, Clone)] @@ -23,7 +23,7 @@ struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_cast(x: T) -> U; } diff --git a/tests/ui/simd/intrinsic/generic-comparison-pass.rs b/tests/ui/simd/intrinsic/generic-comparison-pass.rs index 083236387e47..a4df836b6f82 100644 --- a/tests/ui/simd/intrinsic/generic-comparison-pass.rs +++ b/tests/ui/simd/intrinsic/generic-comparison-pass.rs @@ -1,7 +1,7 @@ //@ run-pass //@ ignore-emscripten FIXME(#45351) hits an LLVM assert -#![feature(repr_simd, platform_intrinsics, concat_idents)] +#![feature(repr_simd, intrinsics, concat_idents)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -14,7 +14,7 @@ struct u32x4(pub u32, pub u32, pub u32, pub u32); #[derive(Copy, Clone)] struct f32x4(pub f32, pub f32, pub f32, pub f32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_eq(x: T, y: T) -> U; fn simd_ne(x: T, y: T) -> U; fn simd_lt(x: T, y: T) -> U; diff --git a/tests/ui/simd/intrinsic/generic-comparison.rs b/tests/ui/simd/intrinsic/generic-comparison.rs index 710e660d9cbb..bb2720f615fe 100644 --- a/tests/ui/simd/intrinsic/generic-comparison.rs +++ b/tests/ui/simd/intrinsic/generic-comparison.rs @@ -1,6 +1,6 @@ //@ build-fail -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #[repr(simd)] #[derive(Copy, Clone)] @@ -12,7 +12,7 @@ struct i32x4(i32, i32, i32, i32); struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_eq(x: T, y: T) -> U; fn simd_ne(x: T, y: T) -> U; fn simd_lt(x: T, y: T) -> U; diff --git a/tests/ui/simd/intrinsic/generic-elements-pass.rs b/tests/ui/simd/intrinsic/generic-elements-pass.rs index e3b527fa4fe4..730030878193 100644 --- a/tests/ui/simd/intrinsic/generic-elements-pass.rs +++ b/tests/ui/simd/intrinsic/generic-elements-pass.rs @@ -1,7 +1,7 @@ //@ run-pass //@ ignore-emscripten FIXME(#45351) hits an LLVM assert -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![feature(inline_const)] #[repr(simd)] @@ -18,7 +18,7 @@ struct i32x4(i32, i32, i32, i32); struct i32x8(i32, i32, i32, i32, i32, i32, i32, i32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_insert(x: T, idx: u32, y: E) -> T; fn simd_extract(x: T, idx: u32) -> E; diff --git a/tests/ui/simd/intrinsic/generic-elements.rs b/tests/ui/simd/intrinsic/generic-elements.rs index a8ee4cf39657..abceb08ecc5a 100644 --- a/tests/ui/simd/intrinsic/generic-elements.rs +++ b/tests/ui/simd/intrinsic/generic-elements.rs @@ -1,6 +1,6 @@ //@ build-fail -#![feature(repr_simd, platform_intrinsics, rustc_attrs, adt_const_params)] +#![feature(repr_simd, intrinsics, rustc_attrs, adt_const_params)] #![allow(incomplete_features)] #[repr(simd)] @@ -31,7 +31,7 @@ struct f32x4(f32, f32, f32, f32); struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_insert(x: T, idx: u32, y: E) -> T; fn simd_extract(x: T, idx: u32) -> E; diff --git a/tests/ui/simd/intrinsic/generic-gather-pass.rs b/tests/ui/simd/intrinsic/generic-gather-pass.rs index ca9e9de2afa1..a00bc67e73bd 100644 --- a/tests/ui/simd/intrinsic/generic-gather-pass.rs +++ b/tests/ui/simd/intrinsic/generic-gather-pass.rs @@ -3,14 +3,14 @@ // Test that the simd_{gather,scatter} intrinsics produce the correct results. -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] struct x4(pub T, pub T, pub T, pub T); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_gather(x: T, y: U, z: V) -> T; fn simd_scatter(x: T, y: U, z: V) -> (); } diff --git a/tests/ui/simd/intrinsic/generic-reduction-pass.rs b/tests/ui/simd/intrinsic/generic-reduction-pass.rs index cf4669cd61f5..64902788709e 100644 --- a/tests/ui/simd/intrinsic/generic-reduction-pass.rs +++ b/tests/ui/simd/intrinsic/generic-reduction-pass.rs @@ -5,7 +5,7 @@ // Test that the simd_reduce_{op} intrinsics produce the correct results. -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #[allow(non_camel_case_types)] #[repr(simd)] @@ -24,7 +24,7 @@ struct f32x4(pub f32, pub f32, pub f32, pub f32); #[derive(Copy, Clone)] struct b8x4(pub i8, pub i8, pub i8, pub i8); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_reduce_add_unordered(x: T) -> U; fn simd_reduce_mul_unordered(x: T) -> U; fn simd_reduce_add_ordered(x: T, acc: U) -> U; diff --git a/tests/ui/simd/intrinsic/generic-reduction.rs b/tests/ui/simd/intrinsic/generic-reduction.rs index 5e3debb411e4..96df73591693 100644 --- a/tests/ui/simd/intrinsic/generic-reduction.rs +++ b/tests/ui/simd/intrinsic/generic-reduction.rs @@ -4,7 +4,7 @@ // Test that the simd_reduce_{op} intrinsics produce ok-ish error // messages when misused. -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -16,7 +16,7 @@ pub struct f32x4(pub f32, pub f32, pub f32, pub f32); pub struct u32x4(pub u32, pub u32, pub u32, pub u32); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_reduce_add_ordered(x: T, y: U) -> U; fn simd_reduce_mul_ordered(x: T, y: U) -> U; fn simd_reduce_and(x: T) -> U; diff --git a/tests/ui/simd/intrinsic/generic-select-pass.rs b/tests/ui/simd/intrinsic/generic-select-pass.rs index df8a89e26c9f..98e1534e6e62 100644 --- a/tests/ui/simd/intrinsic/generic-select-pass.rs +++ b/tests/ui/simd/intrinsic/generic-select-pass.rs @@ -6,7 +6,7 @@ // Test that the simd_select intrinsics produces correct results. -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #[allow(non_camel_case_types)] #[repr(simd)] @@ -29,7 +29,7 @@ struct f32x4(pub f32, pub f32, pub f32, pub f32); #[derive(Copy, Clone, PartialEq, Debug)] struct b8x4(pub i8, pub i8, pub i8, pub i8); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_select(x: T, a: U, b: U) -> U; fn simd_select_bitmask(x: T, a: U, b: U) -> U; } diff --git a/tests/ui/simd/intrinsic/generic-select.rs b/tests/ui/simd/intrinsic/generic-select.rs index ab963ed942f7..215ae405c37e 100644 --- a/tests/ui/simd/intrinsic/generic-select.rs +++ b/tests/ui/simd/intrinsic/generic-select.rs @@ -3,7 +3,7 @@ // Test that the simd_select intrinsic produces ok-ish error // messages when misused. -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -22,7 +22,7 @@ struct b8x4(pub i8, pub i8, pub i8, pub i8); #[derive(Copy, Clone, PartialEq)] struct b8x8(pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_select(x: T, a: U, b: U) -> U; fn simd_select_bitmask(x: T, a: U, b: U) -> U; } diff --git a/tests/ui/simd/intrinsic/generic-shuffle.rs b/tests/ui/simd/intrinsic/generic-shuffle.rs index db814f02c8b3..c0888f677841 100644 --- a/tests/ui/simd/intrinsic/generic-shuffle.rs +++ b/tests/ui/simd/intrinsic/generic-shuffle.rs @@ -3,13 +3,13 @@ // Test that the simd_shuffle intrinsic produces ok-ish error // messages when misused. -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #[repr(simd)] #[derive(Copy, Clone)] pub struct Simd([T; N]); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_shuffle(a: T, b: T, i: I) -> U; } diff --git a/tests/ui/simd/intrinsic/inlining-issue67557-ice.rs b/tests/ui/simd/intrinsic/inlining-issue67557-ice.rs index 5b49f4f7203c..928d3824703e 100644 --- a/tests/ui/simd/intrinsic/inlining-issue67557-ice.rs +++ b/tests/ui/simd/intrinsic/inlining-issue67557-ice.rs @@ -3,9 +3,9 @@ // //@ run-pass //@ compile-flags: -Zmir-opt-level=4 -#![feature(platform_intrinsics, repr_simd)] +#![feature(intrinsics, repr_simd)] -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_shuffle(x: T, y: T, idx: I) -> U; } diff --git a/tests/ui/simd/intrinsic/inlining-issue67557.rs b/tests/ui/simd/intrinsic/inlining-issue67557.rs index 3d6284ef1c6b..b8b8dbba547d 100644 --- a/tests/ui/simd/intrinsic/inlining-issue67557.rs +++ b/tests/ui/simd/intrinsic/inlining-issue67557.rs @@ -3,9 +3,9 @@ // //@ run-pass //@ compile-flags: -Zmir-opt-level=4 -#![feature(platform_intrinsics, repr_simd)] +#![feature(intrinsics, repr_simd)] -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_shuffle(x: T, y: T, idx: I) -> U; } diff --git a/tests/ui/simd/intrinsic/issue-85855.rs b/tests/ui/simd/intrinsic/issue-85855.rs index f276fbd66947..dc04699f7f89 100644 --- a/tests/ui/simd/intrinsic/issue-85855.rs +++ b/tests/ui/simd/intrinsic/issue-85855.rs @@ -2,10 +2,10 @@ // with the wrong number of generic lifetime/type/const parameters, and // that no ICE occurs in these cases. -#![feature(platform_intrinsics)] +#![feature(intrinsics)] #![crate_type="lib"] -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_saturating_add<'a, T: 'a>(x: T, y: T); //~^ ERROR: intrinsic has wrong number of lifetime parameters diff --git a/tests/ui/simd/intrinsic/ptr-cast.rs b/tests/ui/simd/intrinsic/ptr-cast.rs index 109e1d0039a6..83d86baf334a 100644 --- a/tests/ui/simd/intrinsic/ptr-cast.rs +++ b/tests/ui/simd/intrinsic/ptr-cast.rs @@ -1,8 +1,8 @@ //@ run-pass -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_cast_ptr(x: T) -> U; fn simd_expose_addr(x: T) -> U; fn simd_from_exposed_addr(x: T) -> U; diff --git a/tests/ui/simd/issue-105439.rs b/tests/ui/simd/issue-105439.rs index 3eb137e4ee7d..3cb43fc8b1af 100644 --- a/tests/ui/simd/issue-105439.rs +++ b/tests/ui/simd/issue-105439.rs @@ -2,14 +2,14 @@ //@ compile-flags: -O -Zverify-llvm-ir #![feature(repr_simd)] -#![feature(platform_intrinsics)] +#![feature(intrinsics)] #[allow(non_camel_case_types)] #[derive(Clone, Copy)] #[repr(simd)] struct i32x4([i32; 4]); -extern "platform-intrinsic" { +extern "rust-intrinsic" { pub(crate) fn simd_add(x: T, y: T) -> T; } diff --git a/tests/ui/simd/issue-39720.rs b/tests/ui/simd/issue-39720.rs index ea6e893b79d9..4610b1d50044 100644 --- a/tests/ui/simd/issue-39720.rs +++ b/tests/ui/simd/issue-39720.rs @@ -1,7 +1,7 @@ //@ run-pass //@ ignore-emscripten FIXME(#45351) -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #[repr(simd)] #[derive(Copy, Clone, Debug)] @@ -11,7 +11,7 @@ pub struct Char3(pub i8, pub i8, pub i8); #[derive(Copy, Clone, Debug)] pub struct Short3(pub i16, pub i16, pub i16); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_cast(x: T) -> U; } diff --git a/tests/ui/simd/issue-85915-simd-ptrs.rs b/tests/ui/simd/issue-85915-simd-ptrs.rs index 96ac76f0590e..edf60e0205c2 100644 --- a/tests/ui/simd/issue-85915-simd-ptrs.rs +++ b/tests/ui/simd/issue-85915-simd-ptrs.rs @@ -3,7 +3,7 @@ // Short form of the generic gather/scatter tests, // verifying simd([*const T; N]) and simd([*mut T; N]) pass typeck and work. -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] @@ -22,7 +22,7 @@ struct f32x4([f32; 4]); #[derive(Copy, Clone, PartialEq, Debug)] struct i32x4([i32; 4]); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_gather(x: T, y: U, z: V) -> T; fn simd_scatter(x: T, y: U, z: V) -> (); } diff --git a/tests/ui/simd/issue-89193.rs b/tests/ui/simd/issue-89193.rs index f34242e7bf89..a4ed9be9962f 100644 --- a/tests/ui/simd/issue-89193.rs +++ b/tests/ui/simd/issue-89193.rs @@ -3,14 +3,14 @@ // Test that simd gather instructions on slice of usize don't cause crash // See issue #89183 - https://github.com/rust-lang/rust/issues/89193 -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] struct x4(pub T, pub T, pub T, pub T); -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_gather(x: T, y: U, z: V) -> T; } diff --git a/tests/ui/simd/masked-load-store-build-fail.rs b/tests/ui/simd/masked-load-store-build-fail.rs index 7b414dfcc932..fbd657763c98 100644 --- a/tests/ui/simd/masked-load-store-build-fail.rs +++ b/tests/ui/simd/masked-load-store-build-fail.rs @@ -1,7 +1,7 @@ //@ build-fail -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_masked_load(mask: M, pointer: P, values: T) -> T; fn simd_masked_store(mask: M, pointer: P, values: T) -> (); } diff --git a/tests/ui/simd/masked-load-store-check-fail.rs b/tests/ui/simd/masked-load-store-check-fail.rs index a86979d8faf6..39c82c41385c 100644 --- a/tests/ui/simd/masked-load-store-check-fail.rs +++ b/tests/ui/simd/masked-load-store-check-fail.rs @@ -1,7 +1,7 @@ //@ check-fail -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_masked_load(mask: M, pointer: P, values: T) -> T; fn simd_masked_store(mask: M, pointer: P, values: T) -> (); } diff --git a/tests/ui/simd/masked-load-store.rs b/tests/ui/simd/masked-load-store.rs index b2f5490727fd..902143f92615 100644 --- a/tests/ui/simd/masked-load-store.rs +++ b/tests/ui/simd/masked-load-store.rs @@ -1,7 +1,7 @@ //@ run-pass -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_masked_load(mask: M, pointer: P, values: T) -> T; fn simd_masked_store(mask: M, pointer: P, values: T) -> (); } diff --git a/tests/ui/simd/monomorphize-shuffle-index.rs b/tests/ui/simd/monomorphize-shuffle-index.rs index 052f0eec472d..379616884a1b 100644 --- a/tests/ui/simd/monomorphize-shuffle-index.rs +++ b/tests/ui/simd/monomorphize-shuffle-index.rs @@ -1,10 +1,10 @@ //@[old]run-pass //@[generic_with_fn]run-pass //@ revisions: old generic generic_with_fn -#![feature(repr_simd, platform_intrinsics, adt_const_params, generic_const_exprs)] +#![feature(repr_simd, intrinsics, adt_const_params, generic_const_exprs)] #![allow(incomplete_features)] -extern "platform-intrinsic" { +extern "rust-intrinsic" { #[cfg(old)] fn simd_shuffle(a: T, b: T, i: I) -> U; #[cfg(any(generic, generic_with_fn))] diff --git a/tests/ui/simd/repr_packed.rs b/tests/ui/simd/repr_packed.rs index 395751e86f11..411bba3454eb 100644 --- a/tests/ui/simd/repr_packed.rs +++ b/tests/ui/simd/repr_packed.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(non_camel_case_types)] #[repr(simd, packed)] @@ -25,7 +25,7 @@ fn check_ty() { check_size_align::(); } -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_add(a: T, b: T) -> T; } diff --git a/tests/ui/simd/shuffle.rs b/tests/ui/simd/shuffle.rs index 5022afc5b496..09926d95557c 100644 --- a/tests/ui/simd/shuffle.rs +++ b/tests/ui/simd/shuffle.rs @@ -2,11 +2,11 @@ //@ revisions: opt noopt //@[noopt] compile-flags: -Copt-level=0 //@[opt] compile-flags: -O -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #![allow(incomplete_features)] #![feature(adt_const_params)] -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_shuffle(a: T, b: T, i: I) -> U; } diff --git a/tests/ui/simd/simd-bitmask.rs b/tests/ui/simd/simd-bitmask.rs index a3717c9e21ae..4a7c3bc77507 100644 --- a/tests/ui/simd/simd-bitmask.rs +++ b/tests/ui/simd/simd-bitmask.rs @@ -1,8 +1,8 @@ //@run-pass //@ignore-endian-big behavior of simd_select_bitmask is endian-specific -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] -extern "platform-intrinsic" { +extern "rust-intrinsic" { fn simd_bitmask(v: T) -> U; fn simd_select_bitmask(m: T, a: U, b: U) -> U; } diff --git a/tests/ui/simd/type-generic-monomorphisation-empty.rs b/tests/ui/simd/type-generic-monomorphisation-empty.rs index 38c5581105d0..4700f642065b 100644 --- a/tests/ui/simd/type-generic-monomorphisation-empty.rs +++ b/tests/ui/simd/type-generic-monomorphisation-empty.rs @@ -1,6 +1,6 @@ //@ build-fail -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] //@ error-pattern:monomorphising SIMD type `Simd<0>` of zero length diff --git a/tests/ui/simd/type-generic-monomorphisation-oversized.rs b/tests/ui/simd/type-generic-monomorphisation-oversized.rs index 53f66f1d596f..9949f913c445 100644 --- a/tests/ui/simd/type-generic-monomorphisation-oversized.rs +++ b/tests/ui/simd/type-generic-monomorphisation-oversized.rs @@ -1,6 +1,6 @@ //@ build-fail -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] //@ error-pattern:monomorphising SIMD type `Simd<65536>` of length greater than 32768 diff --git a/tests/ui/simd/type-generic-monomorphisation-power-of-two.rs b/tests/ui/simd/type-generic-monomorphisation-power-of-two.rs index 26269335bc47..b3e228970d00 100644 --- a/tests/ui/simd/type-generic-monomorphisation-power-of-two.rs +++ b/tests/ui/simd/type-generic-monomorphisation-power-of-two.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] #[repr(simd)] struct Simd([f32; N]); diff --git a/tests/ui/simd/type-generic-monomorphisation.rs b/tests/ui/simd/type-generic-monomorphisation.rs index 90ddd1dde0fd..2eeba55ef913 100644 --- a/tests/ui/simd/type-generic-monomorphisation.rs +++ b/tests/ui/simd/type-generic-monomorphisation.rs @@ -1,6 +1,6 @@ //@ build-fail -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, intrinsics)] //@ error-pattern:monomorphising SIMD type `Simd2` with a non-primitive-scalar (integer/float/pointer) element type `X` From 3af67bba18f7a204a93831f3eafa26a73de11721 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 25 Feb 2024 16:28:38 +0100 Subject: [PATCH 14/39] Correctly handle if rustdoc JS script hash changed --- src/librustdoc/html/static/js/main.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index b26efb75ff65..b9a769a7c6da 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -185,9 +185,12 @@ function preLoadCss(cssUrl) { (function() { const isHelpPage = window.location.pathname.endsWith("/help.html"); - function loadScript(url) { + function loadScript(url, errorCallback) { const script = document.createElement("script"); script.src = url; + if (errorCallback !== undefined) { + script.onerror = errorCallback; + } document.head.append(script); } @@ -292,11 +295,16 @@ function preLoadCss(cssUrl) { return; } let searchLoaded = false; + // If you're browsing the nightly docs, the page might need to be refreshed for the + // search to work because the hash of the JS scripts might have changed. + function sendSearchForm() { + document.getElementsByClassName("search-form")[0].submit(); + } function loadSearch() { if (!searchLoaded) { searchLoaded = true; - loadScript(getVar("static-root-path") + getVar("search-js")); - loadScript(resourcePath("search-index", ".js")); + loadScript(getVar("static-root-path") + getVar("search-js"), sendSearchForm); + loadScript(resourcePath("search-index", ".js"), sendSearchForm); } } From a3fce72a27ee41077c3752851ff778f886f0a4fa Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Sun, 25 Feb 2024 22:22:09 +0100 Subject: [PATCH 15/39] Add `ast::ExprKind::Dummy` --- compiler/rustc_ast/src/ast.rs | 18 ++++-------------- compiler/rustc_ast/src/mut_visit.rs | 4 ++-- compiler/rustc_ast/src/util/classify.rs | 3 ++- compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 6 ++++++ compiler/rustc_ast_lowering/src/pat.rs | 3 ++- .../rustc_ast_pretty/src/pprust/state/expr.rs | 5 +++++ .../rustc_builtin_macros/src/assert/context.rs | 1 + compiler/rustc_builtin_macros/src/concat.rs | 1 + .../rustc_builtin_macros/src/concat_bytes.rs | 1 + compiler/rustc_expand/src/base.rs | 3 +++ compiler/rustc_parse/src/parser/expr.rs | 3 ++- compiler/rustc_parse/src/parser/pat.rs | 2 +- compiler/rustc_passes/src/hir_stats.rs | 2 +- src/tools/clippy/clippy_utils/src/ast_utils.rs | 1 + src/tools/clippy/clippy_utils/src/sugg.rs | 3 ++- src/tools/rustfmt/src/expr.rs | 2 +- src/tools/rustfmt/src/utils.rs | 1 + 18 files changed, 37 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 3fdb2a2225a5..b30324c76667 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1296,23 +1296,10 @@ impl Expr { ExprKind::Yeet(..) => ExprPrecedence::Yeet, ExprKind::FormatArgs(..) => ExprPrecedence::FormatArgs, ExprKind::Become(..) => ExprPrecedence::Become, - ExprKind::Err => ExprPrecedence::Err, + ExprKind::Err | ExprKind::Dummy => ExprPrecedence::Err, } } - pub fn take(&mut self) -> Self { - mem::replace( - self, - Expr { - id: DUMMY_NODE_ID, - kind: ExprKind::Err, - span: DUMMY_SP, - attrs: AttrVec::new(), - tokens: None, - }, - ) - } - /// To a first-order approximation, is this a pattern? pub fn is_approximately_pattern(&self) -> bool { matches!( @@ -1532,6 +1519,9 @@ pub enum ExprKind { /// Placeholder for an expression that wasn't syntactically well formed in some way. Err, + + /// Acts as a null expression. Lowering it will always emit a bug. + Dummy, } /// Used to differentiate between `for` loops and `for await` loops. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index c42c41999732..b2f3bb303de6 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1526,7 +1526,7 @@ pub fn noop_visit_expr( } ExprKind::Try(expr) => vis.visit_expr(expr), ExprKind::TryBlock(body) => vis.visit_block(body), - ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err => {} + ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err | ExprKind::Dummy => {} } vis.visit_id(id); vis.visit_span(span); @@ -1642,7 +1642,7 @@ impl DummyAstNode for Expr { fn dummy() -> Self { Expr { id: DUMMY_NODE_ID, - kind: ExprKind::Err, + kind: ExprKind::Dummy, span: Default::default(), attrs: Default::default(), tokens: Default::default(), diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index 098b8f2d6d03..e70a75622e63 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -89,7 +89,8 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> { | Paren(_) | Try(_) | Yeet(None) - | Err => break None, + | Err + | Dummy => break None, } } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index ecf379cc2408..ab3d9b496333 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -1063,7 +1063,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V } ExprKind::Try(subexpression) => try_visit!(visitor.visit_expr(subexpression)), ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)), - ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err => {} + ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err | ExprKind::Dummy => {} } visitor.visit_expr_post(expression) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index aafa99b3aa6f..5d33a7a91427 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -14,6 +14,7 @@ use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; +use rustc_middle::span_bug; use rustc_session::errors::report_lit_error; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -331,6 +332,11 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::Err => { hir::ExprKind::Err(self.dcx().span_delayed_bug(e.span, "lowered ExprKind::Err")) } + + ExprKind::Dummy => { + span_bug!(e.span, "lowered ExprKind::Dummy") + } + ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr), ExprKind::Paren(_) | ExprKind::ForLoop { .. } => { diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index c097feb6b347..755b073b2c37 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -331,7 +331,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::IncludedBytes(..) - | ExprKind::Err => {} + | ExprKind::Err + | ExprKind::Dummy => {} ExprKind::Path(..) if allow_paths => {} ExprKind::Unary(UnOp::Neg, inner) if matches!(inner.kind, ExprKind::Lit(_)) => {} _ => { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index ff154a009ed0..0f9fe89402b1 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -898,6 +898,11 @@ impl<'a> State<'a> { self.word("/*ERROR*/"); self.pclose() } + ast::ExprKind::Dummy => { + self.popen(); + self.word("/*DUMMY*/"); + self.pclose(); + } } self.ann.post(self, AnnNode::Expr(expr)); diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index 01821ee833f1..7737041090b0 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -303,6 +303,7 @@ impl<'cx, 'a> Context<'cx, 'a> { | ExprKind::Closure(_) | ExprKind::ConstBlock(_) | ExprKind::Continue(_) + | ExprKind::Dummy | ExprKind::Err | ExprKind::Field(_, _) | ExprKind::ForLoop { .. } diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs index 795161e65d81..691142c03edd 100644 --- a/compiler/rustc_builtin_macros/src/concat.rs +++ b/compiler/rustc_builtin_macros/src/concat.rs @@ -68,6 +68,7 @@ pub fn expand_concat( ast::ExprKind::Err => { has_errors = true; } + ast::ExprKind::Dummy => cx.dcx().span_bug(e.span, "concatenating `ExprKind::Dummy`"), _ => { missing_literal.push(e.span); } diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index 3ef8cb7bffef..8ce004586ce8 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -176,6 +176,7 @@ pub fn expand_concat_bytes( ast::ExprKind::Err => { has_errors = true; } + ast::ExprKind::Dummy => cx.dcx().span_bug(e.span, "concatenating `ExprKind::Dummy`"), _ => { missing_literals.push(e.span); } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 1c8d18bec65c..762d6745341a 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1279,6 +1279,9 @@ pub fn expr_to_spanned_string<'a>( _ => Some((cx.dcx().struct_span_err(expr.span, err_msg), false)), }, ast::ExprKind::Err => None, + ast::ExprKind::Dummy => { + cx.dcx().span_bug(expr.span, "tried to get a string literal from `ExprKind::Dummy`") + } _ => Some((cx.dcx().struct_span_err(expr.span, err_msg), false)), }) } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 1ad637451b19..89f28777bffb 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3949,7 +3949,8 @@ impl MutVisitor for CondChecker<'_> { | ExprKind::Become(_) | ExprKind::IncludedBytes(_) | ExprKind::FormatArgs(_) - | ExprKind::Err => { + | ExprKind::Err + | ExprKind::Dummy => { // These would forbid any let expressions they contain already. } } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 2ede19b11e04..c82b44ac6e10 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -388,7 +388,7 @@ impl<'a> Parser<'a> { // Parse `?`, `.f`, `(arg0, arg1, ...)` or `[expr]` until they've all been eaten. if let Ok(expr) = snapshot .parse_expr_dot_or_call_with( - self.mk_expr_err(pat_span), // equivalent to transforming the parsed pattern into an `Expr` + self.mk_expr(pat_span, ExprKind::Dummy), // equivalent to transforming the parsed pattern into an `Expr` pat_span, AttrVec::new(), ) diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 96429bb77888..be6ba585d200 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -589,7 +589,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { If, While, ForLoop, Loop, Match, Closure, Block, Await, TryBlock, Assign, AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret, InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, - Become, IncludedBytes, Gen, Err + Become, IncludedBytes, Gen, Err, Dummy ] ); ast_visit::walk_expr(self, e) diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 0467a8a65709..81a26a12009d 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -144,6 +144,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (Paren(l), _) => eq_expr(l, r), (_, Paren(r)) => eq_expr(l, r), (Err, Err) => true, + (Dummy, _) | (_, Dummy) => unreachable!("comparing `ExprKind::Dummy`"), (Try(l), Try(r)) | (Await(l, _), Await(r, _)) => eq_expr(l, r), (Array(l), Array(r)) => over(l, r, |l, r| eq_expr(l, r)), (Tup(l), Tup(r)) => over(l, r, |l, r| eq_expr(l, r)), diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index b355e66b7b12..7b1b0388b29f 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -222,7 +222,8 @@ impl<'a> Sugg<'a> { | ast::ExprKind::Array(..) | ast::ExprKind::While(..) | ast::ExprKind::Await(..) - | ast::ExprKind::Err => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0), + | ast::ExprKind::Err + | ast::ExprKind::Dummy => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0), ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp( AssocOp::DotDot, lhs.as_ref().map_or("".into(), |lhs| { diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 4b86c2acdc53..d46d7c53bdb4 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -404,7 +404,7 @@ pub(crate) fn format_expr( // These do not occur in the AST because macros aren't expanded. unreachable!() } - ast::ExprKind::Err => None, + ast::ExprKind::Err | ast::ExprKind::Dummy => None, }; expr_rw diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index 642b6603b1e9..b6b37e492e92 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -497,6 +497,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr | ast::ExprKind::Break(..) | ast::ExprKind::Cast(..) | ast::ExprKind::Continue(..) + | ast::ExprKind::Dummy | ast::ExprKind::Err | ast::ExprKind::Field(..) | ast::ExprKind::IncludedBytes(..) From c440a5b814005c85ec903f9b9e44e25bf5c9c565 Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Sun, 25 Feb 2024 22:22:11 +0100 Subject: [PATCH 16/39] Add `ErrorGuaranteed` to `ast::ExprKind::Err` --- compiler/rustc_ast/src/ast.rs | 4 +- compiler/rustc_ast/src/mut_visit.rs | 2 +- compiler/rustc_ast/src/util/classify.rs | 2 +- compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 4 +- compiler/rustc_ast_lowering/src/pat.rs | 2 +- .../rustc_ast_pretty/src/pprust/state/expr.rs | 2 +- compiler/rustc_builtin_macros/src/asm.rs | 71 ++++---- compiler/rustc_builtin_macros/src/assert.rs | 4 +- .../src/assert/context.rs | 2 +- compiler/rustc_builtin_macros/src/cfg.rs | 4 +- .../rustc_builtin_macros/src/compile_error.rs | 14 +- compiler/rustc_builtin_macros/src/concat.rs | 35 ++-- .../rustc_builtin_macros/src/concat_bytes.rs | 131 +++++++------- .../rustc_builtin_macros/src/concat_idents.rs | 12 +- .../src/deriving/default.rs | 53 +++--- compiler/rustc_builtin_macros/src/env.rs | 36 ++-- compiler/rustc_builtin_macros/src/format.rs | 90 +++++----- compiler/rustc_builtin_macros/src/lib.rs | 1 + .../rustc_builtin_macros/src/source_util.rs | 43 ++--- .../rustc_builtin_macros/src/type_ascribe.rs | 4 +- compiler/rustc_expand/src/base.rs | 99 ++++++----- compiler/rustc_expand/src/expand.rs | 82 +++++---- compiler/rustc_expand/src/mbe/diagnostics.rs | 18 +- compiler/rustc_expand/src/mbe/macro_check.rs | 62 +++---- compiler/rustc_expand/src/mbe/macro_rules.rs | 132 +++++++------- compiler/rustc_lint/src/unused.rs | 2 +- .../rustc_parse/src/parser/diagnostics.rs | 90 +++++----- compiler/rustc_parse/src/parser/expr.rs | 165 ++++++++++-------- compiler/rustc_parse/src/parser/item.rs | 4 +- compiler/rustc_parse/src/parser/pat.rs | 18 +- compiler/rustc_parse/src/parser/stmt.rs | 62 ++++--- compiler/rustc_parse/src/validate_attr.rs | 2 +- .../clippy/clippy_utils/src/ast_utils.rs | 2 +- src/tools/clippy/clippy_utils/src/sugg.rs | 2 +- src/tools/rustfmt/src/expr.rs | 2 +- src/tools/rustfmt/src/utils.rs | 2 +- 37 files changed, 660 insertions(+), 602 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index b30324c76667..8ba2f222fcfa 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1296,7 +1296,7 @@ impl Expr { ExprKind::Yeet(..) => ExprPrecedence::Yeet, ExprKind::FormatArgs(..) => ExprPrecedence::FormatArgs, ExprKind::Become(..) => ExprPrecedence::Become, - ExprKind::Err | ExprKind::Dummy => ExprPrecedence::Err, + ExprKind::Err(_) | ExprKind::Dummy => ExprPrecedence::Err, } } @@ -1518,7 +1518,7 @@ pub enum ExprKind { FormatArgs(P), /// Placeholder for an expression that wasn't syntactically well formed in some way. - Err, + Err(ErrorGuaranteed), /// Acts as a null expression. Lowering it will always emit a bug. Dummy, diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index b2f3bb303de6..60bc21c6441f 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1526,7 +1526,7 @@ pub fn noop_visit_expr( } ExprKind::Try(expr) => vis.visit_expr(expr), ExprKind::TryBlock(body) => vis.visit_block(body), - ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err | ExprKind::Dummy => {} + ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err(_) | ExprKind::Dummy => {} } vis.visit_id(id); vis.visit_span(span); diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index e70a75622e63..f21a9cabb81b 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -89,7 +89,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> { | Paren(_) | Try(_) | Yeet(None) - | Err + | Err(_) | Dummy => break None, } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index ab3d9b496333..f29022386a9d 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -1063,7 +1063,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V } ExprKind::Try(subexpression) => try_visit!(visitor.visit_expr(subexpression)), ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)), - ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err | ExprKind::Dummy => {} + ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err(_) | ExprKind::Dummy => {} } visitor.visit_expr_post(expression) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 5d33a7a91427..9950db4784b9 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -329,9 +329,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()), - ExprKind::Err => { - hir::ExprKind::Err(self.dcx().span_delayed_bug(e.span, "lowered ExprKind::Err")) - } + ExprKind::Err(guar) => hir::ExprKind::Err(*guar), ExprKind::Dummy => { span_bug!(e.span, "lowered ExprKind::Dummy") diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 755b073b2c37..469cdac11e43 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -331,7 +331,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::IncludedBytes(..) - | ExprKind::Err + | ExprKind::Err(_) | ExprKind::Dummy => {} ExprKind::Path(..) if allow_paths => {} ExprKind::Unary(UnOp::Neg, inner) if matches!(inner.kind, ExprKind::Lit(_)) => {} diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 0f9fe89402b1..433ef03b6e54 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -893,7 +893,7 @@ impl<'a> State<'a> { self.word_nbsp("try"); self.print_block_with_attrs(blk, attrs) } - ast::ExprKind::Err => { + ast::ExprKind::Err(_) => { self.popen(); self.word("/*ERROR*/"); self.pclose() diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 263081ea19ea..29bf5e9f3049 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -13,7 +13,7 @@ use rustc_session::lint; use rustc_session::parse::ParseSess; use rustc_span::symbol::Ident; use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::{InnerSpan, Span}; +use rustc_span::{ErrorGuaranteed, InnerSpan, Span}; use rustc_target::asm::InlineAsmArch; use smallvec::smallvec; @@ -433,7 +433,10 @@ fn parse_reg<'a>( Ok(result) } -fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option { +fn expand_preparsed_asm( + ecx: &mut ExtCtxt<'_>, + args: AsmArgs, +) -> Result { let mut template = vec![]; // Register operands are implicitly used since they are not allowed to be // referenced in the template string. @@ -459,10 +462,10 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option template_part, Err(err) => { - if let Some((err, _)) = err { - err.emit(); - } - return None; + return Err(match err { + Ok((err, _)) => err.emit(), + Err(guar) => guar, + }); } }; @@ -551,8 +554,8 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option, args: AsmArgs) -> Option( ) -> Box { match parse_args(ecx, sp, tts, false) { Ok(args) => { - let expr = if let Some(inline_asm) = expand_preparsed_asm(ecx, args) { - P(ast::Expr { + let expr = match expand_preparsed_asm(ecx, args) { + Ok(inline_asm) => P(ast::Expr { id: ast::DUMMY_NODE_ID, kind: ast::ExprKind::InlineAsm(P(inline_asm)), span: sp, attrs: ast::AttrVec::new(), tokens: None, - }) - } else { - DummyResult::raw_expr(sp, true) + }), + Err(guar) => DummyResult::raw_expr(sp, Some(guar)), }; MacEager::expr(expr) } Err(err) => { - err.emit(); - DummyResult::any(sp) + let guar = err.emit(); + DummyResult::any(sp, guar) } } } @@ -762,28 +764,25 @@ pub(super) fn expand_global_asm<'cx>( tts: TokenStream, ) -> Box { match parse_args(ecx, sp, tts, true) { - Ok(args) => { - if let Some(inline_asm) = expand_preparsed_asm(ecx, args) { - MacEager::items(smallvec![P(ast::Item { - ident: Ident::empty(), - attrs: ast::AttrVec::new(), - id: ast::DUMMY_NODE_ID, - kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)), - vis: ast::Visibility { - span: sp.shrink_to_lo(), - kind: ast::VisibilityKind::Inherited, - tokens: None, - }, - span: sp, + Ok(args) => match expand_preparsed_asm(ecx, args) { + Ok(inline_asm) => MacEager::items(smallvec![P(ast::Item { + ident: Ident::empty(), + attrs: ast::AttrVec::new(), + id: ast::DUMMY_NODE_ID, + kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)), + vis: ast::Visibility { + span: sp.shrink_to_lo(), + kind: ast::VisibilityKind::Inherited, tokens: None, - })]) - } else { - DummyResult::any(sp) - } - } + }, + span: sp, + tokens: None, + })]), + Err(guar) => DummyResult::any(sp, guar), + }, Err(err) => { - err.emit(); - DummyResult::any(sp) + let guar = err.emit(); + DummyResult::any(sp, guar) } } } diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index 501d557f3ab8..613ce43dec2d 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -23,8 +23,8 @@ pub fn expand_assert<'cx>( let Assert { cond_expr, custom_message } = match parse_assert(cx, span, tts) { Ok(assert) => assert, Err(err) => { - err.emit(); - return DummyResult::any(span); + let guar = err.emit(); + return DummyResult::any(span, guar); } }; diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index 7737041090b0..56c56b2704b0 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -304,7 +304,7 @@ impl<'cx, 'a> Context<'cx, 'a> { | ExprKind::ConstBlock(_) | ExprKind::Continue(_) | ExprKind::Dummy - | ExprKind::Err + | ExprKind::Err(_) | ExprKind::Field(_, _) | ExprKind::ForLoop { .. } | ExprKind::FormatArgs(_) diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 581d390992ad..ca66bc0da0cc 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -29,8 +29,8 @@ pub fn expand_cfg( MacEager::expr(cx.expr_bool(sp, matches_cfg)) } Err(err) => { - err.emit(); - DummyResult::any(sp) + let guar = err.emit(); + DummyResult::any(sp, guar) } } } diff --git a/compiler/rustc_builtin_macros/src/compile_error.rs b/compiler/rustc_builtin_macros/src/compile_error.rs index f157575da79b..665003512729 100644 --- a/compiler/rustc_builtin_macros/src/compile_error.rs +++ b/compiler/rustc_builtin_macros/src/compile_error.rs @@ -9,16 +9,14 @@ pub fn expand_compile_error<'cx>( sp: Span, tts: TokenStream, ) -> Box { - let Some(var) = get_single_str_from_tts(cx, sp, tts, "compile_error!") else { - return DummyResult::any(sp); + let var = match get_single_str_from_tts(cx, sp, tts, "compile_error!") { + Ok(var) => var, + Err(guar) => return DummyResult::any(sp, guar), }; - #[expect( - rustc::diagnostic_outside_of_impl, - reason = "diagnostic message is specified by user" - )] + #[expect(rustc::diagnostic_outside_of_impl, reason = "diagnostic message is specified by user")] #[expect(rustc::untranslatable_diagnostic, reason = "diagnostic message is specified by user")] - cx.dcx().span_err(sp, var.to_string()); + let guar = cx.dcx().span_err(sp, var.to_string()); - DummyResult::any(sp) + DummyResult::any(sp, guar) } diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs index 691142c03edd..dd4a0e7f2286 100644 --- a/compiler/rustc_builtin_macros/src/concat.rs +++ b/compiler/rustc_builtin_macros/src/concat.rs @@ -11,12 +11,13 @@ pub fn expand_concat( sp: rustc_span::Span, tts: TokenStream, ) -> Box { - let Some(es) = base::get_exprs_from_tts(cx, tts) else { - return DummyResult::any(sp); + let es = match base::get_exprs_from_tts(cx, tts) { + Ok(es) => es, + Err(guar) => return DummyResult::any(sp, guar), }; let mut accumulator = String::new(); let mut missing_literal = vec![]; - let mut has_errors = false; + let mut guar = None; for e in es { match e.kind { ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) { @@ -33,19 +34,16 @@ pub fn expand_concat( accumulator.push_str(&b.to_string()); } Ok(ast::LitKind::CStr(..)) => { - cx.dcx().emit_err(errors::ConcatCStrLit { span: e.span }); - has_errors = true; + guar = Some(cx.dcx().emit_err(errors::ConcatCStrLit { span: e.span })); } Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => { - cx.dcx().emit_err(errors::ConcatBytestr { span: e.span }); - has_errors = true; + guar = Some(cx.dcx().emit_err(errors::ConcatBytestr { span: e.span })); } - Ok(ast::LitKind::Err(_)) => { - has_errors = true; + Ok(ast::LitKind::Err(guarantee)) => { + guar = Some(guarantee); } Err(err) => { - report_lit_error(&cx.sess.parse_sess, err, token_lit, e.span); - has_errors = true; + guar = Some(report_lit_error(&cx.sess.parse_sess, err, token_lit, e.span)); } }, // We also want to allow negative numeric literals. @@ -56,8 +54,7 @@ pub fn expand_concat( Ok(ast::LitKind::Int(i, _)) => accumulator.push_str(&format!("-{i}")), Ok(ast::LitKind::Float(f, _)) => accumulator.push_str(&format!("-{f}")), Err(err) => { - report_lit_error(&cx.sess.parse_sess, err, token_lit, e.span); - has_errors = true; + guar = Some(report_lit_error(&cx.sess.parse_sess, err, token_lit, e.span)); } _ => missing_literal.push(e.span), } @@ -65,8 +62,8 @@ pub fn expand_concat( ast::ExprKind::IncludedBytes(..) => { cx.dcx().emit_err(errors::ConcatBytestr { span: e.span }); } - ast::ExprKind::Err => { - has_errors = true; + ast::ExprKind::Err(guarantee) => { + guar = Some(guarantee); } ast::ExprKind::Dummy => cx.dcx().span_bug(e.span, "concatenating `ExprKind::Dummy`"), _ => { @@ -76,10 +73,10 @@ pub fn expand_concat( } if !missing_literal.is_empty() { - cx.dcx().emit_err(errors::ConcatMissingLiteral { spans: missing_literal }); - return DummyResult::any(sp); - } else if has_errors { - return DummyResult::any(sp); + let guar = cx.dcx().emit_err(errors::ConcatMissingLiteral { spans: missing_literal }); + return DummyResult::any(sp, guar); + } else if let Some(guar) = guar { + return DummyResult::any(sp, guar); } let sp = cx.with_def_site_ctxt(sp); base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator))) diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index 8ce004586ce8..32e17112d8c4 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -2,7 +2,7 @@ use rustc_ast as ast; use rustc_ast::{ptr::P, tokenstream::TokenStream}; use rustc_expand::base::{self, DummyResult}; use rustc_session::errors::report_lit_error; -use rustc_span::Span; +use rustc_span::{ErrorGuaranteed, Span}; use crate::errors; @@ -12,7 +12,7 @@ fn invalid_type_err( token_lit: ast::token::Lit, span: Span, is_nested: bool, -) { +) -> ErrorGuaranteed { use errors::{ ConcatBytesInvalid, ConcatBytesInvalidSuggestion, ConcatBytesNonU8, ConcatBytesOob, }; @@ -22,12 +22,12 @@ fn invalid_type_err( Ok(ast::LitKind::CStr(_, _)) => { // Avoid ambiguity in handling of terminal `NUL` by refusing to // concatenate C string literals as bytes. - dcx.emit_err(errors::ConcatCStrLit { span: span }); + dcx.emit_err(errors::ConcatCStrLit { span }) } Ok(ast::LitKind::Char(_)) => { let sugg = snippet.map(|snippet| ConcatBytesInvalidSuggestion::CharLit { span, snippet }); - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg }); + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg }) } Ok(ast::LitKind::Str(_, _)) => { // suggestion would be invalid if we are nested @@ -36,86 +36,79 @@ fn invalid_type_err( } else { None }; - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg }); + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg }) } Ok(ast::LitKind::Float(_, _)) => { - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None }); + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None }) } Ok(ast::LitKind::Bool(_)) => { - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None }); + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None }) } - Ok(ast::LitKind::Err(_)) => {} Ok(ast::LitKind::Int(_, _)) if !is_nested => { let sugg = snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span: span, snippet }); - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg }); + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg }) } Ok(ast::LitKind::Int( val, ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), )) => { assert!(val.get() > u8::MAX.into()); // must be an error - dcx.emit_err(ConcatBytesOob { span }); - } - Ok(ast::LitKind::Int(_, _)) => { - dcx.emit_err(ConcatBytesNonU8 { span }); + dcx.emit_err(ConcatBytesOob { span }) } + Ok(ast::LitKind::Int(_, _)) => dcx.emit_err(ConcatBytesNonU8 { span }), Ok(ast::LitKind::ByteStr(..) | ast::LitKind::Byte(_)) => unreachable!(), - Err(err) => { - report_lit_error(&cx.sess.parse_sess, err, token_lit, span); - } + Ok(ast::LitKind::Err(guar)) => guar, + Err(err) => report_lit_error(&cx.sess.parse_sess, err, token_lit, span), } } +/// Returns `expr` as a *single* byte literal if applicable. +/// +/// Otherwise, returns `None`, and either pushes the `expr`'s span to `missing_literals` or +/// updates `guar` accordingly. fn handle_array_element( cx: &mut base::ExtCtxt<'_>, - has_errors: &mut bool, + guar: &mut Option, missing_literals: &mut Vec, expr: &P, ) -> Option { let dcx = cx.dcx(); - match expr.kind { - ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => { - if !*has_errors { - dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false }); - } - *has_errors = true; - None - } - ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) { - Ok(ast::LitKind::Int( - val, - ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), - )) if val.get() <= u8::MAX.into() => Some(val.get() as u8), - Ok(ast::LitKind::Byte(val)) => Some(val), - Ok(ast::LitKind::ByteStr(..)) => { - if !*has_errors { - dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: true }); + match expr.kind { + ast::ExprKind::Lit(token_lit) => { + match ast::LitKind::from_token_lit(token_lit) { + Ok(ast::LitKind::Int( + val, + ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), + )) if let Ok(val) = u8::try_from(val.get()) => { + return Some(val); } - *has_errors = true; - None - } - _ => { - if !*has_errors { - invalid_type_err(cx, token_lit, expr.span, true); + Ok(ast::LitKind::Byte(val)) => return Some(val), + Ok(ast::LitKind::ByteStr(..)) => { + guar.get_or_insert_with(|| { + dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: true }) + }); } - *has_errors = true; - None - } - }, + _ => { + guar.get_or_insert_with(|| invalid_type_err(cx, token_lit, expr.span, true)); + } + }; + } + ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => { + guar.get_or_insert_with(|| { + dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false }) + }); + } ast::ExprKind::IncludedBytes(..) => { - if !*has_errors { - dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false }); - } - *has_errors = true; - None - } - _ => { - missing_literals.push(expr.span); - None + guar.get_or_insert_with(|| { + dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false }) + }); } + _ => missing_literals.push(expr.span), } + + None } pub fn expand_concat_bytes( @@ -123,18 +116,19 @@ pub fn expand_concat_bytes( sp: rustc_span::Span, tts: TokenStream, ) -> Box { - let Some(es) = base::get_exprs_from_tts(cx, tts) else { - return DummyResult::any(sp); + let es = match base::get_exprs_from_tts(cx, tts) { + Ok(es) => es, + Err(guar) => return DummyResult::any(sp, guar), }; let mut accumulator = Vec::new(); let mut missing_literals = vec![]; - let mut has_errors = false; + let mut guar = None; for e in es { match &e.kind { ast::ExprKind::Array(exprs) => { for expr in exprs { if let Some(elem) = - handle_array_element(cx, &mut has_errors, &mut missing_literals, expr) + handle_array_element(cx, &mut guar, &mut missing_literals, expr) { accumulator.push(elem); } @@ -146,14 +140,16 @@ pub fn expand_concat_bytes( ast::LitKind::from_token_lit(token_lit) { if let Some(elem) = - handle_array_element(cx, &mut has_errors, &mut missing_literals, expr) + handle_array_element(cx, &mut guar, &mut missing_literals, expr) { for _ in 0..count_val.get() { accumulator.push(elem); } } } else { - cx.dcx().emit_err(errors::ConcatBytesBadRepeat { span: count.value.span }); + guar = Some( + cx.dcx().emit_err(errors::ConcatBytesBadRepeat { span: count.value.span }), + ); } } &ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) { @@ -164,17 +160,14 @@ pub fn expand_concat_bytes( accumulator.extend_from_slice(bytes); } _ => { - if !has_errors { - invalid_type_err(cx, token_lit, e.span, false); - } - has_errors = true; + guar.get_or_insert_with(|| invalid_type_err(cx, token_lit, e.span, false)); } }, ast::ExprKind::IncludedBytes(bytes) => { accumulator.extend_from_slice(bytes); } - ast::ExprKind::Err => { - has_errors = true; + ast::ExprKind::Err(guarantee) => { + guar = Some(*guarantee); } ast::ExprKind::Dummy => cx.dcx().span_bug(e.span, "concatenating `ExprKind::Dummy`"), _ => { @@ -183,10 +176,10 @@ pub fn expand_concat_bytes( } } if !missing_literals.is_empty() { - cx.dcx().emit_err(errors::ConcatBytesMissingLiteral { spans: missing_literals }); - return base::MacEager::expr(DummyResult::raw_expr(sp, true)); - } else if has_errors { - return base::MacEager::expr(DummyResult::raw_expr(sp, true)); + let guar = cx.dcx().emit_err(errors::ConcatBytesMissingLiteral { spans: missing_literals }); + return base::MacEager::expr(DummyResult::raw_expr(sp, Some(guar))); + } else if let Some(guar) = guar { + return base::MacEager::expr(DummyResult::raw_expr(sp, Some(guar))); } let sp = cx.with_def_site_ctxt(sp); base::MacEager::expr(cx.expr_byte_str(sp, accumulator)) diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs index 17fd3901cc6b..29d3f6164aa1 100644 --- a/compiler/rustc_builtin_macros/src/concat_idents.rs +++ b/compiler/rustc_builtin_macros/src/concat_idents.rs @@ -14,8 +14,8 @@ pub fn expand_concat_idents<'cx>( tts: TokenStream, ) -> Box { if tts.is_empty() { - cx.dcx().emit_err(errors::ConcatIdentsMissingArgs { span: sp }); - return DummyResult::any(sp); + let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingArgs { span: sp }); + return DummyResult::any(sp, guar); } let mut res_str = String::new(); @@ -24,8 +24,8 @@ pub fn expand_concat_idents<'cx>( match e { TokenTree::Token(Token { kind: token::Comma, .. }, _) => {} _ => { - cx.dcx().emit_err(errors::ConcatIdentsMissingComma { span: sp }); - return DummyResult::any(sp); + let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingComma { span: sp }); + return DummyResult::any(sp, guar); } } } else { @@ -36,8 +36,8 @@ pub fn expand_concat_idents<'cx>( } } - cx.dcx().emit_err(errors::ConcatIdentsIdentArgs { span: sp }); - return DummyResult::any(sp); + let guar = cx.dcx().emit_err(errors::ConcatIdentsIdentArgs { span: sp }); + return DummyResult::any(sp, guar); } } diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 0bd2d423a294..386d4a54b655 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -6,7 +6,7 @@ use rustc_ast::{attr, walk_list, EnumDef, VariantData}; use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt}; use rustc_span::symbol::Ident; use rustc_span::symbol::{kw, sym}; -use rustc_span::Span; +use rustc_span::{ErrorGuaranteed, Span}; use smallvec::SmallVec; use thin_vec::{thin_vec, ThinVec}; @@ -83,16 +83,19 @@ fn default_enum_substructure( trait_span: Span, enum_def: &EnumDef, ) -> BlockOrExpr { - let expr = if let Ok(default_variant) = extract_default_variant(cx, enum_def, trait_span) - && let Ok(_) = validate_default_attribute(cx, default_variant) - { - // We now know there is exactly one unit variant with exactly one `#[default]` attribute. - cx.expr_path(cx.path( - default_variant.span, - vec![Ident::new(kw::SelfUpper, default_variant.span), default_variant.ident], - )) - } else { - DummyResult::raw_expr(trait_span, true) + let expr = match try { + let default_variant = extract_default_variant(cx, enum_def, trait_span)?; + validate_default_attribute(cx, default_variant)?; + default_variant + } { + Ok(default_variant) => { + // We now know there is exactly one unit variant with exactly one `#[default]` attribute. + cx.expr_path(cx.path( + default_variant.span, + vec![Ident::new(kw::SelfUpper, default_variant.span), default_variant.ident], + )) + } + Err(guar) => DummyResult::raw_expr(trait_span, Some(guar)), }; BlockOrExpr::new_expr(expr) } @@ -101,7 +104,7 @@ fn extract_default_variant<'a>( cx: &mut ExtCtxt<'_>, enum_def: &'a EnumDef, trait_span: Span, -) -> Result<&'a rustc_ast::Variant, ()> { +) -> Result<&'a rustc_ast::Variant, ErrorGuaranteed> { let default_variants: SmallVec<[_; 1]> = enum_def .variants .iter() @@ -120,9 +123,9 @@ fn extract_default_variant<'a>( let suggs = possible_defaults .map(|v| errors::NoDefaultVariantSugg { span: v.span, ident: v.ident }) .collect(); - cx.dcx().emit_err(errors::NoDefaultVariant { span: trait_span, suggs }); + let guar = cx.dcx().emit_err(errors::NoDefaultVariant { span: trait_span, suggs }); - return Err(()); + return Err(guar); } [first, rest @ ..] => { let suggs = default_variants @@ -140,28 +143,28 @@ fn extract_default_variant<'a>( .then_some(errors::MultipleDefaultsSugg { spans, ident: variant.ident }) }) .collect(); - cx.dcx().emit_err(errors::MultipleDefaults { + let guar = cx.dcx().emit_err(errors::MultipleDefaults { span: trait_span, first: first.span, additional: rest.iter().map(|v| v.span).collect(), suggs, }); - return Err(()); + return Err(guar); } }; if !matches!(variant.data, VariantData::Unit(..)) { - cx.dcx().emit_err(errors::NonUnitDefault { span: variant.ident.span }); - return Err(()); + let guar = cx.dcx().emit_err(errors::NonUnitDefault { span: variant.ident.span }); + return Err(guar); } if let Some(non_exhaustive_attr) = attr::find_by_name(&variant.attrs, sym::non_exhaustive) { - cx.dcx().emit_err(errors::NonExhaustiveDefault { + let guar = cx.dcx().emit_err(errors::NonExhaustiveDefault { span: variant.ident.span, non_exhaustive: non_exhaustive_attr.span, }); - return Err(()); + return Err(guar); } Ok(variant) @@ -170,7 +173,7 @@ fn extract_default_variant<'a>( fn validate_default_attribute( cx: &mut ExtCtxt<'_>, default_variant: &rustc_ast::Variant, -) -> Result<(), ()> { +) -> Result<(), ErrorGuaranteed> { let attrs: SmallVec<[_; 1]> = attr::filter_by_name(&default_variant.attrs, kw::Default).collect(); @@ -183,7 +186,7 @@ fn validate_default_attribute( let sugg = errors::MultipleDefaultAttrsSugg { spans: rest.iter().map(|attr| attr.span).collect(), }; - cx.dcx().emit_err(errors::MultipleDefaultAttrs { + let guar = cx.dcx().emit_err(errors::MultipleDefaultAttrs { span: default_variant.ident.span, first: first.span, first_rest: rest[0].span, @@ -192,13 +195,13 @@ fn validate_default_attribute( sugg, }); - return Err(()); + return Err(guar); } }; if !attr.is_word() { - cx.dcx().emit_err(errors::DefaultHasArg { span: attr.span }); + let guar = cx.dcx().emit_err(errors::DefaultHasArg { span: attr.span }); - return Err(()); + return Err(guar); } Ok(()) } diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index a0fd0e3f9be0..67ace546ad04 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -28,8 +28,9 @@ pub fn expand_option_env<'cx>( sp: Span, tts: TokenStream, ) -> Box { - let Some(var) = get_single_str_from_tts(cx, sp, tts, "option_env!") else { - return DummyResult::any(sp); + let var = match get_single_str_from_tts(cx, sp, tts, "option_env!") { + Ok(var) => var, + Err(guar) => return DummyResult::any(sp, guar), }; let sp = cx.with_def_site_ctxt(sp); @@ -65,24 +66,25 @@ pub fn expand_env<'cx>( tts: TokenStream, ) -> Box { let mut exprs = match get_exprs_from_tts(cx, tts) { - Some(exprs) if exprs.is_empty() || exprs.len() > 2 => { - cx.dcx().emit_err(errors::EnvTakesArgs { span: sp }); - return DummyResult::any(sp); + Ok(exprs) if exprs.is_empty() || exprs.len() > 2 => { + let guar = cx.dcx().emit_err(errors::EnvTakesArgs { span: sp }); + return DummyResult::any(sp, guar); } - None => return DummyResult::any(sp), - Some(exprs) => exprs.into_iter(), + Err(guar) => return DummyResult::any(sp, guar), + Ok(exprs) => exprs.into_iter(), }; let var_expr = exprs.next().unwrap(); - let Some((var, _)) = expr_to_string(cx, var_expr.clone(), "expected string literal") else { - return DummyResult::any(sp); + let var = match expr_to_string(cx, var_expr.clone(), "expected string literal") { + Ok((var, _)) => var, + Err(guar) => return DummyResult::any(sp, guar), }; let custom_msg = match exprs.next() { None => None, Some(second) => match expr_to_string(cx, second, "expected string literal") { - None => return DummyResult::any(sp), - Some((s, _)) => Some(s), + Ok((s, _)) => Some(s), + Err(guar) => return DummyResult::any(sp, guar), }, }; @@ -100,23 +102,23 @@ pub fn expand_env<'cx>( unreachable!("`expr_to_string` ensures this is a string lit") }; - if let Some(msg_from_user) = custom_msg { - cx.dcx().emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user }); + let guar = if let Some(msg_from_user) = custom_msg { + cx.dcx().emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user }) } else if is_cargo_env_var(var.as_str()) { cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVar { span, var: *symbol, var_expr: var_expr.ast_deref(), - }); + }) } else { cx.dcx().emit_err(errors::EnvNotDefined::CustomEnvVar { span, var: *symbol, var_expr: var_expr.ast_deref(), - }); - } + }) + }; - return DummyResult::any(sp); + return DummyResult::any(sp, guar); } Some(value) => cx.expr_str(span, value), }; diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 3366378d38da..06c2b6177068 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -13,7 +13,7 @@ use rustc_expand::base::{self, *}; use rustc_parse::parser::Recovered; use rustc_parse_format as parse; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::{BytePos, InnerSpan, Span}; +use rustc_span::{BytePos, ErrorGuaranteed, InnerSpan, Span}; use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY; use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId}; @@ -160,7 +160,7 @@ fn make_format_args( ecx: &mut ExtCtxt<'_>, input: MacroInput, append_newline: bool, -) -> Result { +) -> Result { let msg = "format argument must be a string literal"; let unexpanded_fmt_span = input.fmtstr.span; @@ -173,38 +173,41 @@ fn make_format_args( } Ok(fmt) => fmt, Err(err) => { - if let Some((mut err, suggested)) = err { - if !suggested { - if let ExprKind::Block(block, None) = &efmt.kind - && block.stmts.len() == 1 - && let StmtKind::Expr(expr) = &block.stmts[0].kind - && let ExprKind::Path(None, path) = &expr.kind - && path.is_potential_trivial_const_arg() - { - err.multipart_suggestion( - "quote your inlined format argument to use as string literal", - vec![ - (unexpanded_fmt_span.shrink_to_hi(), "\"".to_string()), - (unexpanded_fmt_span.shrink_to_lo(), "\"".to_string()), - ], - Applicability::MaybeIncorrect, - ); - } else { - let sugg_fmt = match args.explicit_args().len() { - 0 => "{}".to_string(), - _ => format!("{}{{}}", "{} ".repeat(args.explicit_args().len())), - }; - err.span_suggestion( - unexpanded_fmt_span.shrink_to_lo(), - "you might be missing a string literal to format with", - format!("\"{sugg_fmt}\", "), - Applicability::MaybeIncorrect, - ); + let guar = match err { + Ok((mut err, suggested)) => { + if !suggested { + if let ExprKind::Block(block, None) = &efmt.kind + && block.stmts.len() == 1 + && let StmtKind::Expr(expr) = &block.stmts[0].kind + && let ExprKind::Path(None, path) = &expr.kind + && path.is_potential_trivial_const_arg() + { + err.multipart_suggestion( + "quote your inlined format argument to use as string literal", + vec![ + (unexpanded_fmt_span.shrink_to_hi(), "\"".to_string()), + (unexpanded_fmt_span.shrink_to_lo(), "\"".to_string()), + ], + Applicability::MaybeIncorrect, + ); + } else { + let sugg_fmt = match args.explicit_args().len() { + 0 => "{}".to_string(), + _ => format!("{}{{}}", "{} ".repeat(args.explicit_args().len())), + }; + err.span_suggestion( + unexpanded_fmt_span.shrink_to_lo(), + "you might be missing a string literal to format with", + format!("\"{sugg_fmt}\", "), + Applicability::MaybeIncorrect, + ); + } } + err.emit() } - err.emit(); - } - return Err(()); + Err(guar) => guar, + }; + return Err(guar); } }; @@ -293,8 +296,8 @@ fn make_format_args( } } } - ecx.dcx().emit_err(e); - return Err(()); + let guar = ecx.dcx().emit_err(e); + return Err(guar); } let to_span = |inner_span: rustc_parse_format::InnerSpan| { @@ -353,9 +356,9 @@ fn make_format_args( } else { // For the moment capturing variables from format strings expanded from macros is // disabled (see RFC #2795) - ecx.dcx().emit_err(errors::FormatNoArgNamed { span, name }); + let guar = ecx.dcx().emit_err(errors::FormatNoArgNamed { span, name }); unnamed_arg_after_named_arg = true; - DummyResult::raw_expr(span, true) + DummyResult::raw_expr(span, Some(guar)) }; Ok(args.add(FormatArgument { kind: FormatArgumentKind::Captured(ident), expr })) } @@ -972,16 +975,13 @@ fn expand_format_args_impl<'cx>( ) -> Box { sp = ecx.with_def_site_ctxt(sp); match parse_args(ecx, sp, tts) { - Ok(input) => { - if let Ok(format_args) = make_format_args(ecx, input, nl) { - MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args)))) - } else { - MacEager::expr(DummyResult::raw_expr(sp, true)) - } - } + Ok(input) => match make_format_args(ecx, input, nl) { + Ok(format_args) => MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args)))), + Err(guar) => MacEager::expr(DummyResult::raw_expr(sp, Some(guar))), + }, Err(err) => { - err.emit(); - DummyResult::any(sp) + let guar = err.emit(); + DummyResult::any(sp, guar) } } } diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index d30ccab23943..f344dbcd10c0 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -15,6 +15,7 @@ #![feature(lint_reasons)] #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] +#![feature(try_blocks)] extern crate proc_macro; diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 43d13569d1ee..3860057e1d41 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -103,15 +103,16 @@ pub fn expand_include<'cx>( tts: TokenStream, ) -> Box { let sp = cx.with_def_site_ctxt(sp); - let Some(file) = get_single_str_from_tts(cx, sp, tts, "include!") else { - return DummyResult::any(sp); + let file = match get_single_str_from_tts(cx, sp, tts, "include!") { + Ok(file) => file, + Err(guar) => return DummyResult::any(sp, guar), }; // The file will be added to the code map by the parser let file = match resolve_path(&cx.sess, file.as_str(), sp) { Ok(f) => f, Err(err) => { - err.emit(); - return DummyResult::any(sp); + let guar = err.emit(); + return DummyResult::any(sp, guar); } }; let p = new_parser_from_file(cx.parse_sess(), &file, Some(sp)); @@ -130,7 +131,7 @@ pub fn expand_include<'cx>( } impl<'a> base::MacResult for ExpandResult<'a> { fn make_expr(mut self: Box>) -> Option> { - let r = base::parse_expr(&mut self.p)?; + let expr = base::parse_expr(&mut self.p).ok()?; if self.p.token != token::Eof { self.p.sess.buffer_lint( INCOMPLETE_INCLUDE, @@ -139,7 +140,7 @@ pub fn expand_include<'cx>( "include macro expected single expression in source", ); } - Some(r) + Some(expr) } fn make_items(mut self: Box>) -> Option; 1]>> { @@ -176,14 +177,15 @@ pub fn expand_include_str( tts: TokenStream, ) -> Box { let sp = cx.with_def_site_ctxt(sp); - let Some(file) = get_single_str_from_tts(cx, sp, tts, "include_str!") else { - return DummyResult::any(sp); + let file = match get_single_str_from_tts(cx, sp, tts, "include_str!") { + Ok(file) => file, + Err(guar) => return DummyResult::any(sp, guar), }; let file = match resolve_path(&cx.sess, file.as_str(), sp) { Ok(f) => f, Err(err) => { - err.emit(); - return DummyResult::any(sp); + let guar = err.emit(); + return DummyResult::any(sp, guar); } }; match cx.source_map().load_binary_file(&file) { @@ -193,13 +195,13 @@ pub fn expand_include_str( base::MacEager::expr(cx.expr_str(sp, interned_src)) } Err(_) => { - cx.dcx().span_err(sp, format!("{} wasn't a utf-8 file", file.display())); - DummyResult::any(sp) + let guar = cx.dcx().span_err(sp, format!("{} wasn't a utf-8 file", file.display())); + DummyResult::any(sp, guar) } }, Err(e) => { - cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e)); - DummyResult::any(sp) + let guar = cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e)); + DummyResult::any(sp, guar) } } } @@ -210,14 +212,15 @@ pub fn expand_include_bytes( tts: TokenStream, ) -> Box { let sp = cx.with_def_site_ctxt(sp); - let Some(file) = get_single_str_from_tts(cx, sp, tts, "include_bytes!") else { - return DummyResult::any(sp); + let file = match get_single_str_from_tts(cx, sp, tts, "include_bytes!") { + Ok(file) => file, + Err(guar) => return DummyResult::any(sp, guar), }; let file = match resolve_path(&cx.sess, file.as_str(), sp) { Ok(f) => f, Err(err) => { - err.emit(); - return DummyResult::any(sp); + let guar = err.emit(); + return DummyResult::any(sp, guar); } }; match cx.source_map().load_binary_file(&file) { @@ -226,8 +229,8 @@ pub fn expand_include_bytes( base::MacEager::expr(expr) } Err(e) => { - cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e)); - DummyResult::any(sp) + let guar = cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e)); + DummyResult::any(sp, guar) } } } diff --git a/compiler/rustc_builtin_macros/src/type_ascribe.rs b/compiler/rustc_builtin_macros/src/type_ascribe.rs index 564797012ae2..e8b8fe75338c 100644 --- a/compiler/rustc_builtin_macros/src/type_ascribe.rs +++ b/compiler/rustc_builtin_macros/src/type_ascribe.rs @@ -13,8 +13,8 @@ pub fn expand_type_ascribe( let (expr, ty) = match parse_ascribe(cx, tts) { Ok(parsed) => parsed, Err(err) => { - err.emit(); - return DummyResult::any(span); + let guar = err.emit(); + return DummyResult::any(span, guar); } }; diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 762d6745341a..7ece46523dbf 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -532,7 +532,7 @@ impl MacResult for MacEager { /// after hitting errors. #[derive(Copy, Clone)] pub struct DummyResult { - is_error: bool, + guar: Option, span: Span, } @@ -541,20 +541,24 @@ impl DummyResult { /// /// Use this as a return value after hitting any errors and /// calling `span_err`. - pub fn any(span: Span) -> Box { - Box::new(DummyResult { is_error: true, span }) + pub fn any(span: Span, guar: ErrorGuaranteed) -> Box { + Box::new(DummyResult { guar: Some(guar), span }) } /// Same as `any`, but must be a valid fragment, not error. pub fn any_valid(span: Span) -> Box { - Box::new(DummyResult { is_error: false, span }) + Box::new(DummyResult { guar: None, span }) } /// A plain dummy expression. - pub fn raw_expr(sp: Span, is_error: bool) -> P { + pub fn raw_expr(sp: Span, guar: Option) -> P { P(ast::Expr { id: ast::DUMMY_NODE_ID, - kind: if is_error { ast::ExprKind::Err } else { ast::ExprKind::Tup(ThinVec::new()) }, + kind: if let Some(guar) = guar { + ast::ExprKind::Err(guar) + } else { + ast::ExprKind::Tup(ThinVec::new()) + }, span: sp, attrs: ast::AttrVec::new(), tokens: None, @@ -582,7 +586,7 @@ impl DummyResult { impl MacResult for DummyResult { fn make_expr(self: Box) -> Option> { - Some(DummyResult::raw_expr(self.span, self.is_error)) + Some(DummyResult::raw_expr(self.span, self.guar)) } fn make_pat(self: Box) -> Option> { @@ -608,7 +612,7 @@ impl MacResult for DummyResult { fn make_stmts(self: Box) -> Option> { Some(smallvec![ast::Stmt { id: ast::DUMMY_NODE_ID, - kind: ast::StmtKind::Expr(DummyResult::raw_expr(self.span, self.is_error)), + kind: ast::StmtKind::Expr(DummyResult::raw_expr(self.span, self.guar)), span: self.span, }]) } @@ -884,17 +888,19 @@ impl SyntaxExtension { } } + /// A dummy bang macro `foo!()`. pub fn dummy_bang(edition: Edition) -> SyntaxExtension { fn expander<'cx>( - _: &'cx mut ExtCtxt<'_>, + cx: &'cx mut ExtCtxt<'_>, span: Span, _: TokenStream, ) -> Box { - DummyResult::any(span) + DummyResult::any(span, cx.dcx().span_delayed_bug(span, "expanded a dummy bang macro")) } SyntaxExtension::default(SyntaxExtensionKind::LegacyBang(Box::new(expander)), edition) } + /// A dummy derive macro `#[derive(Foo)]`. pub fn dummy_derive(edition: Edition) -> SyntaxExtension { fn expander( _: &mut ExtCtxt<'_>, @@ -1066,7 +1072,7 @@ pub struct ExtCtxt<'a> { pub sess: &'a Session, pub ecfg: expand::ExpansionConfig<'a>, pub num_standard_library_imports: usize, - pub reduced_recursion_limit: Option, + pub reduced_recursion_limit: Option<(Limit, ErrorGuaranteed)>, pub root_path: PathBuf, pub resolver: &'a mut dyn ResolverExpand, pub current_expansion: ExpansionData, @@ -1244,7 +1250,7 @@ pub fn resolve_path( /// Extracts a string literal from the macro expanded version of `expr`, /// returning a diagnostic error of `err_msg` if `expr` is not a string literal. /// The returned bool indicates whether an applicable suggestion has already been -/// added to the diagnostic to avoid emitting multiple suggestions. `Err(None)` +/// added to the diagnostic to avoid emitting multiple suggestions. `Err(Err(ErrorGuaranteed))` /// indicates that an ast error was encountered. // FIXME(Nilstrieb) Make this function setup translatable #[allow(rustc::untranslatable_diagnostic)] @@ -1252,7 +1258,10 @@ pub fn expr_to_spanned_string<'a>( cx: &'a mut ExtCtxt<'_>, expr: P, err_msg: &'static str, -) -> Result<(Symbol, ast::StrStyle, Span), Option<(DiagnosticBuilder<'a>, bool)>> { +) -> Result< + (Symbol, ast::StrStyle, Span), + Result<(DiagnosticBuilder<'a>, bool /* has_suggestions */), ErrorGuaranteed>, +> { // Perform eager expansion on the expression. // We want to be able to handle e.g., `concat!("foo", "bar")`. let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); @@ -1269,38 +1278,33 @@ pub fn expr_to_spanned_string<'a>( "", Applicability::MaybeIncorrect, ); - Some((err, true)) + Ok((err, true)) } - Ok(ast::LitKind::Err(_)) => None, - Err(err) => { - report_lit_error(&cx.sess.parse_sess, err, token_lit, expr.span); - None - } - _ => Some((cx.dcx().struct_span_err(expr.span, err_msg), false)), + Ok(ast::LitKind::Err(guar)) => Err(guar), + Err(err) => Err(report_lit_error(&cx.sess.parse_sess, err, token_lit, expr.span)), + _ => Ok((cx.dcx().struct_span_err(expr.span, err_msg), false)), }, - ast::ExprKind::Err => None, + ast::ExprKind::Err(guar) => Err(guar), ast::ExprKind::Dummy => { cx.dcx().span_bug(expr.span, "tried to get a string literal from `ExprKind::Dummy`") } - _ => Some((cx.dcx().struct_span_err(expr.span, err_msg), false)), + _ => Ok((cx.dcx().struct_span_err(expr.span, err_msg), false)), }) } /// Extracts a string literal from the macro expanded version of `expr`, /// emitting `err_msg` if `expr` is not a string literal. This does not stop -/// compilation on error, merely emits a non-fatal error and returns `None`. +/// compilation on error, merely emits a non-fatal error and returns `Err`. pub fn expr_to_string( cx: &mut ExtCtxt<'_>, expr: P, err_msg: &'static str, -) -> Option<(Symbol, ast::StrStyle)> { +) -> Result<(Symbol, ast::StrStyle), ErrorGuaranteed> { expr_to_spanned_string(cx, expr, err_msg) - .map_err(|err| { - err.map(|(err, _)| { - err.emit(); - }) + .map_err(|err| match err { + Ok((err, _)) => err.emit(), + Err(guar) => guar, }) - .ok() .map(|(symbol, style, _)| (symbol, style)) } @@ -1314,32 +1318,30 @@ pub fn check_zero_tts(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream, name: &str } } -/// Parse an expression. On error, emit it, advancing to `Eof`, and return `None`. -pub fn parse_expr(p: &mut parser::Parser<'_>) -> Option> { - match p.parse_expr() { - Ok(e) => return Some(e), - Err(err) => { - err.emit(); - } - } +/// Parse an expression. On error, emit it, advancing to `Eof`, and return `Err`. +pub fn parse_expr(p: &mut parser::Parser<'_>) -> Result, ErrorGuaranteed> { + let guar = match p.parse_expr() { + Ok(expr) => return Ok(expr), + Err(err) => err.emit(), + }; while p.token != token::Eof { p.bump(); } - None + Err(guar) } /// Interpreting `tts` as a comma-separated sequence of expressions, -/// expect exactly one string literal, or emit an error and return `None`. +/// expect exactly one string literal, or emit an error and return `Err`. pub fn get_single_str_from_tts( cx: &mut ExtCtxt<'_>, span: Span, tts: TokenStream, name: &str, -) -> Option { +) -> Result { let mut p = cx.new_parser_from_tts(tts); if p.token == token::Eof { - cx.dcx().emit_err(errors::OnlyOneArgument { span, name }); - return None; + let guar = cx.dcx().emit_err(errors::OnlyOneArgument { span, name }); + return Err(guar); } let ret = parse_expr(&mut p)?; let _ = p.eat(&token::Comma); @@ -1351,8 +1353,11 @@ pub fn get_single_str_from_tts( } /// Extracts comma-separated expressions from `tts`. -/// On error, emit it, and return `None`. -pub fn get_exprs_from_tts(cx: &mut ExtCtxt<'_>, tts: TokenStream) -> Option>> { +/// On error, emit it, and return `Err`. +pub fn get_exprs_from_tts( + cx: &mut ExtCtxt<'_>, + tts: TokenStream, +) -> Result>, ErrorGuaranteed> { let mut p = cx.new_parser_from_tts(tts); let mut es = Vec::new(); while p.token != token::Eof { @@ -1367,11 +1372,11 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt<'_>, tts: TokenStream) -> Option AstFragment { - self.make_from(DummyResult::any(span)).expect("couldn't create a dummy AST fragment") + pub(crate) fn dummy(self, span: Span, guar: ErrorGuaranteed) -> AstFragment { + self.make_from(DummyResult::any(span, guar)).expect("couldn't create a dummy AST fragment") } pub fn supports_macro_expansion(self) -> SupportsMacroExpansion { @@ -604,14 +604,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { (fragment, invocations) } - fn error_recursion_limit_reached(&mut self) { + fn error_recursion_limit_reached(&mut self) -> ErrorGuaranteed { let expn_data = self.cx.current_expansion.id.expn_data(); let suggested_limit = match self.cx.ecfg.recursion_limit { Limit(0) => Limit(2), limit => limit * 2, }; - self.cx.dcx().emit_err(RecursionLimitReached { + let guar = self.cx.dcx().emit_err(RecursionLimitReached { span: expn_data.call_site, descr: expn_data.kind.descr(), suggested_limit, @@ -619,14 +619,21 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }); self.cx.trace_macros_diag(); + guar } /// A macro's expansion does not fit in this fragment kind. /// For example, a non-type macro in a type position. - fn error_wrong_fragment_kind(&mut self, kind: AstFragmentKind, mac: &ast::MacCall, span: Span) { - self.cx.dcx().emit_err(WrongFragmentKind { span, kind: kind.name(), name: &mac.path }); - + fn error_wrong_fragment_kind( + &mut self, + kind: AstFragmentKind, + mac: &ast::MacCall, + span: Span, + ) -> ErrorGuaranteed { + let guar = + self.cx.dcx().emit_err(WrongFragmentKind { span, kind: kind.name(), name: &mac.path }); self.cx.trace_macros_diag(); + guar } fn expand_invoc( @@ -634,36 +641,41 @@ impl<'a, 'b> MacroExpander<'a, 'b> { invoc: Invocation, ext: &SyntaxExtensionKind, ) -> ExpandResult { - let recursion_limit = - self.cx.reduced_recursion_limit.unwrap_or(self.cx.ecfg.recursion_limit); + let recursion_limit = match self.cx.reduced_recursion_limit { + Some((limit, _)) => limit, + None => self.cx.ecfg.recursion_limit, + }; + if !recursion_limit.value_within_limit(self.cx.current_expansion.depth) { - if self.cx.reduced_recursion_limit.is_none() { - self.error_recursion_limit_reached(); - } + let guar = match self.cx.reduced_recursion_limit { + Some((_, guar)) => guar, + None => self.error_recursion_limit_reached(), + }; // Reduce the recursion limit by half each time it triggers. - self.cx.reduced_recursion_limit = Some(recursion_limit / 2); + self.cx.reduced_recursion_limit = Some((recursion_limit / 2, guar)); - return ExpandResult::Ready(invoc.fragment_kind.dummy(invoc.span())); + return ExpandResult::Ready(invoc.fragment_kind.dummy(invoc.span(), guar)); } let (fragment_kind, span) = (invoc.fragment_kind, invoc.span()); ExpandResult::Ready(match invoc.kind { InvocationKind::Bang { mac, .. } => match ext { SyntaxExtensionKind::Bang(expander) => { - let Ok(tok_result) = expander.expand(self.cx, span, mac.args.tokens.clone()) - else { - return ExpandResult::Ready(fragment_kind.dummy(span)); - }; - self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span) + match expander.expand(self.cx, span, mac.args.tokens.clone()) { + Ok(tok_result) => { + self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span) + } + Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)), + } } SyntaxExtensionKind::LegacyBang(expander) => { let tok_result = expander.expand(self.cx, span, mac.args.tokens.clone()); let result = if let Some(result) = fragment_kind.make_from(tok_result) { result } else { - self.error_wrong_fragment_kind(fragment_kind, &mac, span); - fragment_kind.dummy(span) + let guar = self.error_wrong_fragment_kind(fragment_kind, &mac, span); + fragment_kind.dummy(span, guar) }; result } @@ -705,11 +717,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.dcx().emit_err(UnsupportedKeyValue { span }); } let inner_tokens = attr_item.args.inner_tokens(); - let Ok(tok_result) = expander.expand(self.cx, span, inner_tokens, tokens) - else { - return ExpandResult::Ready(fragment_kind.dummy(span)); - }; - self.parse_ast_fragment(tok_result, fragment_kind, &attr_item.path, span) + match expander.expand(self.cx, span, inner_tokens, tokens) { + Ok(tok_result) => self.parse_ast_fragment( + tok_result, + fragment_kind, + &attr_item.path, + span, + ), + Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)), + } } SyntaxExtensionKind::LegacyAttr(expander) => { match validate_attr::parse_meta(&self.cx.sess.parse_sess, &attr) { @@ -729,15 +745,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> { AstFragmentKind::Expr | AstFragmentKind::MethodReceiverExpr ) && items.is_empty() { - self.cx.dcx().emit_err(RemoveExprNotSupported { span }); - fragment_kind.dummy(span) + let guar = self.cx.dcx().emit_err(RemoveExprNotSupported { span }); + fragment_kind.dummy(span, guar) } else { fragment_kind.expect_from_annotatables(items) } } Err(err) => { - err.emit(); - fragment_kind.dummy(span) + let guar = err.emit(); + fragment_kind.dummy(span, guar) } } } @@ -857,9 +873,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { err.span(span); } annotate_err_with_kind(&mut err, kind, span); - err.emit(); + let guar = err.emit(); self.cx.trace_macros_diag(); - kind.dummy(span) + kind.dummy(span, guar) } } } diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 25af974d3266..5629c5ef5fa0 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -11,7 +11,7 @@ use rustc_errors::{Applicability, DiagCtxt, DiagnosticBuilder, DiagnosticMessage use rustc_parse::parser::{Parser, Recovery}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::Ident; -use rustc_span::Span; +use rustc_span::{ErrorGuaranteed, Span}; use std::borrow::Cow; use super::macro_rules::{parser_from_cx, NoopTracker}; @@ -47,7 +47,7 @@ pub(super) fn failed_to_match_macro<'cx>( let Some(BestFailure { token, msg: label, remaining_matcher, .. }) = tracker.best_failure else { - return DummyResult::any(sp); + return DummyResult::any(sp, cx.dcx().span_delayed_bug(sp, "failed to match a macro")); }; let span = token.span.substitute_dummy(sp); @@ -106,9 +106,9 @@ pub(super) fn failed_to_match_macro<'cx>( } } } - err.emit(); + let guar = err.emit(); cx.trace_macros_diag(); - DummyResult::any(sp) + DummyResult::any(sp, guar) } /// The tracker used for the slow error path that collects useful info for diagnostics. @@ -180,10 +180,10 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx, } Error(err_sp, msg) => { let span = err_sp.substitute_dummy(self.root_span); - self.cx.dcx().span_err(span, msg.clone()); - self.result = Some(DummyResult::any(span)); + let guar = self.cx.dcx().span_err(span, msg.clone()); + self.result = Some(DummyResult::any(span, guar)); } - ErrorReported(_) => self.result = Some(DummyResult::any(self.root_span)), + ErrorReported(guar) => self.result = Some(DummyResult::any(self.root_span, *guar)), } } @@ -224,7 +224,7 @@ pub(super) fn emit_frag_parse_err( site_span: Span, arm_span: Span, kind: AstFragmentKind, -) { +) -> ErrorGuaranteed { // FIXME(davidtwco): avoid depending on the error message text if parser.token == token::Eof && let DiagnosticMessage::Str(message) = &e.messages[0].0 @@ -282,7 +282,7 @@ pub(super) fn emit_frag_parse_err( }, _ => annotate_err_with_kind(&mut e, kind, site_span), }; - e.emit(); + e.emit() } pub(crate) fn annotate_err_with_kind( diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index ffc8f782fd34..8174cb03d337 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -114,7 +114,7 @@ use rustc_errors::{DiagnosticMessage, MultiSpan}; use rustc_session::lint::builtin::{META_VARIABLE_MISUSE, MISSING_FRAGMENT_SPECIFIER}; use rustc_session::parse::ParseSess; use rustc_span::symbol::kw; -use rustc_span::{symbol::MacroRulesNormalizedIdent, Span}; +use rustc_span::{symbol::MacroRulesNormalizedIdent, ErrorGuaranteed, Span}; use smallvec::SmallVec; @@ -203,17 +203,17 @@ pub(super) fn check_meta_variables( span: Span, lhses: &[TokenTree], rhses: &[TokenTree], -) -> bool { +) -> Result<(), ErrorGuaranteed> { if lhses.len() != rhses.len() { sess.dcx.span_bug(span, "length mismatch between LHSes and RHSes") } - let mut valid = true; + let mut guar = None; for (lhs, rhs) in iter::zip(lhses, rhses) { let mut binders = Binders::default(); - check_binders(sess, node_id, lhs, &Stack::Empty, &mut binders, &Stack::Empty, &mut valid); - check_occurrences(sess, node_id, rhs, &Stack::Empty, &binders, &Stack::Empty, &mut valid); + check_binders(sess, node_id, lhs, &Stack::Empty, &mut binders, &Stack::Empty, &mut guar); + check_occurrences(sess, node_id, rhs, &Stack::Empty, &binders, &Stack::Empty, &mut guar); } - valid + guar.map_or(Ok(()), Err) } /// Checks `lhs` as part of the LHS of a macro definition, extends `binders` with new binders, and @@ -226,7 +226,7 @@ pub(super) fn check_meta_variables( /// - `macros` is the stack of possible outer macros /// - `binders` contains the binders of the LHS /// - `ops` is the stack of Kleene operators from the LHS -/// - `valid` is set in case of errors +/// - `guar` is set in case of errors fn check_binders( sess: &ParseSess, node_id: NodeId, @@ -234,7 +234,7 @@ fn check_binders( macros: &Stack<'_, MacroState<'_>>, binders: &mut Binders, ops: &Stack<'_, KleeneToken>, - valid: &mut bool, + guar: &mut Option, ) { match *lhs { TokenTree::Token(..) => {} @@ -258,7 +258,7 @@ fn check_binders( binders.insert(name, BinderInfo { span, ops: ops.into() }); } else { // 3. The meta-variable is bound: This is an occurrence. - check_occurrences(sess, node_id, lhs, macros, binders, ops, valid); + check_occurrences(sess, node_id, lhs, macros, binders, ops, guar); } } // Similarly, this can only happen when checking a toplevel macro. @@ -281,8 +281,10 @@ fn check_binders( if let Some(prev_info) = get_binder_info(macros, binders, name) { // Duplicate binders at the top-level macro definition are errors. The lint is only // for nested macro definitions. - sess.dcx.emit_err(errors::DuplicateMatcherBinding { span, prev: prev_info.span }); - *valid = false; + *guar = Some( + sess.dcx + .emit_err(errors::DuplicateMatcherBinding { span, prev: prev_info.span }), + ); } else { binders.insert(name, BinderInfo { span, ops: ops.into() }); } @@ -291,13 +293,13 @@ fn check_binders( TokenTree::MetaVarExpr(..) => {} TokenTree::Delimited(.., ref del) => { for tt in &del.tts { - check_binders(sess, node_id, tt, macros, binders, ops, valid); + check_binders(sess, node_id, tt, macros, binders, ops, guar); } } TokenTree::Sequence(_, ref seq) => { let ops = ops.push(seq.kleene); for tt in &seq.tts { - check_binders(sess, node_id, tt, macros, binders, &ops, valid); + check_binders(sess, node_id, tt, macros, binders, &ops, guar); } } } @@ -327,7 +329,7 @@ fn get_binder_info<'a>( /// - `macros` is the stack of possible outer macros /// - `binders` contains the binders of the associated LHS /// - `ops` is the stack of Kleene operators from the RHS -/// - `valid` is set in case of errors +/// - `guar` is set in case of errors fn check_occurrences( sess: &ParseSess, node_id: NodeId, @@ -335,7 +337,7 @@ fn check_occurrences( macros: &Stack<'_, MacroState<'_>>, binders: &Binders, ops: &Stack<'_, KleeneToken>, - valid: &mut bool, + guar: &mut Option, ) { match *rhs { TokenTree::Token(..) => {} @@ -353,11 +355,11 @@ fn check_occurrences( check_ops_is_prefix(sess, node_id, macros, binders, ops, dl.entire(), name); } TokenTree::Delimited(.., ref del) => { - check_nested_occurrences(sess, node_id, &del.tts, macros, binders, ops, valid); + check_nested_occurrences(sess, node_id, &del.tts, macros, binders, ops, guar); } TokenTree::Sequence(_, ref seq) => { let ops = ops.push(seq.kleene); - check_nested_occurrences(sess, node_id, &seq.tts, macros, binders, &ops, valid); + check_nested_occurrences(sess, node_id, &seq.tts, macros, binders, &ops, guar); } } } @@ -392,7 +394,7 @@ enum NestedMacroState { /// - `macros` is the stack of possible outer macros /// - `binders` contains the binders of the associated LHS /// - `ops` is the stack of Kleene operators from the RHS -/// - `valid` is set in case of errors +/// - `guar` is set in case of errors fn check_nested_occurrences( sess: &ParseSess, node_id: NodeId, @@ -400,7 +402,7 @@ fn check_nested_occurrences( macros: &Stack<'_, MacroState<'_>>, binders: &Binders, ops: &Stack<'_, KleeneToken>, - valid: &mut bool, + guar: &mut Option, ) { let mut state = NestedMacroState::Empty; let nested_macros = macros.push(MacroState { binders, ops: ops.into() }); @@ -432,7 +434,7 @@ fn check_nested_occurrences( (NestedMacroState::MacroRulesNot, &TokenTree::MetaVar(..)) => { state = NestedMacroState::MacroRulesNotName; // We check that the meta-variable is correctly used. - check_occurrences(sess, node_id, tt, macros, binders, ops, valid); + check_occurrences(sess, node_id, tt, macros, binders, ops, guar); } (NestedMacroState::MacroRulesNotName, TokenTree::Delimited(.., del)) | (NestedMacroState::MacroName, TokenTree::Delimited(.., del)) @@ -441,7 +443,7 @@ fn check_nested_occurrences( let macro_rules = state == NestedMacroState::MacroRulesNotName; state = NestedMacroState::Empty; let rest = - check_nested_macro(sess, node_id, macro_rules, &del.tts, &nested_macros, valid); + check_nested_macro(sess, node_id, macro_rules, &del.tts, &nested_macros, guar); // If we did not check the whole macro definition, then check the rest as if outside // the macro definition. check_nested_occurrences( @@ -451,7 +453,7 @@ fn check_nested_occurrences( macros, binders, ops, - valid, + guar, ); } ( @@ -463,7 +465,7 @@ fn check_nested_occurrences( (NestedMacroState::Macro, &TokenTree::MetaVar(..)) => { state = NestedMacroState::MacroName; // We check that the meta-variable is correctly used. - check_occurrences(sess, node_id, tt, macros, binders, ops, valid); + check_occurrences(sess, node_id, tt, macros, binders, ops, guar); } (NestedMacroState::MacroName, TokenTree::Delimited(.., del)) if del.delim == Delimiter::Parenthesis => @@ -477,7 +479,7 @@ fn check_nested_occurrences( &nested_macros, &mut nested_binders, &Stack::Empty, - valid, + guar, ); } (NestedMacroState::MacroNameParen, TokenTree::Delimited(.., del)) @@ -491,12 +493,12 @@ fn check_nested_occurrences( &nested_macros, &nested_binders, &Stack::Empty, - valid, + guar, ); } (_, tt) => { state = NestedMacroState::Empty; - check_occurrences(sess, node_id, tt, macros, binders, ops, valid); + check_occurrences(sess, node_id, tt, macros, binders, ops, guar); } } } @@ -515,14 +517,14 @@ fn check_nested_occurrences( /// - `macro_rules` specifies whether the macro is `macro_rules` /// - `tts` is checked as a list of (LHS) => {RHS} /// - `macros` is the stack of outer macros -/// - `valid` is set in case of errors +/// - `guar` is set in case of errors fn check_nested_macro( sess: &ParseSess, node_id: NodeId, macro_rules: bool, tts: &[TokenTree], macros: &Stack<'_, MacroState<'_>>, - valid: &mut bool, + guar: &mut Option, ) -> usize { let n = tts.len(); let mut i = 0; @@ -539,8 +541,8 @@ fn check_nested_macro( let lhs = &tts[i]; let rhs = &tts[i + 2]; let mut binders = Binders::default(); - check_binders(sess, node_id, lhs, macros, &mut binders, &Stack::Empty, valid); - check_occurrences(sess, node_id, rhs, macros, &binders, &Stack::Empty, valid); + check_binders(sess, node_id, lhs, macros, &mut binders, &Stack::Empty, guar); + check_occurrences(sess, node_id, rhs, macros, &binders, &Stack::Empty, guar); // Since the last semicolon is optional for `macro_rules` macros and decl_macro are not terminated, // we increment our checked position by how many token trees we already checked (the 3 // above) before checking for the separator. diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index bf99e9e6d5cc..c11d538048aa 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -66,8 +66,10 @@ impl<'a> ParserAnyMacro<'a> { let fragment = match parse_ast_fragment(parser, kind) { Ok(f) => f, Err(err) => { - diagnostics::emit_frag_parse_err(err, parser, snapshot, site_span, arm_span, kind); - return kind.dummy(site_span); + let guar = diagnostics::emit_frag_parse_err( + err, parser, snapshot, site_span, arm_span, kind, + ); + return kind.dummy(site_span, guar); } }; @@ -101,7 +103,6 @@ struct MacroRulesMacroExpander { transparency: Transparency, lhses: Vec>, rhses: Vec, - valid: bool, } impl TTMacroExpander for MacroRulesMacroExpander { @@ -111,9 +112,6 @@ impl TTMacroExpander for MacroRulesMacroExpander { sp: Span, input: TokenStream, ) -> Box { - if !self.valid { - return DummyResult::any(sp); - } expand_macro( cx, sp, @@ -128,12 +126,17 @@ impl TTMacroExpander for MacroRulesMacroExpander { } } -fn macro_rules_dummy_expander<'cx>( - _: &'cx mut ExtCtxt<'_>, - span: Span, - _: TokenStream, -) -> Box { - DummyResult::any(span) +struct DummyExpander(ErrorGuaranteed); + +impl TTMacroExpander for DummyExpander { + fn expand<'cx>( + &self, + _: &'cx mut ExtCtxt<'_>, + span: Span, + _: TokenStream, + ) -> Box { + DummyResult::any(span, self.0) + } } fn trace_macros_note(cx_expansions: &mut FxIndexMap>, sp: Span, message: String) { @@ -217,8 +220,8 @@ fn expand_macro<'cx>( let tts = match transcribe(cx, &named_matches, rhs, rhs_span, transparency) { Ok(tts) => tts, Err(err) => { - err.emit(); - return DummyResult::any(arm_span); + let guar = err.emit(); + return DummyResult::any(arm_span, guar); } }; @@ -249,9 +252,9 @@ fn expand_macro<'cx>( is_local, }) } - Err(CanRetry::No(_)) => { + Err(CanRetry::No(guar)) => { debug!("Will not retry matching as an error was emitted already"); - DummyResult::any(sp) + DummyResult::any(sp, guar) } Err(CanRetry::Yes) => { // Retry and emit a better error. @@ -371,7 +374,7 @@ pub fn compile_declarative_macro( def.id != DUMMY_NODE_ID, ) }; - let dummy_syn_ext = || (mk_syn_ext(Box::new(macro_rules_dummy_expander)), Vec::new()); + let dummy_syn_ext = |guar| (mk_syn_ext(Box::new(DummyExpander(guar))), Vec::new()); let dcx = &sess.parse_sess.dcx; let lhs_nm = Ident::new(sym::lhs, def.span); @@ -456,19 +459,20 @@ pub fn compile_declarative_macro( let mut err = sess.dcx().struct_span_err(sp, s); err.span_label(sp, msg); annotate_doc_comment(sess.dcx(), &mut err, sess.source_map(), sp); - err.emit(); - return dummy_syn_ext(); + let guar = err.emit(); + return dummy_syn_ext(guar); } Error(sp, msg) => { - sess.dcx().span_err(sp.substitute_dummy(def.span), msg); - return dummy_syn_ext(); + let guar = sess.dcx().span_err(sp.substitute_dummy(def.span), msg); + return dummy_syn_ext(guar); } - ErrorReported(_) => { - return dummy_syn_ext(); + ErrorReported(guar) => { + return dummy_syn_ext(guar); } }; - let mut valid = true; + let mut guar = None; + let mut check_emission = |ret: Result<(), ErrorGuaranteed>| guar = guar.or(ret.err()); // Extract the arguments: let lhses = match &argument_map[&MacroRulesNormalizedIdent::new(lhs_nm)] { @@ -488,7 +492,7 @@ pub fn compile_declarative_macro( .unwrap(); // We don't handle errors here, the driver will abort // after parsing/expansion. we can report every error in every macro this way. - valid &= check_lhs_nt_follows(sess, def, &tt).is_ok(); + check_emission(check_lhs_nt_follows(sess, def, &tt)); return tt; } sess.dcx().span_bug(def.span, "wrong-structured lhs") @@ -520,15 +524,21 @@ pub fn compile_declarative_macro( }; for rhs in &rhses { - valid &= check_rhs(sess, rhs); + check_emission(check_rhs(sess, rhs)); } // don't abort iteration early, so that errors for multiple lhses can be reported for lhs in &lhses { - valid &= check_lhs_no_empty_seq(sess, slice::from_ref(lhs)); + check_emission(check_lhs_no_empty_seq(sess, slice::from_ref(lhs))); } - valid &= macro_check::check_meta_variables(&sess.parse_sess, def.id, def.span, &lhses, &rhses); + check_emission(macro_check::check_meta_variables( + &sess.parse_sess, + def.id, + def.span, + &lhses, + &rhses, + )); let (transparency, transparency_error) = attr::find_transparency(&def.attrs, macro_rules); match transparency_error { @@ -541,11 +551,15 @@ pub fn compile_declarative_macro( None => {} } + if let Some(guar) = guar { + // To avoid warning noise, only consider the rules of this + // macro for the lint, if all rules are valid. + return dummy_syn_ext(guar); + } + // Compute the spans of the macro rules for unused rule linting. - // To avoid warning noise, only consider the rules of this - // macro for the lint, if all rules are valid. // Also, we are only interested in non-foreign macros. - let rule_spans = if valid && def.id != DUMMY_NODE_ID { + let rule_spans = if def.id != DUMMY_NODE_ID { lhses .iter() .zip(rhses.iter()) @@ -562,23 +576,19 @@ pub fn compile_declarative_macro( }; // Convert the lhses into `MatcherLoc` form, which is better for doing the - // actual matching. Unless the matcher is invalid. - let lhses = if valid { - lhses - .iter() - .map(|lhs| { - // Ignore the delimiters around the matcher. - match lhs { - mbe::TokenTree::Delimited(.., delimited) => { - mbe::macro_parser::compute_locs(&delimited.tts) - } - _ => sess.dcx().span_bug(def.span, "malformed macro lhs"), + // actual matching. + let lhses = lhses + .iter() + .map(|lhs| { + // Ignore the delimiters around the matcher. + match lhs { + mbe::TokenTree::Delimited(.., delimited) => { + mbe::macro_parser::compute_locs(&delimited.tts) } - }) - .collect() - } else { - vec![] - }; + _ => sess.dcx().span_bug(def.span, "malformed macro lhs"), + } + }) + .collect(); let expander = Box::new(MacroRulesMacroExpander { name: def.ident, @@ -587,7 +597,6 @@ pub fn compile_declarative_macro( transparency, lhses, rhses, - valid, }); (mk_syn_ext(expander), rule_spans) } @@ -640,7 +649,7 @@ fn is_empty_token_tree(sess: &Session, seq: &mbe::SequenceRepetition) -> bool { /// Checks that the lhs contains no repetition which could match an empty token /// tree, because then the matcher would hang indefinitely. -fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> bool { +fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> Result<(), ErrorGuaranteed> { use mbe::TokenTree; for tt in tts { match tt { @@ -648,35 +657,26 @@ fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> bool { | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) | TokenTree::MetaVarExpr(..) => (), - TokenTree::Delimited(.., del) => { - if !check_lhs_no_empty_seq(sess, &del.tts) { - return false; - } - } + TokenTree::Delimited(.., del) => check_lhs_no_empty_seq(sess, &del.tts)?, TokenTree::Sequence(span, seq) => { if is_empty_token_tree(sess, seq) { let sp = span.entire(); - sess.dcx().span_err(sp, "repetition matches empty token tree"); - return false; - } - if !check_lhs_no_empty_seq(sess, &seq.tts) { - return false; + let guar = sess.dcx().span_err(sp, "repetition matches empty token tree"); + return Err(guar); } + check_lhs_no_empty_seq(sess, &seq.tts)? } } } - true + Ok(()) } -fn check_rhs(sess: &Session, rhs: &mbe::TokenTree) -> bool { +fn check_rhs(sess: &Session, rhs: &mbe::TokenTree) -> Result<(), ErrorGuaranteed> { match *rhs { - mbe::TokenTree::Delimited(..) => return true, - _ => { - sess.dcx().span_err(rhs.span(), "macro rhs must be delimited"); - } + mbe::TokenTree::Delimited(..) => Ok(()), + _ => Err(sess.dcx().span_err(rhs.span(), "macro rhs must be delimited")), } - false } fn check_matcher( diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 35ee0c530463..3481c66da702 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -758,7 +758,7 @@ trait UnusedDelimLint { } impl<'ast> Visitor<'ast> for ErrExprVisitor { fn visit_expr(&mut self, expr: &'ast ast::Expr) { - if let ExprKind::Err = expr.kind { + if let ExprKind::Err(_) = expr.kind { self.has_error = true; return; } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 517e3d827876..cc1f7c8ac7d5 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -744,7 +744,8 @@ impl<'a> Parser<'a> { Err(err) } - pub(super) fn attr_on_non_tail_expr(&self, expr: &Expr) { + /// The user has written `#[attr] expr` which is unsupported. (#106020) + pub(super) fn attr_on_non_tail_expr(&self, expr: &Expr) -> ErrorGuaranteed { // Missing semicolon typo error. let span = self.prev_token.span.shrink_to_hi(); let mut err = self.dcx().create_err(ExpectedSemi { @@ -787,6 +788,8 @@ impl<'a> Parser<'a> { ], Applicability::MachineApplicable, ); + + // Special handling for `#[cfg(...)]` chains let mut snapshot = self.create_snapshot_for_diagnostic(); if let [attr] = &expr.attrs[..] && let ast::AttrKind::Normal(attr_kind) = &attr.kind @@ -799,7 +802,7 @@ impl<'a> Parser<'a> { Err(inner_err) => { err.cancel(); inner_err.cancel(); - return; + return self.dcx().span_delayed_bug(expr.span, "not a tail expression"); } } && let ast::AttrKind::Normal(next_attr_kind) = next_attr.kind @@ -812,7 +815,7 @@ impl<'a> Parser<'a> { Err(inner_err) => { err.cancel(); inner_err.cancel(); - return; + return self.dcx().span_delayed_bug(expr.span, "not a tail expression"); } }; // We have for sure @@ -845,7 +848,7 @@ impl<'a> Parser<'a> { ); } } - err.emit(); + err.emit() } fn check_too_many_raw_str_terminators(&mut self, err: &mut DiagnosticBuilder<'_>) -> bool { @@ -921,10 +924,10 @@ impl<'a> Parser<'a> { // fn foo() -> Foo { Path { // field: value, // } } - err.delay_as_bug(); + let guar = err.delay_as_bug(); self.restore_snapshot(snapshot); let mut tail = self.mk_block( - thin_vec![self.mk_stmt_err(expr.span)], + thin_vec![self.mk_stmt_err(expr.span, guar)], s, lo.to(self.prev_token.span), ); @@ -990,7 +993,7 @@ impl<'a> Parser<'a> { decl_hi: Span, ) -> PResult<'a, P> { err.span_label(lo.to(decl_hi), "while parsing the body of this closure"); - match before.kind { + let guar = match before.kind { token::OpenDelim(Delimiter::Brace) if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) => { @@ -1004,8 +1007,9 @@ impl<'a> Parser<'a> { ], Applicability::MaybeIncorrect, ); - err.emit(); + let guar = err.emit(); self.eat_to_tokens(&[&token::CloseDelim(Delimiter::Brace)]); + guar } token::OpenDelim(Delimiter::Parenthesis) if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) => @@ -1022,7 +1026,7 @@ impl<'a> Parser<'a> { ], Applicability::MaybeIncorrect, ); - err.emit(); + err.emit() } _ if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) => { // We don't have a heuristic to correctly identify where the block @@ -1035,8 +1039,8 @@ impl<'a> Parser<'a> { return Err(err); } _ => return Err(err), - } - Ok(self.mk_expr_err(lo.to(self.token.span))) + }; + Ok(self.mk_expr_err(lo.to(self.token.span), guar)) } /// Eats and discards tokens until one of `kets` is encountered. Respects token trees, @@ -1214,7 +1218,7 @@ impl<'a> Parser<'a> { &mut self, mut e: DiagnosticBuilder<'a>, expr: &mut P, - ) -> PResult<'a, ()> { + ) -> PResult<'a, ErrorGuaranteed> { if let ExprKind::Binary(binop, _, _) = &expr.kind && let ast::BinOpKind::Lt = binop.node && self.eat(&token::Comma) @@ -1239,9 +1243,9 @@ impl<'a> Parser<'a> { // The subsequent expression is valid. Mark // `expr` as erroneous and emit `e` now, but // return `Ok` so parsing can continue. - e.emit(); - *expr = self.mk_expr_err(expr.span.to(self.prev_token.span)); - return Ok(()); + let guar = e.emit(); + *expr = self.mk_expr_err(expr.span.to(self.prev_token.span), guar); + return Ok(guar); } Err(err) => { err.cancel(); @@ -1393,7 +1397,8 @@ impl<'a> Parser<'a> { outer_op.node, ); - let mk_err_expr = |this: &Self, span| Ok(Some(this.mk_expr(span, ExprKind::Err))); + let mk_err_expr = + |this: &Self, span, guar| Ok(Some(this.mk_expr(span, ExprKind::Err(guar)))); match &inner_op.kind { ExprKind::Binary(op, l1, r1) if op.node.is_comparison() => { @@ -1443,11 +1448,11 @@ impl<'a> Parser<'a> { match self.parse_expr() { Ok(_) => { // 99% certain that the suggestion is correct, continue parsing. - self.dcx().emit_err(err); + let guar = self.dcx().emit_err(err); // FIXME: actually check that the two expressions in the binop are // paths and resynthesize new fn call expression instead of using // `ExprKind::Err` placeholder. - mk_err_expr(self, inner_op.span.to(self.prev_token.span)) + mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar) } Err(expr_err) => { expr_err.cancel(); @@ -1471,11 +1476,11 @@ impl<'a> Parser<'a> { match self.consume_fn_args() { Err(()) => Err(self.dcx().create_err(err)), Ok(()) => { - self.dcx().emit_err(err); + let guar = self.dcx().emit_err(err); // FIXME: actually check that the two expressions in the binop are // paths and resynthesize new fn call expression instead of using // `ExprKind::Err` placeholder. - mk_err_expr(self, inner_op.span.to(self.prev_token.span)) + mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar) } } } else { @@ -1492,8 +1497,8 @@ impl<'a> Parser<'a> { let recovered = self .attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op); if matches!(recovered, Recovered::Yes) { - self.dcx().emit_err(err); - mk_err_expr(self, inner_op.span.to(self.prev_token.span)) + let guar = self.dcx().emit_err(err); + mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar) } else { // These cases cause too many knock-down errors, bail out (#61329). Err(self.dcx().create_err(err)) @@ -1502,9 +1507,9 @@ impl<'a> Parser<'a> { } let recover = self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op); - self.dcx().emit_err(err); + let guar = self.dcx().emit_err(err); if matches!(recover, Recovered::Yes) { - return mk_err_expr(self, inner_op.span.to(self.prev_token.span)); + return mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar); } } _ => {} @@ -1925,8 +1930,8 @@ impl<'a> Parser<'a> { } else { self.recover_await_prefix(await_sp)? }; - let sp = self.error_on_incorrect_await(lo, hi, &expr, is_question); - let expr = self.mk_expr(lo.to(sp), ExprKind::Err); + let (sp, guar) = self.error_on_incorrect_await(lo, hi, &expr, is_question); + let expr = self.mk_expr_err(lo.to(sp), guar); self.maybe_recover_from_bad_qpath(expr) } @@ -1955,21 +1960,27 @@ impl<'a> Parser<'a> { Ok((expr.span, expr, is_question)) } - fn error_on_incorrect_await(&self, lo: Span, hi: Span, expr: &Expr, is_question: bool) -> Span { + fn error_on_incorrect_await( + &self, + lo: Span, + hi: Span, + expr: &Expr, + is_question: bool, + ) -> (Span, ErrorGuaranteed) { let span = lo.to(hi); let applicability = match expr.kind { ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await ?` _ => Applicability::MachineApplicable, }; - self.dcx().emit_err(IncorrectAwait { + let guar = self.dcx().emit_err(IncorrectAwait { span, sugg_span: (span, applicability), expr: self.span_to_snippet(expr.span).unwrap_or_else(|_| pprust::expr_to_string(expr)), question_mark: if is_question { "?" } else { "" }, }); - span + (span, guar) } /// If encountering `future.await()`, consumes and emits an error. @@ -2013,8 +2024,8 @@ impl<'a> Parser<'a> { ); } err.span_suggestion(lo.shrink_to_lo(), format!("{prefix}you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax"), "r#", Applicability::MachineApplicable); - err.emit(); - Ok(self.mk_expr_err(lo.to(hi))) + let guar = err.emit(); + Ok(self.mk_expr_err(lo.to(hi), guar)) } else { Err(self.expected_expression_found()) // The user isn't trying to invoke the try! macro } @@ -2059,10 +2070,10 @@ impl<'a> Parser<'a> { lo: Span, err: PErr<'a>, ) -> P { - err.emit(); + let guar = err.emit(); // Recover from parse error, callers expect the closing delim to be consumed. self.consume_block(delim, ConsumeClosingDelim::Yes); - self.mk_expr(lo.to(self.prev_token.span), ExprKind::Err) + self.mk_expr(lo.to(self.prev_token.span), ExprKind::Err(guar)) } /// Eats tokens until we can be relatively sure we reached the end of the @@ -2549,9 +2560,10 @@ impl<'a> Parser<'a> { } _ => None, }; - self.dcx().emit_err(UnexpectedConstParamDeclaration { span: param.span(), sugg }); + let guar = + self.dcx().emit_err(UnexpectedConstParamDeclaration { span: param.span(), sugg }); - let value = self.mk_expr_err(param.span()); + let value = self.mk_expr_err(param.span(), guar); Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })) } @@ -2630,8 +2642,8 @@ impl<'a> Parser<'a> { "=", Applicability::MaybeIncorrect, ); - let value = self.mk_expr_err(start.to(expr.span)); - err.emit(); + let guar = err.emit(); + let value = self.mk_expr_err(start.to(expr.span), guar); return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })); } else if token::Colon == snapshot.token.kind && expr.span.lo() == snapshot.token.span.hi() @@ -2701,8 +2713,8 @@ impl<'a> Parser<'a> { vec![(span.shrink_to_lo(), "{ ".to_string()), (span.shrink_to_hi(), " }".to_string())], Applicability::MaybeIncorrect, ); - let value = self.mk_expr_err(span); - err.emit(); + let guar = err.emit(); + let value = self.mk_expr_err(span, guar); GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }) } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 89f28777bffb..e1a5e17004f6 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -34,7 +34,7 @@ use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_span::source_map::{self, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{BytePos, Pos, Span}; +use rustc_span::{BytePos, ErrorGuaranteed, Pos, Span}; use thin_vec::{thin_vec, ThinVec}; /// Possibly accepts an `token::Interpolated` expression (a pre-parsed expression @@ -131,9 +131,9 @@ impl<'a> Parser<'a> { if self.may_recover() && self.look_ahead(1, |t| t == &token::Comma) => { // Special-case handling of `foo(_, _, _)` - err.emit(); + let guar = err.emit(); self.bump(); - Ok(self.mk_expr(self.prev_token.span, ExprKind::Err)) + Ok(self.mk_expr(self.prev_token.span, ExprKind::Err(guar))) } _ => Err(err), }, @@ -667,8 +667,8 @@ impl<'a> Parser<'a> { let (span, _) = self.parse_expr_prefix_common(box_kw)?; let inner_span = span.with_lo(box_kw.hi()); let code = self.sess.source_map().span_to_snippet(inner_span).unwrap(); - self.dcx().emit_err(errors::BoxSyntaxRemoved { span: span, code: code.trim() }); - Ok((span, ExprKind::Err)) + let guar = self.dcx().emit_err(errors::BoxSyntaxRemoved { span: span, code: code.trim() }); + Ok((span, ExprKind::Err(guar))) } fn is_mistaken_not_ident_negation(&self) -> bool { @@ -860,7 +860,7 @@ impl<'a> Parser<'a> { ExprKind::MethodCall(_) => "a method call", ExprKind::Call(_, _) => "a function call", ExprKind::Await(_, _) => "`.await`", - ExprKind::Err => return Ok(with_postfix), + ExprKind::Err(_) => return Ok(with_postfix), _ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"), } ); @@ -1315,7 +1315,7 @@ impl<'a> Parser<'a> { let fields: Vec<_> = fields.into_iter().filter(|field| !field.is_shorthand).collect(); - if !fields.is_empty() && + let guar = if !fields.is_empty() && // `token.kind` should not be compared here. // This is because the `snapshot.token.kind` is treated as the same as // that of the open delim in `TokenTreesReader::parse_token_tree`, even @@ -1338,11 +1338,11 @@ impl<'a> Parser<'a> { .collect(), }, }) - .emit(); + .emit() } else { - err.emit(); - } - Ok(self.mk_expr_err(span)) + err.emit() + }; + Ok(self.mk_expr_err(span, guar)) } Ok(_) => Err(err), Err(err2) => { @@ -1684,13 +1684,13 @@ impl<'a> Parser<'a> { && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt)) { // We're probably inside of a `Path<'a>` that needs a turbofish - self.dcx().emit_err(errors::UnexpectedTokenAfterLabel { + let guar = self.dcx().emit_err(errors::UnexpectedTokenAfterLabel { span: self.token.span, remove_label: None, enclose_in_block: None, }); consume_colon = false; - Ok(self.mk_expr_err(lo)) + Ok(self.mk_expr_err(lo, guar)) } else { let mut err = errors::UnexpectedTokenAfterLabel { span: self.token.span, @@ -2039,7 +2039,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, L> { if let token::Interpolated(nt) = &self.token.kind && let token::NtExpr(e) | token::NtLiteral(e) = &nt.0 - && matches!(e.kind, ExprKind::Err) + && matches!(e.kind, ExprKind::Err(_)) { let mut err = self .dcx() @@ -2207,7 +2207,7 @@ impl<'a> Parser<'a> { let mut snapshot = self.create_snapshot_for_diagnostic(); match snapshot.parse_expr_array_or_repeat(Delimiter::Brace) { Ok(arr) => { - self.dcx().emit_err(errors::ArrayBracketsInsteadOfSpaces { + let guar = self.dcx().emit_err(errors::ArrayBracketsInsteadOfSpaces { span: arr.span, sub: errors::ArrayBracketsInsteadOfSpacesSugg { left: lo, @@ -2216,7 +2216,7 @@ impl<'a> Parser<'a> { }); self.restore_snapshot(snapshot); - Some(self.mk_expr_err(arr.span)) + Some(self.mk_expr_err(arr.span, guar)) } Err(e) => { e.cancel(); @@ -2370,7 +2370,10 @@ impl<'a> Parser<'a> { // It is likely that the closure body is a block but where the // braces have been removed. We will recover and eat the next // statements later in the parsing process. - body = self.mk_expr_err(body.span); + body = self.mk_expr_err( + body.span, + self.dcx().span_delayed_bug(body.span, "recovered a closure body as a block"), + ); } let body_span = body.span; @@ -2485,7 +2488,7 @@ impl<'a> Parser<'a> { ExprKind::Binary(Spanned { span: binop_span, .. }, _, right) if let ExprKind::Block(_, None) = right.kind => { - this.dcx().emit_err(errors::IfExpressionMissingThenBlock { + let guar = this.dcx().emit_err(errors::IfExpressionMissingThenBlock { if_span: lo, missing_then_block_sub: errors::IfExpressionMissingThenBlockSub::UnfinishedCondition( @@ -2493,14 +2496,14 @@ impl<'a> Parser<'a> { ), let_else_sub: None, }); - std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi())) + std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi(), guar)) } ExprKind::Block(_, None) => { - this.dcx().emit_err(errors::IfExpressionMissingCondition { + let guar = this.dcx().emit_err(errors::IfExpressionMissingCondition { if_span: lo.with_neighbor(cond.span).shrink_to_hi(), block_span: self.sess.source_map().start_point(cond_span), }); - std::mem::replace(&mut cond, this.mk_expr_err(cond_span.shrink_to_hi())) + std::mem::replace(&mut cond, this.mk_expr_err(cond_span.shrink_to_hi(), guar)) } _ => { return None; @@ -2520,14 +2523,14 @@ impl<'a> Parser<'a> { let let_else_sub = matches!(cond.kind, ExprKind::Let(..)) .then(|| errors::IfExpressionLetSomeSub { if_span: lo.until(cond_span) }); - self.dcx().emit_err(errors::IfExpressionMissingThenBlock { + let guar = self.dcx().emit_err(errors::IfExpressionMissingThenBlock { if_span: lo, missing_then_block_sub: errors::IfExpressionMissingThenBlockSub::AddThenBlock( cond_span.shrink_to_hi(), ), let_else_sub, }); - self.mk_block_err(cond_span.shrink_to_hi()) + self.mk_block_err(cond_span.shrink_to_hi(), guar) } } else { let attrs = self.parse_outer_attributes()?; // For recovery. @@ -2797,9 +2800,10 @@ impl<'a> Parser<'a> { && !matches!(self.token.kind, token::OpenDelim(Delimiter::Brace)) && self.may_recover() { - self.dcx() + let guar = self + .dcx() .emit_err(errors::MissingExpressionInForLoop { span: expr.span.shrink_to_lo() }); - let err_expr = self.mk_expr(expr.span, ExprKind::Err); + let err_expr = self.mk_expr(expr.span, ExprKind::Err(guar)); let block = self.mk_block(thin_vec![], BlockCheckMode::Default, self.prev_token.span); return Ok(self.mk_expr( lo.to(self.prev_token.span), @@ -2924,7 +2928,7 @@ impl<'a> Parser<'a> { attrs: Default::default(), pat: self.mk_pat(span, ast::PatKind::Err(guar)), guard: None, - body: Some(self.mk_expr_err(span)), + body: Some(self.mk_expr_err(span, guar)), span, id: DUMMY_NODE_ID, is_placeholder: false, @@ -2959,7 +2963,7 @@ impl<'a> Parser<'a> { let err = |this: &Parser<'_>, stmts: Vec| { let span = stmts[0].span.to(stmts[stmts.len() - 1].span); - this.dcx().emit_err(errors::MatchArmBodyWithoutBraces { + let guar = this.dcx().emit_err(errors::MatchArmBodyWithoutBraces { statements: span, arrow: arrow_span, num_statements: stmts.len(), @@ -2972,7 +2976,7 @@ impl<'a> Parser<'a> { errors::MatchArmBodyWithoutBracesSugg::UseComma { semicolon: semi_sp } }, }); - this.mk_expr_err(span) + this.mk_expr_err(span, guar) }; // We might have either a `,` -> `;` typo, or a block without braces. We need // a more subtle parsing strategy. @@ -3433,14 +3437,20 @@ impl<'a> Parser<'a> { pth: ast::Path, recover: bool, close_delim: Delimiter, - ) -> PResult<'a, (ThinVec, ast::StructRest, bool)> { + ) -> PResult< + 'a, + ( + ThinVec, + ast::StructRest, + Option, /* async blocks are forbidden in Rust 2015 */ + ), + > { let mut fields = ThinVec::new(); let mut base = ast::StructRest::None; - let mut recover_async = false; + let mut recovered_async = None; let in_if_guard = self.restrictions.contains(Restrictions::IN_IF_GUARD); - let mut async_block_err = |e: &mut DiagnosticBuilder<'_>, span: Span| { - recover_async = true; + let async_block_err = |e: &mut DiagnosticBuilder<'_>, span: Span| { errors::AsyncBlockIn2015 { span }.add_to_diagnostic(e); errors::HelpUseLatestEdition::new().add_to_diagnostic(e); }; @@ -3465,9 +3475,34 @@ impl<'a> Parser<'a> { break; } - let recovery_field = self.find_struct_error_after_field_looking_code(); + // Peek the field's ident before parsing its expr in order to emit better diagnostics. + let peek = self + .token + .ident() + .filter(|(ident, is_raw)| { + (!ident.is_reserved() || matches!(is_raw, IdentIsRaw::Yes)) + && self.look_ahead(1, |tok| *tok == token::Colon) + }) + .map(|(ident, _)| ident); + + // We still want a field even if its expr didn't parse. + let field_ident = |this: &Self, guar: ErrorGuaranteed| { + peek.map(|ident| { + let span = ident.span; + ExprField { + ident, + span, + expr: this.mk_expr_err(span, guar), + is_shorthand: false, + attrs: AttrVec::new(), + id: DUMMY_NODE_ID, + is_placeholder: false, + } + }) + }; + let parsed_field = match self.parse_expr_field() { - Ok(f) => Some(f), + Ok(f) => Ok(f), Err(mut e) => { if pth == kw::Async { async_block_err(&mut e, pth.span); @@ -3499,7 +3534,10 @@ impl<'a> Parser<'a> { return Err(e); } - e.emit(); + let guar = e.emit(); + if pth == kw::Async { + recovered_async = Some(guar); + } // If the next token is a comma, then try to parse // what comes next as additional fields, rather than @@ -3511,18 +3549,20 @@ impl<'a> Parser<'a> { } } - None + Err(guar) } }; - let is_shorthand = parsed_field.as_ref().is_some_and(|f| f.is_shorthand); + let is_shorthand = parsed_field.as_ref().is_ok_and(|f| f.is_shorthand); // A shorthand field can be turned into a full field with `:`. // We should point this out. self.check_or_expected(!is_shorthand, TokenType::Token(token::Colon)); match self.expect_one_of(&[token::Comma], &[token::CloseDelim(close_delim)]) { Ok(_) => { - if let Some(f) = parsed_field.or(recovery_field) { + if let Some(f) = + parsed_field.or_else(|guar| field_ident(self, guar).ok_or(guar)).ok() + { // Only include the field if there's no parse error for the field name. fields.push(f); } @@ -3532,8 +3572,7 @@ impl<'a> Parser<'a> { async_block_err(&mut e, pth.span); } else { e.span_label(pth.span, "while parsing this struct"); - if let Some(f) = recovery_field { - fields.push(f); + if peek.is_some() { e.span_suggestion( self.prev_token.span.shrink_to_hi(), "try adding a comma", @@ -3545,13 +3584,18 @@ impl<'a> Parser<'a> { if !recover { return Err(e); } - e.emit(); + let guar = e.emit(); + if pth == kw::Async { + recovered_async = Some(guar); + } else if let Some(f) = field_ident(self, guar) { + fields.push(f); + } self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore); self.eat(&token::Comma); } } } - Ok((fields, base, recover_async)) + Ok((fields, base, recovered_async)) } /// Precondition: already parsed the '{'. @@ -3562,39 +3606,18 @@ impl<'a> Parser<'a> { recover: bool, ) -> PResult<'a, P> { let lo = pth.span; - let (fields, base, recover_async) = + let (fields, base, recovered_async) = self.parse_struct_fields(pth.clone(), recover, Delimiter::Brace)?; let span = lo.to(self.token.span); self.expect(&token::CloseDelim(Delimiter::Brace))?; - let expr = if recover_async { - ExprKind::Err + let expr = if let Some(guar) = recovered_async { + ExprKind::Err(guar) } else { ExprKind::Struct(P(ast::StructExpr { qself, path: pth, fields, rest: base })) }; Ok(self.mk_expr(span, expr)) } - /// Use in case of error after field-looking code: `S { foo: () with a }`. - fn find_struct_error_after_field_looking_code(&self) -> Option { - match self.token.ident() { - Some((ident, is_raw)) - if (matches!(is_raw, IdentIsRaw::Yes) || !ident.is_reserved()) - && self.look_ahead(1, |t| *t == token::Colon) => - { - Some(ast::ExprField { - ident, - span: self.token.span, - expr: self.mk_expr_err(self.token.span), - is_shorthand: false, - attrs: AttrVec::new(), - id: DUMMY_NODE_ID, - is_placeholder: false, - }) - } - _ => None, - } - } - fn recover_struct_comma_after_dotdot(&mut self, span: Span) { if self.token != token::Comma { return; @@ -3718,8 +3741,8 @@ impl<'a> Parser<'a> { limits: RangeLimits, ) -> ExprKind { if end.is_none() && limits == RangeLimits::Closed { - self.inclusive_range_with_incorrect_end(); - ExprKind::Err + let guar = self.inclusive_range_with_incorrect_end(); + ExprKind::Err(guar) } else { ExprKind::Range(start, end, limits) } @@ -3756,8 +3779,8 @@ impl<'a> Parser<'a> { self.mk_expr_with_attrs(span, kind, AttrVec::new()) } - pub(super) fn mk_expr_err(&self, span: Span) -> P { - self.mk_expr(span, ExprKind::Err) + pub(super) fn mk_expr_err(&self, span: Span, guar: ErrorGuaranteed) -> P { + self.mk_expr(span, ExprKind::Err(guar)) } /// Create expression span ensuring the span of the parent node @@ -3949,7 +3972,7 @@ impl MutVisitor for CondChecker<'_> { | ExprKind::Become(_) | ExprKind::IncludedBytes(_) | ExprKind::FormatArgs(_) - | ExprKind::Err + | ExprKind::Err(_) | ExprKind::Dummy => { // These would forbid any let expressions they contain already. } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 2e049ca908fd..a678194372e9 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2328,11 +2328,11 @@ impl<'a> Parser<'a> { let _ = self.parse_expr()?; self.expect_semi()?; // `;` let span = eq_sp.to(self.prev_token.span); - self.dcx().emit_err(errors::FunctionBodyEqualsExpr { + let guar = self.dcx().emit_err(errors::FunctionBodyEqualsExpr { span, sugg: errors::FunctionBodyEqualsExprSugg { eq: eq_sp, semi: self.prev_token.span }, }); - (AttrVec::new(), Some(self.mk_block_err(span))) + (AttrVec::new(), Some(self.mk_block_err(span, guar))) } else { let expected = if req_body { &[token::OpenDelim(Delimiter::Brace)][..] diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index c82b44ac6e10..9bff5b930925 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -566,7 +566,7 @@ impl<'a> Parser<'a> { match self.parse_literal_maybe_minus() { Ok(begin) => { let begin = match self.maybe_recover_trailing_expr(begin.span, false) { - Some(_) => self.mk_expr_err(begin.span), + Some(guar) => self.mk_expr_err(begin.span, guar), None => begin, }; @@ -719,7 +719,7 @@ impl<'a> Parser<'a> { self.parse_pat_range_begin_with(begin.clone(), form) } // recover ranges with parentheses around the `(start)..` - PatKind::Err(_) + PatKind::Err(guar) if self.may_recover() && let Some(form) = self.parse_range_end() => { @@ -731,7 +731,7 @@ impl<'a> Parser<'a> { }, }); - self.parse_pat_range_begin_with(self.mk_expr(pat.span, ExprKind::Err), form) + self.parse_pat_range_begin_with(self.mk_expr_err(pat.span, *guar), form) } // (pat) with optional parentheses @@ -886,7 +886,7 @@ impl<'a> Parser<'a> { Ok(PatKind::Range(Some(begin), end, re)) } - pub(super) fn inclusive_range_with_incorrect_end(&mut self) { + pub(super) fn inclusive_range_with_incorrect_end(&mut self) -> ErrorGuaranteed { let tok = &self.token; let span = self.prev_token.span; // If the user typed "..==" instead of "..=", we want to give them @@ -905,15 +905,13 @@ impl<'a> Parser<'a> { let _ = self.parse_pat_range_end().map_err(|e| e.cancel()); } - self.dcx().emit_err(InclusiveRangeExtraEquals { span: span_with_eq }); + self.dcx().emit_err(InclusiveRangeExtraEquals { span: span_with_eq }) } token::Gt if no_space => { let after_pat = span.with_hi(span.hi() - rustc_span::BytePos(1)).shrink_to_hi(); - self.dcx().emit_err(InclusiveRangeMatchArrow { span, arrow: tok.span, after_pat }); - } - _ => { - self.dcx().emit_err(InclusiveRangeNoEnd { span }); + self.dcx().emit_err(InclusiveRangeMatchArrow { span, arrow: tok.span, after_pat }) } + _ => self.dcx().emit_err(InclusiveRangeNoEnd { span }), } } @@ -987,7 +985,7 @@ impl<'a> Parser<'a> { } Ok(match recovered { - Some(_) => self.mk_expr_err(bound.span), + Some(guar) => self.mk_expr_err(bound.span, guar), None => bound, }) } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index ee02b69c6140..15f8124823fb 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -22,7 +22,7 @@ use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, HasAttrs, Local, Stmt}; use rustc_ast::{StmtKind, DUMMY_NODE_ID}; use rustc_errors::{Applicability, DiagnosticBuilder, PResult}; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{BytePos, Span}; +use rustc_span::{BytePos, ErrorGuaranteed, Span}; use std::borrow::Cow; use std::mem; @@ -610,9 +610,9 @@ impl<'a> Parser<'a> { } } - err.emit(); + let guar = err.emit(); self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore); - Some(self.mk_stmt_err(self.token.span)) + Some(self.mk_stmt_err(self.token.span, guar)) } Ok(stmt) => stmt, Err(err) => return Err(err), @@ -651,10 +651,10 @@ impl<'a> Parser<'a> { .contains(&self.token.kind) => { // The user has written `#[attr] expr` which is unsupported. (#106020) - self.attr_on_non_tail_expr(&expr); + let guar = self.attr_on_non_tail_expr(&expr); // We already emitted an error, so don't emit another type error let sp = expr.span.to(self.prev_token.span); - *expr = self.mk_expr_err(sp); + *expr = self.mk_expr_err(sp, guar); } // Expression without semicolon. @@ -666,10 +666,18 @@ impl<'a> Parser<'a> { let expect_result = self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)]); + // Try to both emit a better diagnostic, and avoid further errors by replacing + // the `expr` with `ExprKind::Err`. let replace_with_err = 'break_recover: { match expect_result { - // Recover from parser, skip type error to avoid extra errors. - Ok(Recovered::Yes) => true, + Ok(Recovered::No) => None, + Ok(Recovered::Yes) => { + // Skip type error to avoid extra errors. + let guar = self + .dcx() + .span_delayed_bug(self.prev_token.span, "expected `;` or `}`"); + Some(guar) + } Err(e) => { if self.recover_colon_as_semi() { // recover_colon_as_semi has already emitted a nicer error. @@ -677,7 +685,7 @@ impl<'a> Parser<'a> { add_semi_to_stmt = true; eat_semi = false; - break 'break_recover false; + break 'break_recover None; } match &expr.kind { @@ -705,13 +713,13 @@ impl<'a> Parser<'a> { }; match self.parse_expr_labeled(label, false) { Ok(labeled_expr) => { - e.delay_as_bug(); + e.cancel(); self.dcx().emit_err(MalformedLoopLabel { span: label.ident.span, correct_label: label.ident, }); *expr = labeled_expr; - break 'break_recover false; + break 'break_recover None; } Err(err) => { err.cancel(); @@ -723,26 +731,26 @@ impl<'a> Parser<'a> { _ => {} } - if let Err(e) = - self.check_mistyped_turbofish_with_multiple_type_params(e, expr) - { - if recover.no() { - return Err(e); - } - e.emit(); - self.recover_stmt(); - } + let res = + self.check_mistyped_turbofish_with_multiple_type_params(e, expr); - true + Some(if recover.no() { + res? + } else { + res.unwrap_or_else(|e| { + let guar = e.emit(); + self.recover_stmt(); + guar + }) + }) } - Ok(Recovered::No) => false, } }; - if replace_with_err { + if let Some(guar) = replace_with_err { // We already emitted an error, so don't emit another type error let sp = expr.span.to(self.prev_token.span); - *expr = self.mk_expr_err(sp); + *expr = self.mk_expr_err(sp, guar); } } StmtKind::Expr(_) | StmtKind::MacCall(_) => {} @@ -791,11 +799,11 @@ impl<'a> Parser<'a> { Stmt { id: DUMMY_NODE_ID, kind, span } } - pub(super) fn mk_stmt_err(&self, span: Span) -> Stmt { - self.mk_stmt(span, StmtKind::Expr(self.mk_expr_err(span))) + pub(super) fn mk_stmt_err(&self, span: Span, guar: ErrorGuaranteed) -> Stmt { + self.mk_stmt(span, StmtKind::Expr(self.mk_expr_err(span, guar))) } - pub(super) fn mk_block_err(&self, span: Span) -> P { - self.mk_block(thin_vec![self.mk_stmt_err(span)], BlockCheckMode::Default, span) + pub(super) fn mk_block_err(&self, span: Span, guar: ErrorGuaranteed) -> P { + self.mk_block(thin_vec![self.mk_stmt_err(span, guar)], BlockCheckMode::Default, span) } } diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 5d46581f646c..73c92708eb39 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -90,7 +90,7 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta // been reported. let msg = "attribute value must be a literal"; let mut err = sess.dcx.struct_span_err(expr.span, msg); - if let ast::ExprKind::Err = expr.kind { + if let ast::ExprKind::Err(_) = expr.kind { err.downgrade_to_delayed_bug(); } return Err(err); diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 81a26a12009d..c52a4e0d8b7c 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -143,7 +143,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { match (&l.kind, &r.kind) { (Paren(l), _) => eq_expr(l, r), (_, Paren(r)) => eq_expr(l, r), - (Err, Err) => true, + (Err(_), Err(_)) => true, (Dummy, _) | (_, Dummy) => unreachable!("comparing `ExprKind::Dummy`"), (Try(l), Try(r)) | (Await(l, _), Await(r, _)) => eq_expr(l, r), (Array(l), Array(r)) => over(l, r, |l, r| eq_expr(l, r)), diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 7b1b0388b29f..1f6446b8746e 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -222,7 +222,7 @@ impl<'a> Sugg<'a> { | ast::ExprKind::Array(..) | ast::ExprKind::While(..) | ast::ExprKind::Await(..) - | ast::ExprKind::Err + | ast::ExprKind::Err(_) | ast::ExprKind::Dummy => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0), ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp( AssocOp::DotDot, diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index d46d7c53bdb4..c500b30b9982 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -404,7 +404,7 @@ pub(crate) fn format_expr( // These do not occur in the AST because macros aren't expanded. unreachable!() } - ast::ExprKind::Err | ast::ExprKind::Dummy => None, + ast::ExprKind::Err(_) | ast::ExprKind::Dummy => None, }; expr_rw diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index b6b37e492e92..d4218cff75aa 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -498,7 +498,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr | ast::ExprKind::Cast(..) | ast::ExprKind::Continue(..) | ast::ExprKind::Dummy - | ast::ExprKind::Err + | ast::ExprKind::Err(_) | ast::ExprKind::Field(..) | ast::ExprKind::IncludedBytes(..) | ast::ExprKind::InlineAsm(..) From 34eae07ee52ea0c79b07babc39ae9f139a930091 Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Sun, 25 Feb 2024 22:25:26 +0100 Subject: [PATCH 17/39] Remove `ast::` & `base::` prefixes from some builtin macros --- compiler/rustc_builtin_macros/src/cfg.rs | 4 +- .../rustc_builtin_macros/src/compile_error.rs | 4 +- compiler/rustc_builtin_macros/src/concat.rs | 44 +++++---- .../rustc_builtin_macros/src/concat_bytes.rs | 89 +++++++++---------- .../rustc_builtin_macros/src/concat_idents.rs | 26 +++--- compiler/rustc_builtin_macros/src/env.rs | 20 +++-- .../rustc_builtin_macros/src/source_util.rs | 47 +++++----- 7 files changed, 116 insertions(+), 118 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index ca66bc0da0cc..04bf7dceeff4 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -8,14 +8,14 @@ use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_attr as attr; use rustc_errors::PResult; -use rustc_expand::base::{self, *}; +use rustc_expand::base::{DummyResult, ExtCtxt, MacEager, MacResult}; use rustc_span::Span; pub fn expand_cfg( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let sp = cx.with_def_site_ctxt(sp); match parse_cfg(cx, sp, tts) { diff --git a/compiler/rustc_builtin_macros/src/compile_error.rs b/compiler/rustc_builtin_macros/src/compile_error.rs index 665003512729..b4455d7823f3 100644 --- a/compiler/rustc_builtin_macros/src/compile_error.rs +++ b/compiler/rustc_builtin_macros/src/compile_error.rs @@ -1,14 +1,14 @@ // The compiler code necessary to support the compile_error! extension. use rustc_ast::tokenstream::TokenStream; -use rustc_expand::base::{self, *}; +use rustc_expand::base::{get_single_str_from_tts, DummyResult, ExtCtxt, MacResult}; use rustc_span::Span; pub fn expand_compile_error<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let var = match get_single_str_from_tts(cx, sp, tts, "compile_error!") { Ok(var) => var, Err(guar) => return DummyResult::any(sp, guar), diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs index dd4a0e7f2286..abfaa9b006ed 100644 --- a/compiler/rustc_builtin_macros/src/concat.rs +++ b/compiler/rustc_builtin_macros/src/concat.rs @@ -1,17 +1,17 @@ -use rustc_ast as ast; use rustc_ast::tokenstream::TokenStream; -use rustc_expand::base::{self, DummyResult}; +use rustc_ast::{ExprKind, LitKind, UnOp}; +use rustc_expand::base::{get_exprs_from_tts, DummyResult, ExtCtxt, MacEager, MacResult}; use rustc_session::errors::report_lit_error; use rustc_span::symbol::Symbol; use crate::errors; pub fn expand_concat( - cx: &mut base::ExtCtxt<'_>, + cx: &mut ExtCtxt<'_>, sp: rustc_span::Span, tts: TokenStream, -) -> Box { - let es = match base::get_exprs_from_tts(cx, tts) { +) -> Box { + let es = match get_exprs_from_tts(cx, tts) { Ok(es) => es, Err(guar) => return DummyResult::any(sp, guar), }; @@ -20,26 +20,26 @@ pub fn expand_concat( let mut guar = None; for e in es { match e.kind { - ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) { - Ok(ast::LitKind::Str(s, _) | ast::LitKind::Float(s, _)) => { + ExprKind::Lit(token_lit) => match LitKind::from_token_lit(token_lit) { + Ok(LitKind::Str(s, _) | LitKind::Float(s, _)) => { accumulator.push_str(s.as_str()); } - Ok(ast::LitKind::Char(c)) => { + Ok(LitKind::Char(c)) => { accumulator.push(c); } - Ok(ast::LitKind::Int(i, _)) => { + Ok(LitKind::Int(i, _)) => { accumulator.push_str(&i.to_string()); } - Ok(ast::LitKind::Bool(b)) => { + Ok(LitKind::Bool(b)) => { accumulator.push_str(&b.to_string()); } - Ok(ast::LitKind::CStr(..)) => { + Ok(LitKind::CStr(..)) => { guar = Some(cx.dcx().emit_err(errors::ConcatCStrLit { span: e.span })); } - Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => { + Ok(LitKind::Byte(..) | LitKind::ByteStr(..)) => { guar = Some(cx.dcx().emit_err(errors::ConcatBytestr { span: e.span })); } - Ok(ast::LitKind::Err(guarantee)) => { + Ok(LitKind::Err(guarantee)) => { guar = Some(guarantee); } Err(err) => { @@ -47,25 +47,23 @@ pub fn expand_concat( } }, // We also want to allow negative numeric literals. - ast::ExprKind::Unary(ast::UnOp::Neg, ref expr) - if let ast::ExprKind::Lit(token_lit) = expr.kind => - { - match ast::LitKind::from_token_lit(token_lit) { - Ok(ast::LitKind::Int(i, _)) => accumulator.push_str(&format!("-{i}")), - Ok(ast::LitKind::Float(f, _)) => accumulator.push_str(&format!("-{f}")), + ExprKind::Unary(UnOp::Neg, ref expr) if let ExprKind::Lit(token_lit) = expr.kind => { + match LitKind::from_token_lit(token_lit) { + Ok(LitKind::Int(i, _)) => accumulator.push_str(&format!("-{i}")), + Ok(LitKind::Float(f, _)) => accumulator.push_str(&format!("-{f}")), Err(err) => { guar = Some(report_lit_error(&cx.sess.parse_sess, err, token_lit, e.span)); } _ => missing_literal.push(e.span), } } - ast::ExprKind::IncludedBytes(..) => { + ExprKind::IncludedBytes(..) => { cx.dcx().emit_err(errors::ConcatBytestr { span: e.span }); } - ast::ExprKind::Err(guarantee) => { + ExprKind::Err(guarantee) => { guar = Some(guarantee); } - ast::ExprKind::Dummy => cx.dcx().span_bug(e.span, "concatenating `ExprKind::Dummy`"), + ExprKind::Dummy => cx.dcx().span_bug(e.span, "concatenating `ExprKind::Dummy`"), _ => { missing_literal.push(e.span); } @@ -79,5 +77,5 @@ pub fn expand_concat( return DummyResult::any(sp, guar); } let sp = cx.with_def_site_ctxt(sp); - base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator))) + MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator))) } diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index 32e17112d8c4..3fb0b50f4175 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -1,6 +1,5 @@ -use rustc_ast as ast; -use rustc_ast::{ptr::P, tokenstream::TokenStream}; -use rustc_expand::base::{self, DummyResult}; +use rustc_ast::{ptr::P, token, tokenstream::TokenStream, ExprKind, LitIntType, LitKind, UintTy}; +use rustc_expand::base::{get_exprs_from_tts, DummyResult, ExtCtxt, MacEager, MacResult}; use rustc_session::errors::report_lit_error; use rustc_span::{ErrorGuaranteed, Span}; @@ -8,8 +7,8 @@ use crate::errors; /// Emits errors for literal expressions that are invalid inside and outside of an array. fn invalid_type_err( - cx: &mut base::ExtCtxt<'_>, - token_lit: ast::token::Lit, + cx: &mut ExtCtxt<'_>, + token_lit: token::Lit, span: Span, is_nested: bool, ) -> ErrorGuaranteed { @@ -18,18 +17,18 @@ fn invalid_type_err( }; let snippet = cx.sess.source_map().span_to_snippet(span).ok(); let dcx = cx.dcx(); - match ast::LitKind::from_token_lit(token_lit) { - Ok(ast::LitKind::CStr(_, _)) => { + match LitKind::from_token_lit(token_lit) { + Ok(LitKind::CStr(_, _)) => { // Avoid ambiguity in handling of terminal `NUL` by refusing to // concatenate C string literals as bytes. dcx.emit_err(errors::ConcatCStrLit { span }) } - Ok(ast::LitKind::Char(_)) => { + Ok(LitKind::Char(_)) => { let sugg = snippet.map(|snippet| ConcatBytesInvalidSuggestion::CharLit { span, snippet }); dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg }) } - Ok(ast::LitKind::Str(_, _)) => { + Ok(LitKind::Str(_, _)) => { // suggestion would be invalid if we are nested let sugg = if !is_nested { snippet.map(|snippet| ConcatBytesInvalidSuggestion::StrLit { span, snippet }) @@ -38,27 +37,24 @@ fn invalid_type_err( }; dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg }) } - Ok(ast::LitKind::Float(_, _)) => { + Ok(LitKind::Float(_, _)) => { dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None }) } - Ok(ast::LitKind::Bool(_)) => { + Ok(LitKind::Bool(_)) => { dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None }) } - Ok(ast::LitKind::Int(_, _)) if !is_nested => { + Ok(LitKind::Int(_, _)) if !is_nested => { let sugg = - snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span: span, snippet }); + snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span, snippet }); dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg }) } - Ok(ast::LitKind::Int( - val, - ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), - )) => { + Ok(LitKind::Int(val, LitIntType::Unsuffixed | LitIntType::Unsigned(UintTy::U8))) => { assert!(val.get() > u8::MAX.into()); // must be an error dcx.emit_err(ConcatBytesOob { span }) } - Ok(ast::LitKind::Int(_, _)) => dcx.emit_err(ConcatBytesNonU8 { span }), - Ok(ast::LitKind::ByteStr(..) | ast::LitKind::Byte(_)) => unreachable!(), - Ok(ast::LitKind::Err(guar)) => guar, + Ok(LitKind::Int(_, _)) => dcx.emit_err(ConcatBytesNonU8 { span }), + Ok(LitKind::ByteStr(..) | LitKind::Byte(_)) => unreachable!(), + Ok(LitKind::Err(guar)) => guar, Err(err) => report_lit_error(&cx.sess.parse_sess, err, token_lit, span), } } @@ -68,7 +64,7 @@ fn invalid_type_err( /// Otherwise, returns `None`, and either pushes the `expr`'s span to `missing_literals` or /// updates `guar` accordingly. fn handle_array_element( - cx: &mut base::ExtCtxt<'_>, + cx: &mut ExtCtxt<'_>, guar: &mut Option, missing_literals: &mut Vec, expr: &P, @@ -76,16 +72,16 @@ fn handle_array_element( let dcx = cx.dcx(); match expr.kind { - ast::ExprKind::Lit(token_lit) => { - match ast::LitKind::from_token_lit(token_lit) { - Ok(ast::LitKind::Int( + ExprKind::Lit(token_lit) => { + match LitKind::from_token_lit(token_lit) { + Ok(LitKind::Int( val, - ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), + LitIntType::Unsuffixed | LitIntType::Unsigned(UintTy::U8), )) if let Ok(val) = u8::try_from(val.get()) => { return Some(val); } - Ok(ast::LitKind::Byte(val)) => return Some(val), - Ok(ast::LitKind::ByteStr(..)) => { + Ok(LitKind::Byte(val)) => return Some(val), + Ok(LitKind::ByteStr(..)) => { guar.get_or_insert_with(|| { dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: true }) }); @@ -95,12 +91,12 @@ fn handle_array_element( } }; } - ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => { + ExprKind::Array(_) | ExprKind::Repeat(_, _) => { guar.get_or_insert_with(|| { dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false }) }); } - ast::ExprKind::IncludedBytes(..) => { + ExprKind::IncludedBytes(..) => { guar.get_or_insert_with(|| { dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false }) }); @@ -112,11 +108,11 @@ fn handle_array_element( } pub fn expand_concat_bytes( - cx: &mut base::ExtCtxt<'_>, - sp: rustc_span::Span, + cx: &mut ExtCtxt<'_>, + sp: Span, tts: TokenStream, -) -> Box { - let es = match base::get_exprs_from_tts(cx, tts) { +) -> Box { + let es = match get_exprs_from_tts(cx, tts) { Ok(es) => es, Err(guar) => return DummyResult::any(sp, guar), }; @@ -125,7 +121,7 @@ pub fn expand_concat_bytes( let mut guar = None; for e in es { match &e.kind { - ast::ExprKind::Array(exprs) => { + ExprKind::Array(exprs) => { for expr in exprs { if let Some(elem) = handle_array_element(cx, &mut guar, &mut missing_literals, expr) @@ -134,10 +130,9 @@ pub fn expand_concat_bytes( } } } - ast::ExprKind::Repeat(expr, count) => { - if let ast::ExprKind::Lit(token_lit) = count.value.kind - && let Ok(ast::LitKind::Int(count_val, _)) = - ast::LitKind::from_token_lit(token_lit) + ExprKind::Repeat(expr, count) => { + if let ExprKind::Lit(token_lit) = count.value.kind + && let Ok(LitKind::Int(count_val, _)) = LitKind::from_token_lit(token_lit) { if let Some(elem) = handle_array_element(cx, &mut guar, &mut missing_literals, expr) @@ -152,24 +147,24 @@ pub fn expand_concat_bytes( ); } } - &ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) { - Ok(ast::LitKind::Byte(val)) => { + &ExprKind::Lit(token_lit) => match LitKind::from_token_lit(token_lit) { + Ok(LitKind::Byte(val)) => { accumulator.push(val); } - Ok(ast::LitKind::ByteStr(ref bytes, _)) => { + Ok(LitKind::ByteStr(ref bytes, _)) => { accumulator.extend_from_slice(bytes); } _ => { guar.get_or_insert_with(|| invalid_type_err(cx, token_lit, e.span, false)); } }, - ast::ExprKind::IncludedBytes(bytes) => { + ExprKind::IncludedBytes(bytes) => { accumulator.extend_from_slice(bytes); } - ast::ExprKind::Err(guarantee) => { + ExprKind::Err(guarantee) => { guar = Some(*guarantee); } - ast::ExprKind::Dummy => cx.dcx().span_bug(e.span, "concatenating `ExprKind::Dummy`"), + ExprKind::Dummy => cx.dcx().span_bug(e.span, "concatenating `ExprKind::Dummy`"), _ => { missing_literals.push(e.span); } @@ -177,10 +172,10 @@ pub fn expand_concat_bytes( } if !missing_literals.is_empty() { let guar = cx.dcx().emit_err(errors::ConcatBytesMissingLiteral { spans: missing_literals }); - return base::MacEager::expr(DummyResult::raw_expr(sp, Some(guar))); + return MacEager::expr(DummyResult::raw_expr(sp, Some(guar))); } else if let Some(guar) = guar { - return base::MacEager::expr(DummyResult::raw_expr(sp, Some(guar))); + return MacEager::expr(DummyResult::raw_expr(sp, Some(guar))); } let sp = cx.with_def_site_ctxt(sp); - base::MacEager::expr(cx.expr_byte_str(sp, accumulator)) + MacEager::expr(cx.expr_byte_str(sp, accumulator)) } diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs index 29d3f6164aa1..fffcddc5325b 100644 --- a/compiler/rustc_builtin_macros/src/concat_idents.rs +++ b/compiler/rustc_builtin_macros/src/concat_idents.rs @@ -1,8 +1,8 @@ -use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::token::{self, Token}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; -use rustc_expand::base::{self, *}; +use rustc_ast::{AttrVec, Expr, ExprKind, Path, Ty, TyKind, DUMMY_NODE_ID}; +use rustc_expand::base::{DummyResult, ExtCtxt, MacResult}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; @@ -12,7 +12,7 @@ pub fn expand_concat_idents<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { if tts.is_empty() { let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingArgs { span: sp }); return DummyResult::any(sp, guar); @@ -47,21 +47,21 @@ pub fn expand_concat_idents<'cx>( ident: Ident, } - impl base::MacResult for ConcatIdentsResult { - fn make_expr(self: Box) -> Option> { - Some(P(ast::Expr { - id: ast::DUMMY_NODE_ID, - kind: ast::ExprKind::Path(None, ast::Path::from_ident(self.ident)), + impl MacResult for ConcatIdentsResult { + fn make_expr(self: Box) -> Option> { + Some(P(Expr { + id: DUMMY_NODE_ID, + kind: ExprKind::Path(None, Path::from_ident(self.ident)), span: self.ident.span, - attrs: ast::AttrVec::new(), + attrs: AttrVec::new(), tokens: None, })) } - fn make_ty(self: Box) -> Option> { - Some(P(ast::Ty { - id: ast::DUMMY_NODE_ID, - kind: ast::TyKind::Path(None, ast::Path::from_ident(self.ident)), + fn make_ty(self: Box) -> Option> { + Some(P(Ty { + id: DUMMY_NODE_ID, + kind: TyKind::Path(None, Path::from_ident(self.ident)), span: self.ident.span, tokens: None, })) diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index 67ace546ad04..f057d44bf710 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -3,9 +3,13 @@ // interface. // +use rustc_ast::token::{self, LitKind}; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{self as ast, AstDeref, GenericArg}; -use rustc_expand::base::{self, *}; +use rustc_ast::{AstDeref, ExprKind, GenericArg, Mutability}; +use rustc_expand::base::{ + expr_to_string, get_exprs_from_tts, get_single_str_from_tts, DummyResult, ExtCtxt, MacEager, + MacResult, +}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; use std::env; @@ -27,7 +31,7 @@ pub fn expand_option_env<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let var = match get_single_str_from_tts(cx, sp, tts, "option_env!") { Ok(var) => var, Err(guar) => return DummyResult::any(sp, guar), @@ -47,7 +51,7 @@ pub fn expand_option_env<'cx>( sp, cx.ty_ident(sp, Ident::new(sym::str, sp)), Some(lt), - ast::Mutability::Not, + Mutability::Not, ))], )) } @@ -64,7 +68,7 @@ pub fn expand_env<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let mut exprs = match get_exprs_from_tts(cx, tts) { Ok(exprs) if exprs.is_empty() || exprs.len() > 2 => { let guar = cx.dcx().emit_err(errors::EnvTakesArgs { span: sp }); @@ -93,10 +97,8 @@ pub fn expand_env<'cx>( cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value)); let e = match value { None => { - let ast::ExprKind::Lit(ast::token::Lit { - kind: ast::token::LitKind::Str | ast::token::LitKind::StrRaw(..), - symbol, - .. + let ExprKind::Lit(token::Lit { + kind: LitKind::Str | LitKind::StrRaw(..), symbol, .. }) = &var_expr.kind else { unreachable!("`expr_to_string` ensures this is a string lit") diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 3860057e1d41..8e0978de2374 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -3,7 +3,10 @@ use rustc_ast::ptr::P; use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_ast_pretty::pprust; -use rustc_expand::base::{self, *}; +use rustc_expand::base::{ + check_zero_tts, get_single_str_from_tts, parse_expr, resolve_path, DummyResult, ExtCtxt, + MacEager, MacResult, +}; use rustc_expand::module::DirOwnership; use rustc_parse::new_parser_from_file; use rustc_parse::parser::{ForceCollect, Parser}; @@ -23,14 +26,14 @@ pub fn expand_line( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let sp = cx.with_def_site_ctxt(sp); - base::check_zero_tts(cx, sp, tts, "line!"); + check_zero_tts(cx, sp, tts, "line!"); let topmost = cx.expansion_cause().unwrap_or(sp); let loc = cx.source_map().lookup_char_pos(topmost.lo()); - base::MacEager::expr(cx.expr_u32(topmost, loc.line as u32)) + MacEager::expr(cx.expr_u32(topmost, loc.line as u32)) } /* column!(): expands to the current column number */ @@ -38,14 +41,14 @@ pub fn expand_column( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let sp = cx.with_def_site_ctxt(sp); - base::check_zero_tts(cx, sp, tts, "column!"); + check_zero_tts(cx, sp, tts, "column!"); let topmost = cx.expansion_cause().unwrap_or(sp); let loc = cx.source_map().lookup_char_pos(topmost.lo()); - base::MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32 + 1)) + MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32 + 1)) } /// file!(): expands to the current filename */ @@ -55,15 +58,15 @@ pub fn expand_file( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let sp = cx.with_def_site_ctxt(sp); - base::check_zero_tts(cx, sp, tts, "file!"); + check_zero_tts(cx, sp, tts, "file!"); let topmost = cx.expansion_cause().unwrap_or(sp); let loc = cx.source_map().lookup_char_pos(topmost.lo()); use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt}; - base::MacEager::expr(cx.expr_str( + MacEager::expr(cx.expr_str( topmost, Symbol::intern( &loc.file.name.for_scope(cx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(), @@ -75,23 +78,23 @@ pub fn expand_stringify( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let sp = cx.with_def_site_ctxt(sp); let s = pprust::tts_to_string(&tts); - base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&s))) + MacEager::expr(cx.expr_str(sp, Symbol::intern(&s))) } pub fn expand_mod( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let sp = cx.with_def_site_ctxt(sp); - base::check_zero_tts(cx, sp, tts, "module_path!"); + check_zero_tts(cx, sp, tts, "module_path!"); let mod_path = &cx.current_expansion.module.mod_path; let string = mod_path.iter().map(|x| x.to_string()).collect::>().join("::"); - base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&string))) + MacEager::expr(cx.expr_str(sp, Symbol::intern(&string))) } /// include! : parse the given file as an expr @@ -101,7 +104,7 @@ pub fn expand_include<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let sp = cx.with_def_site_ctxt(sp); let file = match get_single_str_from_tts(cx, sp, tts, "include!") { Ok(file) => file, @@ -129,9 +132,9 @@ pub fn expand_include<'cx>( p: Parser<'a>, node_id: ast::NodeId, } - impl<'a> base::MacResult for ExpandResult<'a> { + impl<'a> MacResult for ExpandResult<'a> { fn make_expr(mut self: Box>) -> Option> { - let expr = base::parse_expr(&mut self.p).ok()?; + let expr = parse_expr(&mut self.p).ok()?; if self.p.token != token::Eof { self.p.sess.buffer_lint( INCOMPLETE_INCLUDE, @@ -175,7 +178,7 @@ pub fn expand_include_str( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let sp = cx.with_def_site_ctxt(sp); let file = match get_single_str_from_tts(cx, sp, tts, "include_str!") { Ok(file) => file, @@ -192,7 +195,7 @@ pub fn expand_include_str( Ok(bytes) => match std::str::from_utf8(&bytes) { Ok(src) => { let interned_src = Symbol::intern(src); - base::MacEager::expr(cx.expr_str(sp, interned_src)) + MacEager::expr(cx.expr_str(sp, interned_src)) } Err(_) => { let guar = cx.dcx().span_err(sp, format!("{} wasn't a utf-8 file", file.display())); @@ -210,7 +213,7 @@ pub fn expand_include_bytes( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let sp = cx.with_def_site_ctxt(sp); let file = match get_single_str_from_tts(cx, sp, tts, "include_bytes!") { Ok(file) => file, @@ -226,7 +229,7 @@ pub fn expand_include_bytes( match cx.source_map().load_binary_file(&file) { Ok(bytes) => { let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes)); - base::MacEager::expr(expr) + MacEager::expr(expr) } Err(e) => { let guar = cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e)); From bf7d1b54e8a3195a0f52516d48659d9f1270436d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 26 Feb 2024 09:24:03 +1100 Subject: [PATCH 18/39] Move `emit_stashed_diagnostic` call in rustfmt. This call was added to `parse_crate_mod` in #121487, to fix a case where a stashed diagnostic wasn't emitted. But there is another path where a stashed diagnostic might fail to be emitted if there's a parse error, if the `build` call in `parse_crate_inner` fails before `parse_crate_mod` is reached. So this commit moves the `emit_stashed_diagnostic` call outwards, from `parse_crate_mod` to `format_project`, just after the `Parser::parse_crate` call. This should be far out enough to catch any parsing errors. Fixes #121517. --- src/tools/rustfmt/src/formatting.rs | 22 ++++++++++++++----- src/tools/rustfmt/src/parse/parser.rs | 16 ++++---------- src/tools/rustfmt/src/parse/session.rs | 6 ++++- src/tools/rustfmt/src/test/parser.rs | 7 ++++++ .../rustfmt/tests/parser/stashed-diag2.rs | 3 +++ 5 files changed, 35 insertions(+), 19 deletions(-) create mode 100644 src/tools/rustfmt/tests/parser/stashed-diag2.rs diff --git a/src/tools/rustfmt/src/formatting.rs b/src/tools/rustfmt/src/formatting.rs index cd57a025b672..323ae83fe6ed 100644 --- a/src/tools/rustfmt/src/formatting.rs +++ b/src/tools/rustfmt/src/formatting.rs @@ -109,7 +109,7 @@ fn format_project( let main_file = input.file_name(); let input_is_stdin = main_file == FileName::Stdin; - let parse_session = ParseSess::new(config)?; + let mut parse_session = ParseSess::new(config)?; if config.skip_children() && parse_session.ignore_file(&main_file) { return Ok(FormatReport::new()); } @@ -117,11 +117,21 @@ fn format_project( // Parse the crate. let mut report = FormatReport::new(); let directory_ownership = input.to_directory_ownership(); - let krate = match Parser::parse_crate(input, &parse_session) { - Ok(krate) => krate, - // Surface parse error via Session (errors are merged there from report) - Err(e) => { - let forbid_verbose = input_is_stdin || e != ParserError::ParsePanicError; + + // rustfmt doesn't use `run_compiler` like other tools, so it must emit any + // stashed diagnostics itself, otherwise the `DiagCtxt` will assert when + // dropped. The final result here combines the parsing result and the + // `emit_stashed_diagnostics` result. + let parse_res = Parser::parse_crate(input, &parse_session); + let stashed_res = parse_session.emit_stashed_diagnostics(); + let krate = match (parse_res, stashed_res) { + (Ok(krate), None) => krate, + (parse_res, _) => { + // Surface parse error via Session (errors are merged there from report). + let forbid_verbose = match parse_res { + Err(e) if e != ParserError::ParsePanicError => true, + _ => input_is_stdin, + }; should_emit_verbose(forbid_verbose, config, || { eprintln!("The Rust parser panicked"); }); diff --git a/src/tools/rustfmt/src/parse/parser.rs b/src/tools/rustfmt/src/parse/parser.rs index cca14353b5c1..3269fe7c7c70 100644 --- a/src/tools/rustfmt/src/parse/parser.rs +++ b/src/tools/rustfmt/src/parse/parser.rs @@ -162,22 +162,14 @@ impl<'a> Parser<'a> { fn parse_crate_mod(&mut self) -> Result { let mut parser = AssertUnwindSafe(&mut self.parser); - - // rustfmt doesn't use `run_compiler` like other tools, so it must emit - // any stashed diagnostics itself, otherwise the `DiagCtxt` will assert - // when dropped. The final result here combines the parsing result and - // the `emit_stashed_diagnostics` result. - let parse_res = catch_unwind(move || parser.parse_crate_mod()); - let stashed_res = self.parser.dcx().emit_stashed_diagnostics(); let err = Err(ParserError::ParsePanicError); - match (parse_res, stashed_res) { - (Ok(Ok(k)), None) => Ok(k), - (Ok(Ok(_)), Some(_guar)) => err, - (Ok(Err(db)), _) => { + match catch_unwind(move || parser.parse_crate_mod()) { + Ok(Ok(k)) => Ok(k), + Ok(Err(db)) => { db.emit(); err } - (Err(_), _) => err, + Err(_) => err, } } } diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index cff025cf2ab3..decd3b167e0a 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -6,7 +6,7 @@ use rustc_data_structures::sync::{IntoDynSyncSend, Lrc}; use rustc_errors::emitter::{DynEmitter, Emitter, HumanEmitter}; use rustc_errors::translation::Translate; use rustc_errors::{ - ColorConfig, DiagCtxt, Diagnostic, DiagnosticBuilder, Level as DiagnosticLevel, + ColorConfig, DiagCtxt, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, Level as DiagnosticLevel, }; use rustc_session::parse::ParseSess as RawParseSess; use rustc_span::{ @@ -230,6 +230,10 @@ impl ParseSess { self.ignore_path_set.as_ref().is_match(path) } + pub(crate) fn emit_stashed_diagnostics(&mut self) -> Option { + self.parse_sess.dcx.emit_stashed_diagnostics() + } + pub(crate) fn set_silent_emitter(&mut self) { self.parse_sess.dcx = DiagCtxt::with_emitter(silent_emitter()); } diff --git a/src/tools/rustfmt/src/test/parser.rs b/src/tools/rustfmt/src/test/parser.rs index da2a2ba62e00..d951c8469e66 100644 --- a/src/tools/rustfmt/src/test/parser.rs +++ b/src/tools/rustfmt/src/test/parser.rs @@ -62,3 +62,10 @@ fn crate_parsing_stashed_diag() { let filename = "tests/parser/stashed-diag.rs"; assert_parser_error(filename); } + +#[test] +fn crate_parsing_stashed_diag2() { + // See also https://github.com/rust-lang/rust/issues/121517 + let filename = "tests/parser/stashed-diag2.rs"; + assert_parser_error(filename); +} diff --git a/src/tools/rustfmt/tests/parser/stashed-diag2.rs b/src/tools/rustfmt/tests/parser/stashed-diag2.rs new file mode 100644 index 000000000000..579a69def163 --- /dev/null +++ b/src/tools/rustfmt/tests/parser/stashed-diag2.rs @@ -0,0 +1,3 @@ +trait Trait<'1> { s> {} + +fn main() {} From edda2a7d3e7e541097285c03c0a8f68ad9b2fbc4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 26 Feb 2024 08:40:51 +1100 Subject: [PATCH 19/39] Revert some `span_bug`s to `span_delayed_bug`. Fixes #121503. Fixes #121597. --- .../src/collect/resolve_bound_vars.rs | 2 +- compiler/rustc_hir_typeck/src/method/probe.rs | 3 +- .../trait-bounds/span-bug-issue-121597.rs | 20 ++++++++ .../trait-bounds/span-bug-issue-121597.stderr | 49 +++++++++++++++++++ .../could-not-resolve-issue-121503.rs | 13 +++++ .../could-not-resolve-issue-121503.stderr | 28 +++++++++++ 6 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.rs create mode 100644 tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr create mode 100644 tests/ui/lifetimes/could-not-resolve-issue-121503.rs create mode 100644 tests/ui/lifetimes/could-not-resolve-issue-121503.stderr diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index efde4e11c79d..22beac14b24d 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1331,7 +1331,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { } } - self.tcx.dcx().span_bug( + self.tcx.dcx().span_delayed_bug( lifetime_ref.ident.span, format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,), ); diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 7117a59c4098..bdc796aca3a4 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -804,10 +804,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let trait_ref = principal.with_self_ty(self.tcx, self_ty); self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| { if new_trait_ref.has_non_region_bound_vars() { - this.dcx().span_bug( + this.dcx().span_delayed_bug( this.span, "tried to select method from HRTB with non-lifetime bound vars", ); + return; } let new_trait_ref = this.instantiate_bound_regions_with_erased(new_trait_ref); diff --git a/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.rs b/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.rs new file mode 100644 index 000000000000..aeace9f2158a --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.rs @@ -0,0 +1,20 @@ +#![allow(incomplete_features)] +#![feature(non_lifetime_binders)] + +trait Foo: for Bar {} + +trait Bar { + fn method(&self) {} +} + +struct Type2; +fn needs_bar(_: *mut Type2) {} + +fn main() { + let x: &dyn Foo = &(); + //~^ ERROR the trait `Foo` cannot be made into an object + //~| ERROR the trait `Foo` cannot be made into an object + + needs_bar(x); + //~^ ERROR mismatched types +} diff --git a/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr b/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr new file mode 100644 index 000000000000..27f82563aae7 --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr @@ -0,0 +1,49 @@ +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/span-bug-issue-121597.rs:14:23 + | +LL | let x: &dyn Foo = &(); + | ^^^ `Foo` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/span-bug-issue-121597.rs:4:12 + | +LL | trait Foo: for Bar {} + | --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables + | | + | this trait cannot be made into an object... + = note: required for the cast from `&()` to `&dyn Foo` + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/span-bug-issue-121597.rs:14:12 + | +LL | let x: &dyn Foo = &(); + | ^^^^^^^^ `Foo` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/span-bug-issue-121597.rs:4:12 + | +LL | trait Foo: for Bar {} + | --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables + | | + | this trait cannot be made into an object... + +error[E0308]: mismatched types + --> $DIR/span-bug-issue-121597.rs:18:15 + | +LL | needs_bar(x); + | --------- ^ types differ in mutability + | | + | arguments to this function are incorrect + | + = note: expected raw pointer `*mut Type2` + found reference `&dyn Foo` +note: function defined here + --> $DIR/span-bug-issue-121597.rs:11:4 + | +LL | fn needs_bar(_: *mut Type2) {} + | ^^^^^^^^^ ------------- + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0038, E0308. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/lifetimes/could-not-resolve-issue-121503.rs b/tests/ui/lifetimes/could-not-resolve-issue-121503.rs new file mode 100644 index 000000000000..6bc70a907d9e --- /dev/null +++ b/tests/ui/lifetimes/could-not-resolve-issue-121503.rs @@ -0,0 +1,13 @@ +//@ edition:2018 + +#![feature(allocator_api)] +struct Struct; +impl Struct { + async fn box_ref_Struct(self: Box) -> &u32 { + //~^ ERROR the trait bound `impl FnMut(&mut Self): Allocator` is not satisfied + //~| ERROR Box` cannot be used as the type of `self` without + &1 + } +} + +fn main() {} diff --git a/tests/ui/lifetimes/could-not-resolve-issue-121503.stderr b/tests/ui/lifetimes/could-not-resolve-issue-121503.stderr new file mode 100644 index 000000000000..a5d8239a2df0 --- /dev/null +++ b/tests/ui/lifetimes/could-not-resolve-issue-121503.stderr @@ -0,0 +1,28 @@ +error[E0277]: the trait bound `impl FnMut(&mut Self): Allocator` is not satisfied + --> $DIR/could-not-resolve-issue-121503.rs:6:5 + | +LL | async fn box_ref_Struct(self: Box) -> &u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Allocator` is not implemented for `impl FnMut(&mut Self)` + | +note: required by a bound in `Box` + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL +help: consider further restricting this bound + | +LL | async fn box_ref_Struct(self: Box) -> &u32 { + | +++++++++++++++++++++++ + +error[E0658]: `Box` cannot be used as the type of `self` without the `arbitrary_self_types` feature + --> $DIR/could-not-resolve-issue-121503.rs:6:35 + | +LL | async fn box_ref_Struct(self: Box) -> &u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #44874 for more information + = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0658. +For more information about an error, try `rustc --explain E0277`. From 35421c74616e44e1001be852d9255a593195f66c Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 25 Feb 2024 22:28:30 -0300 Subject: [PATCH 20/39] Add synchronization library to run-make flags --- tests/run-make/tools.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-make/tools.mk b/tests/run-make/tools.mk index 1d4e91113892..b1e872a202af 100644 --- a/tests/run-make/tools.mk +++ b/tests/run-make/tools.mk @@ -134,9 +134,9 @@ endif # Extra flags needed to compile a working executable with the standard library ifdef IS_WINDOWS ifdef IS_MSVC - EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib ntdll.lib + EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib ntdll.lib synchronization.lib else - EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt -lntdll + EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt -lntdll -lsynchronization EXTRACXXFLAGS := -lstdc++ # So this is a bit hacky: we can't use the DLL version of libstdc++ because # it pulls in the DLL version of libgcc, which means that we end up with 2 From ff07f55db500dafb2d6570b5de7928bcc10a955f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 26 Feb 2024 01:36:08 +0000 Subject: [PATCH 21/39] Actually use the right closure kind when checking async Fn goals --- .../src/traits/select/confirmation.rs | 5 ++-- .../async-closures/wrong-fn-kind.rs | 8 ++++-- .../async-closures/wrong-fn-kind.stderr | 27 ++++++++++++++++--- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index f76be8769488..d316149731e1 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -934,7 +934,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { (trait_ref, Ty::from_closure_kind(tcx, ty::ClosureKind::Fn)) } ty::Closure(_, args) => { - let sig = args.as_closure().sig(); + let args = args.as_closure(); + let sig = args.sig(); let trait_ref = sig.map_bound(|sig| { ty::TraitRef::new( self.tcx(), @@ -950,7 +951,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::TraitRef::new(tcx, future_trait_def_id, [sig.output()]) }), )); - (trait_ref, Ty::from_closure_kind(tcx, ty::ClosureKind::Fn)) + (trait_ref, args.kind_ty()) } _ => bug!("expected callable type for AsyncFn candidate"), }; diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.rs b/tests/ui/async-await/async-closures/wrong-fn-kind.rs index 7c3c7337e2ef..8502bb6e2d45 100644 --- a/tests/ui/async-await/async-closures/wrong-fn-kind.rs +++ b/tests/ui/async-await/async-closures/wrong-fn-kind.rs @@ -1,7 +1,5 @@ //@ edition:2021 -// FIXME(async_closures): This needs a better error message! - #![feature(async_closure)] fn main() { @@ -12,4 +10,10 @@ fn main() { //~^ ERROR expected a closure that implements the `async Fn` trait, but this closure only implements `async FnMut` x += 1; }); + + let x = String::new(); + needs_async_fn(move || async move { + //~^ ERROR expected a closure that implements the `async Fn` trait, but this closure only implements `async FnOnce` + println!("{x}"); + }); } diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr index 34a6b3a485a6..d0f1948e48f8 100644 --- a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr +++ b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr @@ -1,5 +1,5 @@ error[E0525]: expected a closure that implements the `async Fn` trait, but this closure only implements `async FnMut` - --> $DIR/wrong-fn-kind.rs:11:20 + --> $DIR/wrong-fn-kind.rs:9:20 | LL | needs_async_fn(async || { | -------------- -^^^^^^^ @@ -14,11 +14,32 @@ LL | | }); | |_____- the requirement to implement `async Fn` derives from here | note: required by a bound in `needs_async_fn` - --> $DIR/wrong-fn-kind.rs:8:31 + --> $DIR/wrong-fn-kind.rs:6:31 | LL | fn needs_async_fn(_: impl async Fn()) {} | ^^^^^^^^^^ required by this bound in `needs_async_fn` -error: aborting due to 1 previous error +error[E0525]: expected a closure that implements the `async Fn` trait, but this closure only implements `async FnOnce` + --> $DIR/wrong-fn-kind.rs:15:20 + | +LL | needs_async_fn(move || async move { + | -------------- -^^^^^^ + | | | + | _____|______________this closure implements `async FnOnce`, not `async Fn` + | | | + | | required by a bound introduced by this call +LL | | +LL | | println!("{x}"); + | | - closure is `async FnOnce` because it moves the variable `x` out of its environment +LL | | }); + | |_____- the requirement to implement `async Fn` derives from here + | +note: required by a bound in `needs_async_fn` + --> $DIR/wrong-fn-kind.rs:6:31 + | +LL | fn needs_async_fn(_: impl async Fn()) {} + | ^^^^^^^^^^ required by this bound in `needs_async_fn` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0525`. From 8bccceb8fc588d60dd25e6f13beea69aa5fc6b63 Mon Sep 17 00:00:00 2001 From: "HTGAzureX1212." <39023054+HTGAzureX1212@users.noreply.github.com> Date: Fri, 9 Feb 2024 18:26:30 +0800 Subject: [PATCH 22/39] separate messages for individual categories --- compiler/rustc_lint/messages.ftl | 23 ++++++++- compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_lint/src/lints.rs | 2 + compiler/rustc_lint/src/non_ascii_idents.rs | 47 +++++++++++++++---- tests/ui/lexer/lex-emoji-identifiers.rs | 2 +- tests/ui/lexer/lex-emoji-identifiers.stderr | 3 +- .../lint-uncommon-codepoints.rs | 7 +-- .../lint-uncommon-codepoints.stderr | 13 +++-- 8 files changed, 79 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 785895e0ab82..c08ff0fef3c2 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -241,9 +241,28 @@ lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of lint_identifier_non_ascii_char = identifier contains non-ASCII characters lint_identifier_uncommon_codepoints = identifier contains {$codepoints_len -> - [one] an uncommon Unicode codepoint - *[other] uncommon Unicode codepoints + [one] { $identifier_type -> + [Exclusion] a character from an archaic script + [Technical] a character that is for non-linguistic, specialized usage + [Limited_Use] a character from a script in limited use + [Not_NFKC] a non normalized (NFKC) character + *[other] an uncommon character + } + *[other] { $identifier_type -> + [Exclusion] {$codepoints_len} characters from archaic scripts + [Technical] {$codepoints_len} characters that are for non-linguistic, specialized usage + [Limited_Use] {$codepoints_len} characters from scripts in limited use + [Not_NFKC] {$codepoints_len} non normalized (NFKC) characters + *[other] uncommon characters + } }: {$codepoints} + .note = {$codepoints_len -> + [one] this character is + *[other] these characters are + } included in the{$identifier_type -> + [Restricted] {""} + *[other] {" "}{$identifier_type} + } Unicode general security profile lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 85f9d3bd63ec..6c4e717faa6c 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -31,6 +31,7 @@ #![feature(array_windows)] #![feature(box_patterns)] #![feature(control_flow_enum)] +#![feature(extract_if)] #![feature(generic_nonzero)] #![feature(if_let_guard)] #![feature(iter_order_by)] diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index c204c67fc1f7..70d30611e8fc 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1098,9 +1098,11 @@ pub struct IdentifierNonAsciiChar; #[derive(LintDiagnostic)] #[diag(lint_identifier_uncommon_codepoints)] +#[note] pub struct IdentifierUncommonCodepoints { pub codepoints: Vec, pub codepoints_len: usize, + pub identifier_type: &'static str, } #[derive(LintDiagnostic)] diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs index e112cd6915c3..5e66ade03577 100644 --- a/compiler/rustc_lint/src/non_ascii_idents.rs +++ b/compiler/rustc_lint/src/non_ascii_idents.rs @@ -7,6 +7,7 @@ use rustc_ast as ast; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::UnordMap; use rustc_span::symbol::Symbol; +use unicode_security::general_security_profile::IdentifierType; declare_lint! { /// The `non_ascii_idents` lint detects non-ASCII identifiers. @@ -189,17 +190,47 @@ impl EarlyLintPass for NonAsciiIdents { if check_uncommon_codepoints && !symbol_str.chars().all(GeneralSecurityProfile::identifier_allowed) { - let codepoints: Vec<_> = symbol_str + let mut chars: Vec<_> = symbol_str .chars() - .filter(|c| !GeneralSecurityProfile::identifier_allowed(*c)) + .map(|c| (c, GeneralSecurityProfile::identifier_type(c))) .collect(); - let codepoints_len = codepoints.len(); - cx.emit_span_lint( - UNCOMMON_CODEPOINTS, - sp, - IdentifierUncommonCodepoints { codepoints, codepoints_len }, - ); + for (id_ty, id_ty_descr) in [ + (IdentifierType::Exclusion, "Exclusion"), + (IdentifierType::Technical, "Technical"), + (IdentifierType::Limited_Use, "Limited_Use"), + (IdentifierType::Not_NFKC, "Not_NFKC"), + ] { + let codepoints: Vec<_> = + chars.extract_if(|(_, ty)| *ty == Some(id_ty)).collect(); + if codepoints.is_empty() { + continue; + } + cx.emit_span_lint( + UNCOMMON_CODEPOINTS, + sp, + IdentifierUncommonCodepoints { + codepoints_len: codepoints.len(), + codepoints: codepoints.into_iter().map(|(c, _)| c).collect(), + identifier_type: id_ty_descr, + }, + ); + } + + let remaining = chars + .extract_if(|(c, _)| !GeneralSecurityProfile::identifier_allowed(*c)) + .collect::>(); + if !remaining.is_empty() { + cx.emit_span_lint( + UNCOMMON_CODEPOINTS, + sp, + IdentifierUncommonCodepoints { + codepoints_len: remaining.len(), + codepoints: remaining.into_iter().map(|(c, _)| c).collect(), + identifier_type: "Restricted", + }, + ); + } } } diff --git a/tests/ui/lexer/lex-emoji-identifiers.rs b/tests/ui/lexer/lex-emoji-identifiers.rs index bbc088521b7b..4fcd102018be 100644 --- a/tests/ui/lexer/lex-emoji-identifiers.rs +++ b/tests/ui/lexer/lex-emoji-identifiers.rs @@ -4,7 +4,7 @@ fn invalid_emoji_usages() { let wireless🛜 = "basic emoji"; //~ ERROR: identifiers cannot contain emoji // FIXME let key1️⃣ = "keycap sequence"; //~ ERROR: unknown start of token - //~^ WARN: identifier contains an uncommon Unicode codepoint + //~^ WARN: identifier contains an uncommon character: '\u{fe0f}' let flag🇺🇳 = "flag sequence"; //~ ERROR: identifiers cannot contain emoji let wales🏴 = "tag sequence"; //~ ERROR: identifiers cannot contain emoji let folded🙏🏿 = "modifier sequence"; //~ ERROR: identifiers cannot contain emoji diff --git a/tests/ui/lexer/lex-emoji-identifiers.stderr b/tests/ui/lexer/lex-emoji-identifiers.stderr index 679b7422bc15..8e2daa6d1d38 100644 --- a/tests/ui/lexer/lex-emoji-identifiers.stderr +++ b/tests/ui/lexer/lex-emoji-identifiers.stderr @@ -40,12 +40,13 @@ error: identifiers cannot contain emoji: `folded🙏🏿` LL | let folded🙏🏿 = "modifier sequence"; | ^^^^^^^^^^ -warning: identifier contains an uncommon Unicode codepoint: '\u{fe0f}' +warning: identifier contains an uncommon character: '\u{fe0f}' --> $DIR/lex-emoji-identifiers.rs:6:9 | LL | let key1️⃣ = "keycap sequence"; | ^^^^ | + = note: this character is included in the Unicode general security profile = note: `#[warn(uncommon_codepoints)]` on by default error: aborting due to 7 previous errors; 1 warning emitted diff --git a/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.rs b/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.rs index c3459930a94c..a51452f06959 100644 --- a/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.rs +++ b/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.rs @@ -1,12 +1,13 @@ #![deny(uncommon_codepoints)] -const µ: f64 = 0.000001; //~ ERROR identifier contains an uncommon Unicode codepoint +const µ: f64 = 0.000001; //~ identifier contains a non normalized (NFKC) character: 'µ' //~| WARNING should have an upper case name -fn dijkstra() {} //~ ERROR identifier contains an uncommon Unicode codepoint +fn dijkstra() {} +//~^ ERROR identifier contains a non normalized (NFKC) character: 'ij' fn main() { - let ㇻㇲㇳ = "rust"; //~ ERROR identifier contains uncommon Unicode codepoints + let ㇻㇲㇳ = "rust"; //~ ERROR identifier contains uncommon characters: 'ㇻ', 'ㇲ', and 'ㇳ' // using the same identifier the second time won't trigger the lint. println!("{}", ㇻㇲㇳ); diff --git a/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.stderr b/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.stderr index bae5ac654d35..000545a06007 100644 --- a/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.stderr +++ b/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.stderr @@ -1,26 +1,31 @@ -error: identifier contains an uncommon Unicode codepoint: 'µ' +error: identifier contains a non normalized (NFKC) character: 'µ' --> $DIR/lint-uncommon-codepoints.rs:3:7 | LL | const µ: f64 = 0.000001; | ^ | + = note: this character is included in the Not_NFKC Unicode general security profile note: the lint level is defined here --> $DIR/lint-uncommon-codepoints.rs:1:9 | LL | #![deny(uncommon_codepoints)] | ^^^^^^^^^^^^^^^^^^^ -error: identifier contains an uncommon Unicode codepoint: 'ij' +error: identifier contains a non normalized (NFKC) character: 'ij' --> $DIR/lint-uncommon-codepoints.rs:6:4 | LL | fn dijkstra() {} | ^^^^^^^ + | + = note: this character is included in the Not_NFKC Unicode general security profile -error: identifier contains uncommon Unicode codepoints: 'ㇻ', 'ㇲ', and 'ㇳ' - --> $DIR/lint-uncommon-codepoints.rs:9:9 +error: identifier contains uncommon characters: 'ㇻ', 'ㇲ', and 'ㇳ' + --> $DIR/lint-uncommon-codepoints.rs:10:9 | LL | let ㇻㇲㇳ = "rust"; | ^^^^^^ + | + = note: these characters are included in the Unicode general security profile warning: constant `µ` should have an upper case name --> $DIR/lint-uncommon-codepoints.rs:3:7 From eeeb9b4d3148b9153a872fa61f29c9fb3efa5a64 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 26 Feb 2024 10:12:40 +0100 Subject: [PATCH 23/39] add additional logging --- compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 1 + compiler/rustc_trait_selection/src/solve/assembly/mod.rs | 7 ++++++- compiler/rustc_trait_selection/src/solve/mod.rs | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 7d448820cebe..cc591fcf8c47 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1516,6 +1516,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// In case there is still ambiguity, the returned type may be an inference /// variable. This is different from `structurally_resolve_type` which errors /// in this case. + #[instrument(level = "debug", skip(self, sp), ret)] pub fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { let ty = self.resolve_vars_with_obligations(ty); diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 8e66b1d580f9..4c4cd2af779b 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -777,6 +777,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // FIXME(@lcnr): The current structure here makes me unhappy and feels ugly. idk how // to improve this however. However, this should make it fairly straightforward to refine // the filtering going forward, so it seems alright-ish for now. + #[instrument(level = "debug", skip(self, goal))] fn discard_impls_shadowed_by_env>( &mut self, goal: Goal<'tcx, G>, @@ -799,7 +800,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // This feels dangerous. Certainty::Yes => { candidates.retain(|c| match c.source { - CandidateSource::Impl(_) | CandidateSource::BuiltinImpl(_) => false, + CandidateSource::Impl(_) | CandidateSource::BuiltinImpl(_) => { + debug!(?c, "discard impl candidate"); + false + } CandidateSource::ParamEnv(_) | CandidateSource::AliasBound => true, }); } @@ -807,6 +811,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // to be ambig and wait for inference constraints. See // tests/ui/traits/next-solver/env-shadows-impls/ambig-env-no-shadow.rs Certainty::Maybe(cause) => { + debug!(?cause, "force ambiguity"); *candidates = self.forced_ambiguity(cause); } } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 8b163d47d347..51094b781c0c 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -267,6 +267,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// This function is necessary in nearly all cases before matching on a type. /// Not doing so is likely to be incomplete and therefore unsound during /// coherence. + #[instrument(level = "debug", skip(self, param_env), ret)] fn structurally_normalize_ty( &mut self, param_env: ty::ParamEnv<'tcx>, From 1b3164f5c9098c239bc23b3bfea657cc27ff80c7 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 26 Feb 2024 10:17:43 +0100 Subject: [PATCH 24/39] always emit `AliasRelate` goals when relating aliases Add `StructurallyRelateAliases` to allow instantiating infer vars with rigid aliases. Change `instantiate_query_response` to be infallible in the new solver. This requires canonicalization to not hide any information used by the query, so weaken universe compression. It also modifies `term_is_fully_unconstrained` to allow region inference variables in a higher universe. --- .../src/type_check/relate_tys.rs | 7 +- compiler/rustc_infer/src/infer/at.rs | 18 ++- compiler/rustc_infer/src/infer/mod.rs | 1 + .../rustc_infer/src/infer/relate/combine.rs | 54 +++++-- .../rustc_infer/src/infer/relate/equate.rs | 13 +- .../src/infer/relate/generalize.rs | 53 ++++++- compiler/rustc_infer/src/infer/relate/glb.rs | 9 +- compiler/rustc_infer/src/infer/relate/lub.rs | 9 +- compiler/rustc_infer/src/infer/relate/mod.rs | 12 ++ compiler/rustc_infer/src/infer/relate/sub.rs | 9 +- .../rustc_middle/src/traits/solve/inspect.rs | 2 - .../src/traits/solve/inspect/format.rs | 15 +- .../src/canonicalizer.rs | 38 ++++- .../src/solve/alias_relate.rs | 67 +++++--- .../src/solve/eval_ctxt/canonical.rs | 74 ++++----- .../src/solve/eval_ctxt/mod.rs | 145 ++++++++++-------- .../src/solve/eval_ctxt/select.rs | 57 +++---- .../src/solve/fulfill.rs | 25 +-- .../src/solve/inspect/analyse.rs | 13 +- .../src/solve/inspect/build.rs | 14 -- .../src/solve/normalizes_to/mod.rs | 54 +++++-- 21 files changed, 417 insertions(+), 272 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 61b803ea38d4..00296aa38daa 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -1,7 +1,8 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::{NllRegionVariableOrigin, ObligationEmittingRelation}; +use rustc_infer::infer::NllRegionVariableOrigin; +use rustc_infer::infer::{ObligationEmittingRelation, StructurallyRelateAliases}; use rustc_infer::traits::{Obligation, PredicateObligations}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::query::NoSolution; @@ -548,6 +549,10 @@ impl<'bccx, 'tcx> ObligationEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx self.locations.span(self.type_checker.body) } + fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { + StructurallyRelateAliases::No + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.type_checker.param_env } diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 05b9479c7b06..cc09a0946886 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -302,7 +302,23 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { let Trace { at, trace, a_is_expected } = self; let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types); fields - .equate(a_is_expected) + .equate(StructurallyRelateAliases::No, a_is_expected) + .relate(a, b) + .map(move |_| InferOk { value: (), obligations: fields.obligations }) + } + + /// Equates `a` and `b` while structurally relating aliases. This should only + /// be used inside of the next generation trait solver when relating rigid aliases. + #[instrument(skip(self), level = "debug")] + pub fn eq_structurally_relating_aliases(self, a: T, b: T) -> InferResult<'tcx, ()> + where + T: Relate<'tcx>, + { + let Trace { at, trace, a_is_expected } = self; + debug_assert!(at.infcx.next_trait_solver()); + let mut fields = at.infcx.combine_fields(trace, at.param_env, DefineOpaqueTypes::No); + fields + .equate(StructurallyRelateAliases::Yes, a_is_expected) .relate(a, b) .map(move |_| InferOk { value: (), obligations: fields.obligations }) } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index c30f42c1656e..89dbc36906d1 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -54,6 +54,7 @@ use self::region_constraints::{ RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot, }; pub use self::relate::combine::CombineFields; +pub use self::relate::StructurallyRelateAliases; use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; pub mod at; diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index f7690831c2ac..0852bb4f993b 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -26,6 +26,7 @@ use super::equate::Equate; use super::glb::Glb; use super::lub::Lub; use super::sub::Sub; +use super::StructurallyRelateAliases; use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace}; use crate::traits::{Obligation, PredicateObligations}; use rustc_middle::infer::canonical::OriginalQueryValues; @@ -116,8 +117,15 @@ impl<'tcx> InferCtxt<'tcx> { } (_, ty::Alias(..)) | (ty::Alias(..), _) if self.next_trait_solver() => { - relation.register_type_relate_obligation(a, b); - Ok(a) + match relation.structurally_relate_aliases() { + StructurallyRelateAliases::Yes => { + ty::relate::structurally_relate_tys(relation, a, b) + } + StructurallyRelateAliases::No => { + relation.register_type_relate_obligation(a, b); + Ok(a) + } + } } // All other cases of inference are errors @@ -240,19 +248,26 @@ impl<'tcx> InferCtxt<'tcx> { (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..)) if self.tcx.features().generic_const_exprs || self.next_trait_solver() => { - let (a, b) = if relation.a_is_expected() { (a, b) } else { (b, a) }; + match relation.structurally_relate_aliases() { + StructurallyRelateAliases::No => { + let (a, b) = if relation.a_is_expected() { (a, b) } else { (b, a) }; - relation.register_predicates([if self.next_trait_solver() { - ty::PredicateKind::AliasRelate( - a.into(), - b.into(), - ty::AliasRelationDirection::Equate, - ) - } else { - ty::PredicateKind::ConstEquate(a, b) - }]); + relation.register_predicates([if self.next_trait_solver() { + ty::PredicateKind::AliasRelate( + a.into(), + b.into(), + ty::AliasRelationDirection::Equate, + ) + } else { + ty::PredicateKind::ConstEquate(a, b) + }]); - Ok(b) + Ok(b) + } + StructurallyRelateAliases::Yes => { + ty::relate::structurally_relate_consts(relation, a, b) + } + } } _ => ty::relate::structurally_relate_consts(relation, a, b), } @@ -303,8 +318,12 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { self.infcx.tcx } - pub fn equate<'a>(&'a mut self, a_is_expected: bool) -> Equate<'a, 'infcx, 'tcx> { - Equate::new(self, a_is_expected) + pub fn equate<'a>( + &'a mut self, + structurally_relate_aliases: StructurallyRelateAliases, + a_is_expected: bool, + ) -> Equate<'a, 'infcx, 'tcx> { + Equate::new(self, structurally_relate_aliases, a_is_expected) } pub fn sub<'a>(&'a mut self, a_is_expected: bool) -> Sub<'a, 'infcx, 'tcx> { @@ -335,6 +354,11 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> { fn param_env(&self) -> ty::ParamEnv<'tcx>; + /// Whether aliases should be related structurally. This is pretty much + /// always `No` unless you're equating in some specific locations of the + /// new solver. See the comments in these use-cases for more details. + fn structurally_relate_aliases(&self) -> StructurallyRelateAliases; + /// Register obligations that must hold in order for this relation to hold fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>); diff --git a/compiler/rustc_infer/src/infer/relate/equate.rs b/compiler/rustc_infer/src/infer/relate/equate.rs index aefa9a5a0d61..43d6aef3e153 100644 --- a/compiler/rustc_infer/src/infer/relate/equate.rs +++ b/compiler/rustc_infer/src/infer/relate/equate.rs @@ -1,4 +1,5 @@ use super::combine::{CombineFields, ObligationEmittingRelation}; +use super::StructurallyRelateAliases; use crate::infer::{DefineOpaqueTypes, SubregionOrigin}; use crate::traits::PredicateObligations; @@ -13,15 +14,17 @@ use rustc_span::Span; /// Ensures `a` is made equal to `b`. Returns `a` on success. pub struct Equate<'combine, 'infcx, 'tcx> { fields: &'combine mut CombineFields<'infcx, 'tcx>, + structurally_relate_aliases: StructurallyRelateAliases, a_is_expected: bool, } impl<'combine, 'infcx, 'tcx> Equate<'combine, 'infcx, 'tcx> { pub fn new( fields: &'combine mut CombineFields<'infcx, 'tcx>, + structurally_relate_aliases: StructurallyRelateAliases, a_is_expected: bool, ) -> Equate<'combine, 'infcx, 'tcx> { - Equate { fields, a_is_expected } + Equate { fields, structurally_relate_aliases, a_is_expected } } } @@ -99,7 +102,7 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), ) if a_def_id == b_def_id => { - self.fields.infcx.super_combine_tys(self, a, b)?; + infcx.super_combine_tys(self, a, b)?; } (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) @@ -120,7 +123,7 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { ); } _ => { - self.fields.infcx.super_combine_tys(self, a, b)?; + infcx.super_combine_tys(self, a, b)?; } } @@ -180,6 +183,10 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Equate<'_, '_, 'tcx> { self.fields.trace.span() } + fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { + self.structurally_relate_aliases + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env } diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 2e1ea19078cd..e84d4ceaea89 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -1,5 +1,6 @@ use std::mem; +use super::StructurallyRelateAliases; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind, TypeVariableValue}; use crate::infer::{InferCtxt, ObligationEmittingRelation, RegionVariableOrigin}; use rustc_data_structures::sso::SsoHashMap; @@ -45,8 +46,14 @@ impl<'tcx> InferCtxt<'tcx> { // region/type inference variables. // // We then relate `generalized_ty <: source_ty`,adding constraints like `'x: '?2` and `?1 <: ?3`. - let Generalization { value_may_be_infer: generalized_ty, has_unconstrained_ty_var } = - self.generalize(relation.span(), target_vid, instantiation_variance, source_ty)?; + let Generalization { value_may_be_infer: generalized_ty, has_unconstrained_ty_var } = self + .generalize( + relation.span(), + relation.structurally_relate_aliases(), + target_vid, + instantiation_variance, + source_ty, + )?; // Constrain `b_vid` to the generalized type `generalized_ty`. if let &ty::Infer(ty::TyVar(generalized_vid)) = generalized_ty.kind() { @@ -178,8 +185,14 @@ impl<'tcx> InferCtxt<'tcx> { ) -> RelateResult<'tcx, ()> { // FIXME(generic_const_exprs): Occurs check failures for unevaluated // constants and generic expressions are not yet handled correctly. - let Generalization { value_may_be_infer: generalized_ct, has_unconstrained_ty_var } = - self.generalize(relation.span(), target_vid, ty::Variance::Invariant, source_ct)?; + let Generalization { value_may_be_infer: generalized_ct, has_unconstrained_ty_var } = self + .generalize( + relation.span(), + relation.structurally_relate_aliases(), + target_vid, + ty::Variance::Invariant, + source_ct, + )?; debug_assert!(!generalized_ct.is_ct_infer()); if has_unconstrained_ty_var { @@ -217,6 +230,7 @@ impl<'tcx> InferCtxt<'tcx> { fn generalize> + Relate<'tcx>>( &self, span: Span, + structurally_relate_aliases: StructurallyRelateAliases, target_vid: impl Into, ambient_variance: ty::Variance, source_term: T, @@ -237,6 +251,7 @@ impl<'tcx> InferCtxt<'tcx> { let mut generalizer = Generalizer { infcx: self, span, + structurally_relate_aliases, root_vid, for_universe, ambient_variance, @@ -270,6 +285,10 @@ struct Generalizer<'me, 'tcx> { span: Span, + /// Whether aliases should be related structurally. If not, we have to + /// be careful when generalizing aliases. + structurally_relate_aliases: StructurallyRelateAliases, + /// The vid of the type variable that is in the process of being /// instantiated. If we find this within the value we are folding, /// that means we would have created a cyclic value. @@ -314,13 +333,30 @@ impl<'tcx> Generalizer<'_, 'tcx> { /// to normalize the alias after all. /// /// We handle this by lazily equating the alias and generalizing - /// it to an inference variable. + /// it to an inference variable. In the new solver, we always + /// generalize to an infer var unless the alias contains escaping + /// bound variables. /// - /// This is incomplete and will hopefully soon get fixed by #119106. + /// Correctly handling aliases with escaping bound variables is + /// difficult and currently incomplete in two opposite ways: + /// - if we get an occurs check failure in the alias, replace it with a new infer var. + /// This causes us to later emit an alias-relate goal and is incomplete in case the + /// alias normalizes to type containing one of the bound variables. + /// - if the alias contains an inference variable not nameable by `for_universe`, we + /// continue generalizing the alias. This ends up pulling down the universe of the + /// inference variable and is incomplete in case the alias would normalize to a type + /// which does not mention that inference variable. fn generalize_alias_ty( &mut self, alias: ty::AliasTy<'tcx>, ) -> Result, TypeError<'tcx>> { + if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() { + return Ok(self.infcx.next_ty_var_in_universe( + TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span: self.span }, + self.for_universe, + )); + } + let is_nested_alias = mem::replace(&mut self.in_alias, true); let result = match self.relate(alias, alias) { Ok(alias) => Ok(alias.to_ty(self.tcx())), @@ -490,7 +526,10 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { } } - ty::Alias(_, data) => self.generalize_alias_ty(data), + ty::Alias(_, data) => match self.structurally_relate_aliases { + StructurallyRelateAliases::No => self.generalize_alias_ty(data), + StructurallyRelateAliases::Yes => relate::structurally_relate_tys(self, t, t), + }, _ => relate::structurally_relate_tys(self, t, t), }?; diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs index 6cf513545996..52a2f4c73470 100644 --- a/compiler/rustc_infer/src/infer/relate/glb.rs +++ b/compiler/rustc_infer/src/infer/relate/glb.rs @@ -6,6 +6,7 @@ use rustc_span::Span; use super::combine::{CombineFields, ObligationEmittingRelation}; use super::lattice::{self, LatticeDir}; +use super::StructurallyRelateAliases; use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; use crate::traits::{ObligationCause, PredicateObligations}; @@ -45,7 +46,9 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { b: T, ) -> RelateResult<'tcx, T> { match variance { - ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), + ty::Invariant => { + self.fields.equate(StructurallyRelateAliases::No, self.a_is_expected).relate(a, b) + } ty::Covariant => self.relate(a, b), // FIXME(#41044) -- not correct, need test ty::Bivariant => Ok(a), @@ -139,6 +142,10 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> { self.fields.trace.span() } + fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { + StructurallyRelateAliases::No + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env } diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs index 5b4f80fd73a0..fa0da64ca65a 100644 --- a/compiler/rustc_infer/src/infer/relate/lub.rs +++ b/compiler/rustc_infer/src/infer/relate/lub.rs @@ -2,6 +2,7 @@ use super::combine::{CombineFields, ObligationEmittingRelation}; use super::lattice::{self, LatticeDir}; +use super::StructurallyRelateAliases; use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; use crate::traits::{ObligationCause, PredicateObligations}; @@ -45,7 +46,9 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { b: T, ) -> RelateResult<'tcx, T> { match variance { - ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), + ty::Invariant => { + self.fields.equate(StructurallyRelateAliases::No, self.a_is_expected).relate(a, b) + } ty::Covariant => self.relate(a, b), // FIXME(#41044) -- not correct, need test ty::Bivariant => Ok(a), @@ -139,6 +142,10 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> { self.fields.trace.span() } + fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { + StructurallyRelateAliases::No + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env } diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs index 1207377e8571..8619cc502ad2 100644 --- a/compiler/rustc_infer/src/infer/relate/mod.rs +++ b/compiler/rustc_infer/src/infer/relate/mod.rs @@ -9,3 +9,15 @@ mod higher_ranked; mod lattice; mod lub; mod sub; + +/// Whether aliases should be related structurally or not. Used +/// to adjust the behavior of generalization and combine. +/// +/// This should always be `No` unless in a few special-cases when +/// instantiating canonical responses and in the new solver. Each +/// such case should have a comment explaining why it is used. +#[derive(Debug, Copy, Clone)] +pub enum StructurallyRelateAliases { + Yes, + No, +} diff --git a/compiler/rustc_infer/src/infer/relate/sub.rs b/compiler/rustc_infer/src/infer/relate/sub.rs index 5bd3a238a67e..2cc8d0d3b10b 100644 --- a/compiler/rustc_infer/src/infer/relate/sub.rs +++ b/compiler/rustc_infer/src/infer/relate/sub.rs @@ -1,4 +1,5 @@ use super::combine::CombineFields; +use super::StructurallyRelateAliases; use crate::infer::{DefineOpaqueTypes, ObligationEmittingRelation, SubregionOrigin}; use crate::traits::{Obligation, PredicateObligations}; @@ -64,7 +65,9 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { b: T, ) -> RelateResult<'tcx, T> { match variance { - ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), + ty::Invariant => { + self.fields.equate(StructurallyRelateAliases::No, self.a_is_expected).relate(a, b) + } ty::Covariant => self.relate(a, b), ty::Bivariant => Ok(a), ty::Contravariant => self.with_expected_switched(|this| this.relate(b, a)), @@ -204,6 +207,10 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Sub<'_, '_, 'tcx> { self.fields.trace.span() } + fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { + StructurallyRelateAliases::No + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env } diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs index e94ad4aa539b..90180af3b167 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect.rs @@ -58,8 +58,6 @@ pub struct GoalEvaluation<'tcx> { pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>, pub kind: GoalEvaluationKind<'tcx>, pub evaluation: CanonicalGoalEvaluation<'tcx>, - /// The nested goals from instantiating the query response. - pub returned_goals: Vec>>, } #[derive(Eq, PartialEq)] diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs index 54db8dbd3360..89c5eb517e56 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs @@ -48,20 +48,7 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { }, }; writeln!(self.f, "{}: {:?}", goal_text, eval.uncanonicalized_goal)?; - self.nested(|this| this.format_canonical_goal_evaluation(&eval.evaluation))?; - if eval.returned_goals.len() > 0 { - writeln!(self.f, "NESTED GOALS ADDED TO CALLER: [")?; - self.nested(|this| { - for goal in eval.returned_goals.iter() { - writeln!(this.f, "ADDED GOAL: {goal:?},")?; - } - Ok(()) - })?; - - writeln!(self.f, "]") - } else { - Ok(()) - } + self.nested(|this| this.format_canonical_goal_evaluation(&eval.evaluation)) } pub(super) fn format_canonical_goal_evaluation( diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index cd434fecce2c..7b73e2aebf03 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -108,21 +108,22 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> Canonicalizer<'a, Infc // universes `n`, this algorithm compresses them in place so that: // // - the new universe indices are as small as possible - // - we only create a new universe if we would otherwise put a placeholder in - // the same compressed universe as an existential which cannot name it + // - we create a new universe if we would otherwise + // 1. put existentials from a different universe into the same one + // 2. put a placeholder in the same universe as an existential which cannot name it // // Let's walk through an example: // - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 0 // - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 1 // - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 1, next_orig_uv: 2 // - var_infos: [E0, U1, E5, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 5 - // - var_infos: [E0, U1, E1, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 6 - // - var_infos: [E0, U1, E1, U1, E1, E2, U2], curr_compressed_uv: 2, next_orig_uv: - + // - var_infos: [E0, U1, E2, U1, E1, E6, U6], curr_compressed_uv: 2, next_orig_uv: 6 + // - var_infos: [E0, U1, E1, U1, E1, E3, U3], curr_compressed_uv: 2, next_orig_uv: - // // This algorithm runs in `O(n²)` where `n` is the number of different universe // indices in the input. This should be fine as `n` is expected to be small. let mut curr_compressed_uv = ty::UniverseIndex::ROOT; - let mut existential_in_new_uv = false; + let mut existential_in_new_uv = None; let mut next_orig_uv = Some(ty::UniverseIndex::ROOT); while let Some(orig_uv) = next_orig_uv.take() { let mut update_uv = |var: &mut CanonicalVarInfo, orig_uv, is_existential| { @@ -131,14 +132,29 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> Canonicalizer<'a, Infc Ordering::Less => (), // Already updated Ordering::Equal => { if is_existential { - existential_in_new_uv = true; - } else if existential_in_new_uv { + if existential_in_new_uv.is_some_and(|uv| uv < orig_uv) { + // Condition 1. + // + // We already put an existential from a outer universe + // into the current compressed universe, so we need to + // create a new one. + curr_compressed_uv = curr_compressed_uv.next_universe(); + } + + // `curr_compressed_uv` will now contain an existential from + // `orig_uv`. Trying to canonicalizing an existential from + // a higher universe has to therefore use a new compressed + // universe. + existential_in_new_uv = Some(orig_uv); + } else if existential_in_new_uv.is_some() { + // Condition 2. + // // `var` is a placeholder from a universe which is not nameable // by an existential which we already put into the compressed // universe `curr_compressed_uv`. We therefore have to create a // new universe for `var`. curr_compressed_uv = curr_compressed_uv.next_universe(); - existential_in_new_uv = false; + existential_in_new_uv = None; } *var = var.with_updated_universe(curr_compressed_uv); @@ -174,8 +190,14 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> Canonicalizer<'a, Infc } } + // We uniquify regions and always put them into their own universe + let mut first_region = true; for var in var_infos.iter_mut() { if var.is_region() { + if first_region { + first_region = false; + curr_compressed_uv = curr_compressed_uv.next_universe(); + } assert!(var.is_existential()); *var = var.with_updated_universe(curr_compressed_uv); } diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs index 81be5c091644..afd9d95cb570 100644 --- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs +++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs @@ -8,8 +8,9 @@ //! //! (1.) If we end up with two rigid aliases, then we relate them structurally. //! -//! (2.) If we end up with an infer var and a rigid alias, then -//! we assign the alias to the infer var. +//! (2.) If we end up with an infer var and a rigid alias, then we instantiate +//! the infer var with the constructor of the alias and then recursively relate +//! the terms. //! //! (3.) Otherwise, if we end with two rigid (non-projection) or infer types, //! relate them structurally. @@ -53,22 +54,15 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } - (Some(_), None) => { - if rhs.is_infer() { - self.relate(param_env, lhs, variance, rhs)?; - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } else { - Err(NoSolution) - } - } - (None, Some(_)) => { - if lhs.is_infer() { - self.relate(param_env, lhs, variance, rhs)?; - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } else { - Err(NoSolution) - } + (Some(alias), None) => { + self.relate_rigid_alias_non_alias(param_env, alias, variance, rhs) } + (None, Some(alias)) => self.relate_rigid_alias_non_alias( + param_env, + alias, + variance.xform(ty::Variance::Contravariant), + lhs, + ), (Some(alias_lhs), Some(alias_rhs)) => { self.relate(param_env, alias_lhs, variance, alias_rhs)?; @@ -77,6 +71,39 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } + /// Relate a rigid alias with another type. This is the same as + /// an ordinary relate except that we treat the outer most alias + /// constructor as rigid. + #[instrument(level = "debug", skip(self, param_env), ret)] + fn relate_rigid_alias_non_alias( + &mut self, + param_env: ty::ParamEnv<'tcx>, + alias: ty::AliasTy<'tcx>, + variance: ty::Variance, + term: ty::Term<'tcx>, + ) -> QueryResult<'tcx> { + // NOTE: this check is purely an optimization, the structural eq would + // always fail if the term is not an inference variable. + if term.is_infer() { + let tcx = self.tcx(); + // We need to relate `alias` to `term` treating only the outermost + // constructor as rigid, relating any contained generic arguments as + // normal. We do this by first structurally equating the `term` + // with the alias constructor instantiated with unconstrained infer vars, + // and then relate this with the whole `alias`. + // + // Alternatively we could modify `Equate` for this case by adding another + // variant to `StructurallyRelateAliases`. + let identity_args = self.fresh_args_for_item(alias.def_id); + let rigid_ctor = ty::AliasTy::new(tcx, alias.def_id, identity_args); + self.eq_structurally_relating_aliases(param_env, term, rigid_ctor.to_ty(tcx).into())?; + self.eq(param_env, alias, rigid_ctor)?; + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } else { + Err(NoSolution) + } + } + // FIXME: This needs a name that reflects that it's okay to bottom-out with an inference var. /// Normalize the `term` to equate it later. #[instrument(level = "debug", skip(self, param_env), ret)] @@ -105,6 +132,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } + #[instrument(level = "debug", skip(self, param_env), ret)] fn try_normalize_ty_recur( &mut self, param_env: ty::ParamEnv<'tcx>, @@ -128,10 +156,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ); this.add_goal(GoalSource::Misc, normalizes_to_goal); this.try_evaluate_added_goals()?; - let ty = this.resolve_vars_if_possible(normalized_ty); - Ok(this.try_normalize_ty_recur(param_env, depth + 1, ty)) + Ok(this.resolve_vars_if_possible(normalized_ty)) }) { - Ok(ty) => ty, + Ok(ty) => self.try_normalize_ty_recur(param_env, depth + 1, ty), Err(NoSolution) => Some(ty), } } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index 1a6aa3f144c3..251b0a193f1b 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -18,7 +18,7 @@ use rustc_infer::infer::canonical::query_response::make_query_region_constraints use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints}; use rustc_infer::infer::resolve::EagerResolver; -use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; +use rustc_infer::infer::{InferCtxt, InferOk}; use rustc_middle::infer::canonical::Canonical; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{ @@ -80,7 +80,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// the values inferred while solving the instantiated goal. /// - `external_constraints`: additional constraints which aren't expressible /// using simple unification of inference variables. - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] pub(in crate::solve) fn evaluate_added_goals_and_make_canonical_response( &mut self, certainty: Certainty, @@ -191,7 +191,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { param_env: ty::ParamEnv<'tcx>, original_values: Vec>, response: CanonicalResponse<'tcx>, - ) -> Result<(Certainty, Vec>>), NoSolution> { + ) -> Certainty { let instantiation = Self::compute_query_response_instantiation_values( self.infcx, &original_values, @@ -201,15 +201,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let Response { var_values, external_constraints, certainty } = response.instantiate(self.tcx(), &instantiation); - let nested_goals = - Self::unify_query_var_values(self.infcx, param_env, &original_values, var_values)?; + Self::unify_query_var_values(self.infcx, param_env, &original_values, var_values); let ExternalConstraintsData { region_constraints, opaque_types } = external_constraints.deref(); self.register_region_constraints(region_constraints); - self.register_opaque_types(param_env, opaque_types)?; - - Ok((certainty, nested_goals)) + self.register_new_opaque_types(param_env, opaque_types); + certainty } /// This returns the canoncial variable values to instantiate the bound variables of @@ -296,32 +294,36 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { CanonicalVarValues { var_values } } - #[instrument(level = "debug", skip(infcx, param_env), ret)] + /// Unify the `original_values` with the `var_values` returned by the canonical query.. + /// + /// This assumes that this unification will always succeed. This is the case when + /// applying a query response right away. However, calling a canonical query, doing any + /// other kind of trait solving, and only then instantiating the result of the query + /// can cause the instantiation to fail. This is not supported and we ICE in this case. + /// + /// We always structurally instantiate aliases. Relating aliases needs to be different + /// depending on whether the alias is *rigid* or not. We're only really able to tell + /// whether an alias is rigid by using the trait solver. When instantiating a response + /// from the solver we assume that the solver correctly handled aliases and therefore + /// always relate them structurally here. + #[instrument(level = "debug", skip(infcx), ret)] fn unify_query_var_values( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, original_values: &[ty::GenericArg<'tcx>], var_values: CanonicalVarValues<'tcx>, - ) -> Result>>, NoSolution> { + ) { assert_eq!(original_values.len(), var_values.len()); - let mut nested_goals = vec![]; + let cause = ObligationCause::dummy(); for (&orig, response) in iter::zip(original_values, var_values.var_values) { - nested_goals.extend( - infcx - .at(&ObligationCause::dummy(), param_env) - .eq(DefineOpaqueTypes::No, orig, response) - .map(|InferOk { value: (), obligations }| { - obligations.into_iter().map(|o| Goal::from(o)) - }) - .map_err(|e| { - debug!(?e, "failed to equate"); - NoSolution - })?, - ); + let InferOk { value: (), obligations } = infcx + .at(&cause, param_env) + .trace(orig, response) + .eq_structurally_relating_aliases(orig, response) + .unwrap(); + assert!(obligations.is_empty()); } - - Ok(nested_goals) } fn register_region_constraints(&mut self, region_constraints: &QueryRegionConstraints<'tcx>) { @@ -333,21 +335,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } - for member_constraint in ®ion_constraints.member_constraints { - // FIXME: Deal with member constraints :< - let _ = member_constraint; - } + assert!(region_constraints.member_constraints.is_empty()); } - fn register_opaque_types( + fn register_new_opaque_types( &mut self, param_env: ty::ParamEnv<'tcx>, opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)], - ) -> Result<(), NoSolution> { + ) { for &(key, ty) in opaque_types { - self.insert_hidden_type(key, param_env, ty)?; + self.insert_hidden_type(key, param_env, ty).unwrap(); } - Ok(()) } } @@ -366,19 +364,21 @@ impl<'tcx> inspect::ProofTreeBuilder<'tcx> { ) } + /// Instantiate a `CanonicalState`. This assumes that unifying the var values + /// trivially succeeds. Adding any inference constraints which weren't present when + /// originally computing the canonical query can result in bugs. pub fn instantiate_canonical_state>>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, original_values: &[ty::GenericArg<'tcx>], state: inspect::CanonicalState<'tcx, T>, - ) -> Result<(Vec>>, T), NoSolution> { + ) -> T { let instantiation = EvalCtxt::compute_query_response_instantiation_values(infcx, original_values, &state); let inspect::State { var_values, data } = state.instantiate(infcx.tcx, &instantiation); - let nested_goals = - EvalCtxt::unify_query_var_values(infcx, param_env, original_values, var_values)?; - Ok((nested_goals, data)) + EvalCtxt::unify_query_var_values(infcx, param_env, original_values, var_values); + data } } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index 5c1e8bf616fd..7abe8eb1947c 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -17,8 +17,8 @@ use rustc_middle::traits::solve::{ }; use rustc_middle::traits::{specialization_graph, DefiningAnchor}; use rustc_middle::ty::{ - self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, - TypeVisitableExt, TypeVisitor, + self, InferCtxtLike, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, + TypeVisitable, TypeVisitableExt, TypeVisitor, }; use rustc_session::config::DumpSolverProofTree; use rustc_span::DUMMY_SP; @@ -142,10 +142,7 @@ impl<'tcx> InferCtxt<'tcx> { &self, goal: Goal<'tcx, ty::Predicate<'tcx>>, generate_proof_tree: GenerateProofTree, - ) -> ( - Result<(bool, Certainty, Vec>>), NoSolution>, - Option>, - ) { + ) -> (Result<(bool, Certainty), NoSolution>, Option>) { EvalCtxt::enter_root(self, generate_proof_tree, |ecx| { ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal) }) @@ -327,7 +324,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { goal_evaluation_kind: GoalEvaluationKind, source: GoalSource, goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) -> Result<(bool, Certainty, Vec>>), NoSolution> { + ) -> Result<(bool, Certainty), NoSolution> { let (orig_values, canonical_goal) = self.canonicalize_goal(goal); let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind); @@ -345,26 +342,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { Ok(response) => response, }; - let (certainty, has_changed, nested_goals) = match self - .instantiate_response_discarding_overflow( - goal.param_env, - source, - orig_values, - canonical_response, - ) { - Err(e) => { - self.inspect.goal_evaluation(goal_evaluation); - return Err(e); - } - Ok(response) => response, - }; - goal_evaluation.returned_goals(&nested_goals); + let (certainty, has_changed) = self.instantiate_response_discarding_overflow( + goal.param_env, + source, + orig_values, + canonical_response, + ); self.inspect.goal_evaluation(goal_evaluation); - - if !has_changed && !nested_goals.is_empty() { - bug!("an unchanged goal shouldn't have any side-effects on instantiation"); - } - // FIXME: We previously had an assert here that checked that recomputing // a goal after applying its constraints did not change its response. // @@ -375,7 +359,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { // Once we have decided on how to handle trait-system-refactor-initiative#75, // we should re-add an assert here. - Ok((has_changed, certainty, nested_goals)) + Ok((has_changed, certainty)) } fn instantiate_response_discarding_overflow( @@ -384,7 +368,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { source: GoalSource, original_values: Vec>, response: CanonicalResponse<'tcx>, - ) -> Result<(Certainty, bool, Vec>>), NoSolution> { + ) -> (Certainty, bool) { // The old solver did not evaluate nested goals when normalizing. // It returned the selection constraints allowing a `Projection` // obligation to not hold in coherence while avoiding the fatal error @@ -405,14 +389,14 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { }; if response.value.certainty == Certainty::OVERFLOW && !keep_overflow_constraints() { - Ok((Certainty::OVERFLOW, false, Vec::new())) + (Certainty::OVERFLOW, false) } else { let has_changed = !response.value.var_values.is_identity_modulo_regions() || !response.value.external_constraints.opaque_types.is_empty(); - let (certainty, nested_goals) = - self.instantiate_and_apply_query_response(param_env, original_values, response)?; - Ok((certainty, has_changed, nested_goals)) + let certainty = + self.instantiate_and_apply_query_response(param_env, original_values, response); + (certainty, has_changed) } } @@ -537,12 +521,11 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { ty::NormalizesTo { alias: goal.predicate.alias, term: unconstrained_rhs }, ); - let (_, certainty, instantiate_goals) = self.evaluate_goal( + let (_, certainty) = self.evaluate_goal( GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::Yes }, GoalSource::Misc, unconstrained_goal, )?; - self.nested_goals.goals.extend(with_misc_source(instantiate_goals)); // Finally, equate the goal's RHS with the unconstrained var. // We put the nested goals from this into goals instead of @@ -573,12 +556,11 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } for (source, goal) in goals.goals.drain(..) { - let (has_changed, certainty, instantiate_goals) = self.evaluate_goal( + let (has_changed, certainty) = self.evaluate_goal( GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::No }, source, goal, )?; - self.nested_goals.goals.extend(with_misc_source(instantiate_goals)); if has_changed { unchanged_certainty = None; } @@ -633,43 +615,46 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { &self, goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, ) -> bool { - let term_is_infer = match goal.predicate.term.unpack() { + let universe_of_term = match goal.predicate.term.unpack() { ty::TermKind::Ty(ty) => { if let &ty::Infer(ty::TyVar(vid)) = ty.kind() { - match self.infcx.probe_ty_var(vid) { - Ok(value) => bug!("resolved var in query: {goal:?} {value:?}"), - Err(universe) => universe == self.infcx.universe(), - } + self.infcx.universe_of_ty(vid).unwrap() } else { - false + return false; } } ty::TermKind::Const(ct) => { if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() { - match self.infcx.probe_const_var(vid) { - Ok(value) => bug!("resolved var in query: {goal:?} {value:?}"), - Err(universe) => universe == self.infcx.universe(), - } + self.infcx.universe_of_ct(vid).unwrap() } else { - false + return false; } } }; // Guard against `>::Assoc = ?0>`. - struct ContainsTerm<'a, 'tcx> { + struct ContainsTermOrNotNameable<'a, 'tcx> { term: ty::Term<'tcx>, + universe_of_term: ty::UniverseIndex, infcx: &'a InferCtxt<'tcx>, } - impl<'tcx> TypeVisitor> for ContainsTerm<'_, 'tcx> { + impl<'tcx> TypeVisitor> for ContainsTermOrNotNameable<'_, 'tcx> { type BreakTy = (); fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { - if let Some(vid) = t.ty_vid() - && let ty::TermKind::Ty(term) = self.term.unpack() - && let Some(term_vid) = term.ty_vid() - && self.infcx.root_var(vid) == self.infcx.root_var(term_vid) - { - ControlFlow::Break(()) + if let Some(vid) = t.ty_vid() { + if let ty::TermKind::Ty(term) = self.term.unpack() + && let Some(term_vid) = term.ty_vid() + && self.infcx.root_var(vid) == self.infcx.root_var(term_vid) + { + ControlFlow::Break(()) + } else if self + .universe_of_term + .cannot_name(self.infcx.universe_of_ty(vid).unwrap()) + { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } } else if t.has_non_region_infer() { t.super_visit_with(self) } else { @@ -678,12 +663,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow { - if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = c.kind() - && let ty::TermKind::Const(term) = self.term.unpack() - && let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind() - && self.infcx.root_const_var(vid) == self.infcx.root_const_var(term_vid) - { - ControlFlow::Break(()) + if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = c.kind() { + if let ty::TermKind::Const(term) = self.term.unpack() + && let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind() + && self.infcx.root_const_var(vid) == self.infcx.root_const_var(term_vid) + { + ControlFlow::Break(()) + } else if self + .universe_of_term + .cannot_name(self.infcx.universe_of_ct(vid).unwrap()) + { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } } else if c.has_non_region_infer() { c.super_visit_with(self) } else { @@ -692,10 +685,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } - let mut visitor = ContainsTerm { infcx: self.infcx, term: goal.predicate.term }; - - term_is_infer - && goal.predicate.alias.visit_with(&mut visitor).is_continue() + let mut visitor = ContainsTermOrNotNameable { + infcx: self.infcx, + universe_of_term, + term: goal.predicate.term, + }; + goal.predicate.alias.visit_with(&mut visitor).is_continue() && goal.param_env.visit_with(&mut visitor).is_continue() } @@ -718,6 +713,26 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { }) } + /// This sohuld only be used when we're either instantiating a previously + /// unconstrained "return value" or when we're sure that all aliases in + /// the types are rigid. + #[instrument(level = "debug", skip(self, param_env), ret)] + pub(super) fn eq_structurally_relating_aliases>( + &mut self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + rhs: T, + ) -> Result<(), NoSolution> { + let cause = ObligationCause::dummy(); + let InferOk { value: (), obligations } = self + .infcx + .at(&cause, param_env) + .trace(lhs, rhs) + .eq_structurally_relating_aliases(lhs, rhs)?; + assert!(obligations.is_empty()); + Ok(()) + } + #[instrument(level = "debug", skip(self, param_env), ret)] pub(super) fn sub>( &mut self, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs index 7196a5af259f..3262d64cb7d5 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs @@ -58,44 +58,26 @@ impl<'tcx> InferCtxt<'tcx> { } let candidate = candidates.pop().unwrap(); - let (certainty, nested_goals) = ecx - .instantiate_and_apply_query_response( - trait_goal.param_env, - orig_values, - candidate.result, - ) - .map_err(|_| SelectionError::Unimplemented)?; + let certainty = ecx.instantiate_and_apply_query_response( + trait_goal.param_env, + orig_values, + candidate.result, + ); - Ok(Some((candidate, certainty, nested_goals))) + Ok(Some((candidate, certainty))) }); - let (candidate, certainty, nested_goals) = match result { - Ok(Some((candidate, certainty, nested_goals))) => { - (candidate, certainty, nested_goals) - } + let (candidate, certainty) = match result { + Ok(Some(result)) => result, Ok(None) => return Ok(None), Err(e) => return Err(e), }; - let nested_obligations: Vec<_> = nested_goals - .into_iter() - .map(|goal| { - Obligation::new( - self.tcx, - ObligationCause::dummy(), - goal.param_env, - goal.predicate, - ) - }) - .collect(); - let goal = self.resolve_vars_if_possible(trait_goal); match (certainty, candidate.source) { // Rematching the implementation will instantiate the same nested goals that // would have caused the ambiguity, so we can still make progress here regardless. - (_, CandidateSource::Impl(def_id)) => { - rematch_impl(self, goal, def_id, nested_obligations) - } + (_, CandidateSource::Impl(def_id)) => rematch_impl(self, goal, def_id), // If an unsize goal is ambiguous, then we can manually rematch it to make // selection progress for coercion during HIR typeck. If it is *not* ambiguous, @@ -108,20 +90,20 @@ impl<'tcx> InferCtxt<'tcx> { | (Certainty::Yes, CandidateSource::BuiltinImpl(src @ BuiltinImplSource::Misc)) if self.tcx.lang_items().unsize_trait() == Some(goal.predicate.def_id()) => { - rematch_unsize(self, goal, nested_obligations, src, certainty) + rematch_unsize(self, goal, src, certainty) } // Technically some builtin impls have nested obligations, but if // `Certainty::Yes`, then they should've all been verified and don't // need re-checking. (Certainty::Yes, CandidateSource::BuiltinImpl(src)) => { - Ok(Some(ImplSource::Builtin(src, nested_obligations))) + Ok(Some(ImplSource::Builtin(src, vec![]))) } // It's fine not to do anything to rematch these, since there are no // nested obligations. (Certainty::Yes, CandidateSource::ParamEnv(_) | CandidateSource::AliasBound) => { - Ok(Some(ImplSource::Param(nested_obligations))) + Ok(Some(ImplSource::Param(vec![]))) } (Certainty::Maybe(_), _) => Ok(None), @@ -192,19 +174,16 @@ fn rematch_impl<'tcx>( infcx: &InferCtxt<'tcx>, goal: Goal<'tcx, ty::TraitPredicate<'tcx>>, impl_def_id: DefId, - mut nested: Vec>, ) -> SelectionResult<'tcx, Selection<'tcx>> { let args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id); let impl_trait_ref = infcx.tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(infcx.tcx, args); - nested.extend( - infcx - .at(&ObligationCause::dummy(), goal.param_env) - .eq(DefineOpaqueTypes::No, goal.predicate.trait_ref, impl_trait_ref) - .map_err(|_| SelectionError::Unimplemented)? - .into_obligations(), - ); + let mut nested = infcx + .at(&ObligationCause::dummy(), goal.param_env) + .eq(DefineOpaqueTypes::No, goal.predicate.trait_ref, impl_trait_ref) + .map_err(|_| SelectionError::Unimplemented)? + .into_obligations(); nested.extend( infcx.tcx.predicates_of(impl_def_id).instantiate(infcx.tcx, args).into_iter().map( @@ -221,11 +200,11 @@ fn rematch_impl<'tcx>( fn rematch_unsize<'tcx>( infcx: &InferCtxt<'tcx>, goal: Goal<'tcx, ty::TraitPredicate<'tcx>>, - mut nested: Vec>, source: BuiltinImplSource, certainty: Certainty, ) -> SelectionResult<'tcx, Selection<'tcx>> { let tcx = infcx.tcx; + let mut nested = vec![]; let a_ty = structurally_normalize(goal.predicate.self_ty(), infcx, goal.param_env, &mut nested); let b_ty = structurally_normalize( goal.predicate.trait_ref.args.type_at(1), diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 97f715b6386c..c1b07765e501 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -2,7 +2,6 @@ use std::mem; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::solve::MaybeCause; -use rustc_infer::traits::Obligation; use rustc_infer::traits::{ query::NoSolution, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, PredicateObligation, SelectionError, TraitEngine, @@ -11,7 +10,7 @@ use rustc_middle::ty; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use super::eval_ctxt::GenerateProofTree; -use super::{Certainty, Goal, InferCtxtEvalExt}; +use super::{Certainty, InferCtxtEvalExt}; /// A trait engine using the new trait solver. /// @@ -48,11 +47,11 @@ impl<'tcx> FulfillmentCtxt<'tcx> { &self, infcx: &InferCtxt<'tcx>, obligation: &PredicateObligation<'tcx>, - result: &Result<(bool, Certainty, Vec>>), NoSolution>, + result: &Result<(bool, Certainty), NoSolution>, ) { if let Some(inspector) = infcx.obligation_inspector.get() { let result = match result { - Ok((_, c, _)) => Ok(*c), + Ok((_, c)) => Ok(*c), Err(NoSolution) => Err(NoSolution), }; (inspector)(infcx, &obligation, result); @@ -80,13 +79,13 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { .evaluate_root_goal(obligation.clone().into(), GenerateProofTree::IfEnabled) .0 { - Ok((_, Certainty::Maybe(MaybeCause::Ambiguity), _)) => { + Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => { FulfillmentErrorCode::Ambiguity { overflow: false } } - Ok((_, Certainty::Maybe(MaybeCause::Overflow), _)) => { + Ok((_, Certainty::Maybe(MaybeCause::Overflow))) => { FulfillmentErrorCode::Ambiguity { overflow: true } } - Ok((_, Certainty::Yes, _)) => { + Ok((_, Certainty::Yes)) => { bug!("did not expect successful goal when collecting ambiguity errors") } Err(_) => { @@ -120,7 +119,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { let goal = obligation.clone().into(); let result = infcx.evaluate_root_goal(goal, GenerateProofTree::IfEnabled).0; self.inspect_evaluated_obligation(infcx, &obligation, &result); - let (changed, certainty, nested_goals) = match result { + let (changed, certainty) = match result { Ok(result) => result, Err(NoSolution) => { errors.push(FulfillmentError { @@ -178,16 +177,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { continue; } }; - // Push any nested goals that we get from unifying our canonical response - // with our obligation onto the fulfillment context. - self.obligations.extend(nested_goals.into_iter().map(|goal| { - Obligation::new( - infcx.tcx, - obligation.cause.clone(), - goal.param_env, - goal.predicate, - ) - })); has_changed |= changed; match certainty { Certainty::Yes => {} diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index c5d4ce33d861..52b900af8532 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -63,21 +63,12 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { infcx.probe(|_| { let mut instantiated_goals = vec![]; for goal in &self.nested_goals { - let goal = match ProofTreeBuilder::instantiate_canonical_state( + let goal = ProofTreeBuilder::instantiate_canonical_state( infcx, self.goal.goal.param_env, self.goal.orig_values, *goal, - ) { - Ok((_goals, goal)) => goal, - Err(NoSolution) => { - warn!( - "unexpected failure when instantiating {:?}: {:?}", - goal, self.nested_goals - ); - return ControlFlow::Continue(()); - } - }; + ); instantiated_goals.push(goal); } diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs index b587a93b24c4..f7b310a7abe2 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs @@ -87,7 +87,6 @@ struct WipGoalEvaluation<'tcx> { pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>, pub kind: WipGoalEvaluationKind<'tcx>, pub evaluation: Option>, - pub returned_goals: Vec>>, } impl<'tcx> WipGoalEvaluation<'tcx> { @@ -103,7 +102,6 @@ impl<'tcx> WipGoalEvaluation<'tcx> { } }, evaluation: self.evaluation.unwrap().finalize(), - returned_goals: self.returned_goals, } } } @@ -312,7 +310,6 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } }, evaluation: None, - returned_goals: vec![], }) } @@ -369,17 +366,6 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } } - pub fn returned_goals(&mut self, goals: &[Goal<'tcx, ty::Predicate<'tcx>>]) { - if let Some(this) = self.as_mut() { - match this { - DebugSolver::GoalEvaluation(evaluation) => { - assert!(evaluation.returned_goals.is_empty()); - evaluation.returned_goals.extend(goals); - } - _ => unreachable!(), - } - } - } pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<'tcx>) { if let Some(this) = self.as_mut() { match (this, *goal_evaluation.state.unwrap()) { diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 5f6258311567..aa8cc3667cd7 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -68,6 +68,34 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { kind => bug!("unknown DefKind {} in projection goal: {goal:#?}", kind.descr(def_id)), } } + + /// When normalizing an associated item, constrain the result to `term`. + /// + /// While `NormalizesTo` goals have the normalized-to term as an argument, + /// this argument is always fully unconstrained for associated items. + /// It is therefore appropriate to instead think of these `NormalizesTo` goals + /// as function returning a term after normalizing. + /// + /// When equating an inference variable and an alias, we tend to emit `alias-relate` + /// goals and only actually instantiate the inference variable with an alias if the + /// alias is rigid. However, this means that constraining the expected term of + /// such goals ends up fully structurally normalizing the resulting type instead of + /// only by one step. To avoid this we instead use structural equality here, resulting + /// in each `NormalizesTo` only projects by a single step. + /// + /// Not doing so, currently causes issues because trying to normalize an opaque type + /// during alias-relate doesn't actually constrain the opaque if the concrete type + /// is an inference variable. This means that `NormalizesTo` for associated types + /// normalizing to an opaque type always resulted in ambiguity, breaking tests e.g. + /// tests/ui/type-alias-impl-trait/issue-78450.rs. + pub fn instantiate_normalizes_to_term( + &mut self, + goal: Goal<'tcx, NormalizesTo<'tcx>>, + term: ty::Term<'tcx>, + ) { + self.eq_structurally_relating_aliases(goal.param_env, goal.predicate.term, term) + .expect("expected goal term to be fully unconstrained"); + } } impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { @@ -104,8 +132,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { goal.predicate.alias, assumption_projection_pred.projection_ty, )?; - ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term) - .expect("expected goal term to be fully unconstrained"); + + ecx.instantiate_normalizes_to_term(goal, assumption_projection_pred.term); // Add GAT where clauses from the trait's definition ecx.add_goals( @@ -192,8 +220,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { "cannot project to an associated function" ), }; - ecx.eq(goal.param_env, goal.predicate.term, error_term) - .expect("expected goal term to be fully unconstrained"); + ecx.instantiate_normalizes_to_term(goal, error_term); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }; @@ -248,8 +275,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ty::AssocKind::Fn => unreachable!("we should never project to a fn"), }; - ecx.eq(goal.param_env, goal.predicate.term, term.instantiate(tcx, args)) - .expect("expected goal term to be fully unconstrained"); + ecx.instantiate_normalizes_to_term(goal, term.instantiate(tcx, args)); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } @@ -456,7 +482,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { borrow_region.expect_region(), ); - ecx.eq(goal.param_env, goal.predicate.term.ty().unwrap(), upvars_ty)?; + ecx.instantiate_normalizes_to_term(goal, upvars_ty.into()); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } @@ -543,8 +569,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ), }; - ecx.eq(goal.param_env, goal.predicate.term, metadata_ty.into()) - .expect("expected goal term to be fully unconstrained"); + ecx.instantiate_normalizes_to_term(goal, metadata_ty.into()); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } @@ -627,20 +652,22 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } ecx.probe_misc_candidate("builtin AsyncIterator kind").enter(|ecx| { + let expected_ty = ecx.next_ty_infer(); // Take `AsyncIterator` and turn it into the corresponding // coroutine yield ty `Poll>`. - let expected_ty = Ty::new_adt( + let wrapped_expected_ty = Ty::new_adt( tcx, tcx.adt_def(tcx.require_lang_item(LangItem::Poll, None)), tcx.mk_args(&[Ty::new_adt( tcx, tcx.adt_def(tcx.require_lang_item(LangItem::Option, None)), - tcx.mk_args(&[goal.predicate.term.into()]), + tcx.mk_args(&[expected_ty.into()]), ) .into()]), ); let yield_ty = args.as_coroutine().yield_ty(); - ecx.eq(goal.param_env, expected_ty, yield_ty)?; + ecx.eq(goal.param_env, wrapped_expected_ty, yield_ty)?; + ecx.instantiate_normalizes_to_term(goal, expected_ty.into()); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } @@ -742,8 +769,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { }; ecx.probe_misc_candidate("builtin discriminant kind").enter(|ecx| { - ecx.eq(goal.param_env, goal.predicate.term, discriminant_ty.into()) - .expect("expected goal term to be fully unconstrained"); + ecx.instantiate_normalizes_to_term(goal, discriminant_ty.into()); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } From 297abc35b3625335a6aa9c3541be040ac040cbe9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 Feb 2024 10:40:48 +0100 Subject: [PATCH 25/39] fix some references to no-longer-existing ReprOptions.layout_seed --- compiler/rustc_abi/src/layout.rs | 2 +- compiler/rustc_abi/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index ec3ab828b719..28e148bddb22 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -958,7 +958,7 @@ fn univariant< #[cfg(feature = "randomize")] { use rand::{seq::SliceRandom, SeedableRng}; - // `ReprOptions.layout_seed` is a deterministic seed we can use to randomize field + // `ReprOptions.field_shuffle_seed` is a deterministic seed we can use to randomize field // ordering. let mut rng = rand_xoshiro::Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed); diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index c45a4a410f96..297dbf890290 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -41,7 +41,7 @@ bitflags! { // Internal only for now. If true, don't reorder fields. const IS_LINEAR = 1 << 3; // If true, the type's layout can be randomized using - // the seed stored in `ReprOptions.layout_seed` + // the seed stored in `ReprOptions.field_shuffle_seed` const RANDOMIZE_LAYOUT = 1 << 4; // Any of these flags being set prevent field reordering optimisation. const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits() From a788be0aae7558b41beb344c090470da4a60f277 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 26 Feb 2024 10:19:03 +0100 Subject: [PATCH 26/39] use fulfillment in `Coerce::unify' only checking whether nested goals hold means that we don't consider their inference constraints. Given that we now emit `AliasRelate` when relating aliases and infer vars, this previously resulted in an "unconstrained" inference var in `coerce_unsized`. --- compiler/rustc_hir_typeck/src/coercion.rs | 26 +++++++++++++---------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 9f6175eac135..ba3000d80377 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -44,6 +44,8 @@ use rustc_hir::Expr; use rustc_hir_analysis::astconv::AstConv; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult}; +use rustc_infer::traits::TraitEngine; +use rustc_infer::traits::TraitEngineExt as _; use rustc_infer::traits::{Obligation, PredicateObligation}; use rustc_middle::lint::in_external_macro; use rustc_middle::traits::BuiltinImplSource; @@ -61,6 +63,7 @@ use rustc_target::spec::abi::Abi; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +use rustc_trait_selection::traits::TraitEngineExt as _; use rustc_trait_selection::traits::{ self, NormalizeExt, ObligationCause, ObligationCauseCode, ObligationCtxt, }; @@ -157,17 +160,19 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // In the new solver, lazy norm may allow us to shallowly equate // more types, but we emit possibly impossible-to-satisfy obligations. // Filter these cases out to make sure our coercion is more accurate. - if self.next_trait_solver() { - if let Ok(res) = &res { - for obligation in &res.obligations { - if !self.predicate_may_hold(obligation) { - return Err(TypeError::Mismatch); - } + match res { + Ok(InferOk { value, obligations }) if self.next_trait_solver() => { + let mut fulfill_cx = >::new(self); + fulfill_cx.register_predicate_obligations(self, obligations); + let errs = fulfill_cx.select_where_possible(self); + if errs.is_empty() { + Ok(InferOk { value, obligations: fulfill_cx.pending_obligations() }) + } else { + Err(TypeError::Mismatch) } } + res => res, } - - res }) } @@ -625,19 +630,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let traits = [coerce_unsized_did, unsize_did]; while !queue.is_empty() { let obligation = queue.remove(0); - debug!("coerce_unsized resolve step: {:?}", obligation); let trait_pred = match obligation.predicate.kind().no_bound_vars() { Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred))) if traits.contains(&trait_pred.def_id()) => { - trait_pred + self.resolve_vars_if_possible(trait_pred) } _ => { coercion.obligations.push(obligation); continue; } }; - let trait_pred = self.resolve_vars_if_possible(trait_pred); + debug!("coerce_unsized resolve step: {:?}", trait_pred); match selcx.select(&obligation.with(selcx.tcx(), trait_pred)) { // Uncertain or unimplemented. Ok(None) => { From 2c7ede8f52fb2d861ab875ac44ddd88850315cc6 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 26 Feb 2024 10:19:11 +0100 Subject: [PATCH 27/39] update tests --- .../occurs-check/associated-type.next.stderr | 4 --- .../occurs-check/opaques.next.stderr | 6 ++-- .../auto-trait-coherence.next.stderr | 4 +-- tests/ui/impl-trait/auto-trait-coherence.rs | 3 +- ...o_tait_defining_each_other2.current.stderr | 2 +- .../two_tait_defining_each_other2.next.stderr | 8 ++--- .../two_tait_defining_each_other2.rs | 2 +- .../trait_ref_is_knowable-norm-overflow.rs | 2 +- ...trait_ref_is_knowable-norm-overflow.stderr | 4 +-- .../trait_ref_is_knowable-normalization-3.rs | 2 +- .../generalize-proj-new-universe-index-2.rs | 4 +-- ...eneralize-proj-new-universe-index-2.stderr | 19 ----------- ...tantiate-canonical-occurs-check-failure.rs | 29 ++++++++++++++++ .../occurs-check-nested-alias.next.stderr | 9 ----- .../generalize/occurs-check-nested-alias.rs | 34 +++++++++++-------- .../issue-118950-root-region.stderr | 4 --- 16 files changed, 68 insertions(+), 68 deletions(-) delete mode 100644 tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.stderr create mode 100644 tests/ui/traits/next-solver/generalize/instantiate-canonical-occurs-check-failure.rs delete mode 100644 tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.next.stderr diff --git a/tests/ui/coherence/occurs-check/associated-type.next.stderr b/tests/ui/coherence/occurs-check/associated-type.next.stderr index 6119e6149a71..50b83b90b0bd 100644 --- a/tests/ui/coherence/occurs-check/associated-type.next.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.next.stderr @@ -1,11 +1,7 @@ WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } error[E0119]: conflicting implementations of trait `Overlap fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())` --> $DIR/associated-type.rs:31:1 | diff --git a/tests/ui/coherence/occurs-check/opaques.next.stderr b/tests/ui/coherence/occurs-check/opaques.next.stderr index 4ad8257d2c14..a5182eb5d9c3 100644 --- a/tests/ui/coherence/occurs-check/opaques.next.stderr +++ b/tests/ui/coherence/occurs-check/opaques.next.stderr @@ -1,17 +1,17 @@ -error[E0119]: conflicting implementations of trait `Trait>` for type `Alias<_>` +error[E0119]: conflicting implementations of trait `Trait<_>` --> $DIR/opaques.rs:30:1 | LL | impl Trait for T { | ---------------------- first implementation here ... LL | impl Trait for defining_scope::Alias { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Alias<_>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation error[E0282]: type annotations needed --> $DIR/opaques.rs:13:20 | LL | pub fn cast(x: Container, T>) -> Container { - | ^ cannot infer type for struct `Container, T>` + | ^ cannot infer type for struct `Container` error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/auto-trait-coherence.next.stderr b/tests/ui/impl-trait/auto-trait-coherence.next.stderr index 3f979d1a50b3..cd91bfcb48d7 100644 --- a/tests/ui/impl-trait/auto-trait-coherence.next.stderr +++ b/tests/ui/impl-trait/auto-trait-coherence.next.stderr @@ -1,11 +1,11 @@ -error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D` +error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<_>` --> $DIR/auto-trait-coherence.rs:24:1 | LL | impl AnotherTrait for T {} | -------------------------------- first implementation here ... LL | impl AnotherTrait for D { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<_>` error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/auto-trait-coherence.rs b/tests/ui/impl-trait/auto-trait-coherence.rs index 0f089c5adbd7..e3036fd0fe2c 100644 --- a/tests/ui/impl-trait/auto-trait-coherence.rs +++ b/tests/ui/impl-trait/auto-trait-coherence.rs @@ -22,7 +22,8 @@ impl AnotherTrait for T {} // (We treat opaque types as "foreign types" that could grow more impls // in the future.) impl AnotherTrait for D { - //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D` + //[old]~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D` + //[next]~^^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<_>` } fn main() {} diff --git a/tests/ui/impl-trait/two_tait_defining_each_other2.current.stderr b/tests/ui/impl-trait/two_tait_defining_each_other2.current.stderr index 33866451c6b4..c5c9ae33f4d8 100644 --- a/tests/ui/impl-trait/two_tait_defining_each_other2.current.stderr +++ b/tests/ui/impl-trait/two_tait_defining_each_other2.current.stderr @@ -7,7 +7,7 @@ LL | type A = impl Foo; = note: `A` must be used in combination with a concrete type within the same module error: opaque type's hidden type cannot be another opaque type from the same scope - --> $DIR/two_tait_defining_each_other2.rs:11:5 + --> $DIR/two_tait_defining_each_other2.rs:12:5 | LL | x // B's hidden type is A (opaquely) | ^ one of the two opaque types used here has to be outside its defining scope diff --git a/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr b/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr index 69328e205831..7e2b05618c4b 100644 --- a/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr +++ b/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot satisfy `A == B` - --> $DIR/two_tait_defining_each_other2.rs:11:5 +error[E0284]: type annotations needed: cannot satisfy `_ == A` + --> $DIR/two_tait_defining_each_other2.rs:10:8 | -LL | x // B's hidden type is A (opaquely) - | ^ cannot satisfy `A == B` +LL | fn muh(x: A) -> B { + | ^ cannot satisfy `_ == A` error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/two_tait_defining_each_other2.rs b/tests/ui/impl-trait/two_tait_defining_each_other2.rs index 229a74119516..faa1fed22d34 100644 --- a/tests/ui/impl-trait/two_tait_defining_each_other2.rs +++ b/tests/ui/impl-trait/two_tait_defining_each_other2.rs @@ -8,9 +8,9 @@ type B = impl Foo; trait Foo {} fn muh(x: A) -> B { + //[next]~^ ERROR type annotations needed: cannot satisfy `_ == A` x // B's hidden type is A (opaquely) //[current]~^ ERROR opaque type's hidden type cannot be another opaque type - //[next]~^^ ERROR type annotations needed: cannot satisfy `A == B` } struct Bar; diff --git a/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.rs b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.rs index 66409f171e6e..3238f0283628 100644 --- a/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.rs +++ b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.rs @@ -16,6 +16,6 @@ trait Trait {} impl Trait for T {} struct LocalTy; impl Trait for ::Assoc {} -//~^ ERROR conflicting implementations of trait `Trait` for type `::Assoc` +//~^ ERROR conflicting implementations of trait `Trait` fn main() {} diff --git a/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr index 583945723d5f..fc145b811964 100644 --- a/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr +++ b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr @@ -1,11 +1,11 @@ -error[E0119]: conflicting implementations of trait `Trait` for type `::Assoc` +error[E0119]: conflicting implementations of trait `Trait` --> $DIR/trait_ref_is_knowable-norm-overflow.rs:18:1 | LL | impl Trait for T {} | ------------------------- first implementation here LL | struct LocalTy; LL | impl Trait for ::Assoc {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `::Assoc` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation error[E0275]: overflow evaluating the requirement `::Assoc: Sized` --> $DIR/trait_ref_is_knowable-norm-overflow.rs:10:18 diff --git a/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-normalization-3.rs b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-normalization-3.rs index 98fd98ac2825..70d8d74d5ea8 100644 --- a/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-normalization-3.rs +++ b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-normalization-3.rs @@ -9,7 +9,7 @@ impl Id for T { } -// Coherence should be able to reason that `(): PartialEq<::Assoc>>` +// Coherence should be able to reason that `(): PartialEq<::Assoc>>` // does not hold. // // See https://github.com/rust-lang/trait-system-refactor-initiative/issues/51 diff --git a/tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.rs b/tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.rs index 4de5eda3a798..91793e59f1a4 100644 --- a/tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.rs +++ b/tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.rs @@ -1,8 +1,8 @@ //@ compile-flags: -Znext-solver -//@ known-bug: trait-system-refactor-initiative#60 +//@ check-pass // Generalizing a projection containing an inference variable -// which cannot be named by the `root_vid` can result in ambiguity. +// which cannot be named by the `root_vid` previously resulted in ambiguity. // // Because we do not decrement the universe index when exiting a forall, // this can cause unexpected failures. diff --git a/tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.stderr b/tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.stderr deleted file mode 100644 index 4548ab1e2972..000000000000 --- a/tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0284]: type annotations needed - --> $DIR/generalize-proj-new-universe-index-2.rs:74:5 - | -LL | bound::<::Assoc, as Id>::Assoc, _>() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `V` declared on the function `bound` - | - = note: cannot satisfy `<::Assoc as WithAssoc< as Id>::Assoc>>::Assoc == _` -note: required by a bound in `bound` - --> $DIR/generalize-proj-new-universe-index-2.rs:69:21 - | -LL | fn bound() - | ----- required by a bound in this function -LL | where -LL | T: WithAssoc, - | ^^^^^^^^^ required by this bound in `bound` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/traits/next-solver/generalize/instantiate-canonical-occurs-check-failure.rs b/tests/ui/traits/next-solver/generalize/instantiate-canonical-occurs-check-failure.rs new file mode 100644 index 000000000000..37d91fe2c7d1 --- /dev/null +++ b/tests/ui/traits/next-solver/generalize/instantiate-canonical-occurs-check-failure.rs @@ -0,0 +1,29 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// With #119106 generalization now results in `AliasRelate` if the generalized +// alias contains an inference variable which is not nameable. +// +// We previously proved alias-relate after canonicalization, which does not keep track +// of universe indices, so all inference vars were nameable inside of `AliasRelate`. +// +// If we now have a rigid projection containing an unnameable inference variable, +// we should emit an alias-relate obligation, which constrains the type of `x` to +// an alias. This caused us to emit yet another equivalent alias-relate obligation +// when trying to instantiate the query result, resulting in overflow. +trait Trait<'a> { + type Assoc: Default; +} + +fn takes_alias<'a, T: Trait<'a>>(_: >::Assoc) {} + +fn foo Trait<'a>>() { + let x = Default::default(); + + let _incr_universe: for<'a, 'b> fn(&'a (), &'b ()) = + (|&(), &()| ()) as for<'a> fn(&'a (), &'a ()); + + takes_alias::(x); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.next.stderr b/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.next.stderr deleted file mode 100644 index cde925db1848..000000000000 --- a/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.next.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0284]: type annotations needed: cannot satisfy `_ == <>::Id as Unnormalizable>::Assoc` - --> $DIR/occurs-check-nested-alias.rs:36:9 - | -LL | x = y; - | ^ cannot satisfy `_ == <>::Id as Unnormalizable>::Assoc` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs b/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs index 78fbe4415278..536e7e97c40d 100644 --- a/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs +++ b/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs @@ -1,10 +1,8 @@ //@ revisions: old next -//@[old] check-pass - -// Currently always fails to generalize the outer alias, even if it -// is treated as rigid by `alias-relate`. //@[next] compile-flags: -Znext-solver -//@[next] known-bug: trait-system-refactor-initiative#8 +//@ check-pass + +// case 3 of https://github.com/rust-lang/trait-system-refactor-initiative/issues/8. #![crate_type = "lib"] #![allow(unused)] trait Unnormalizable { @@ -14,8 +12,8 @@ trait Unnormalizable { trait Id { type Id; } -impl Id for U { - type Id = U; +impl Id for T { + type Id = T; } struct Inv(*mut T); @@ -24,15 +22,23 @@ fn unconstrained() -> T { todo!() } -fn create( - x: &U, -) -> (Inv, Inv<<>::Id as Unnormalizable>::Assoc>) { +fn create( + x: &T, +) -> (Inv, Inv<<>::Id as Unnormalizable>::Assoc>) { todo!() } fn foo() { - let q = unconstrained(); - let (mut x, y) = create::<_, _>(&q); - x = y; - drop::(q); + let t = unconstrained(); + let (mut u, assoc) = create::<_, _>(&t); + u = assoc; + // Instantiating `?u` with `<>::Id as Unnormalizable>::Assoc` would + // result in a cyclic type. However, we can still unify these types by first + // normalizing the inner associated type. Emitting an error here would be incomplete. + drop::(t); + + // FIXME(-Znext-solver): This line is necessary due to an unrelated solver bug + // and should get removed in the future. + // https://github.com/rust-lang/trait-system-refactor-initiative/issues/96 + drop::::Assoc>>(u); } diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.stderr b/tests/ui/traits/next-solver/issue-118950-root-region.stderr index e33320ed9e60..931c46c68872 100644 --- a/tests/ui/traits/next-solver/issue-118950-root-region.stderr +++ b/tests/ui/traits/next-solver/issue-118950-root-region.stderr @@ -14,13 +14,9 @@ LL | #![feature(lazy_type_alias)] = note: `#[warn(incomplete_features)]` on by default WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } error[E0119]: conflicting implementations of trait `Overlap` for type `fn(_)` --> $DIR/issue-118950-root-region.rs:19:1 | From 1c264ca9cafaa06d529ce2d701559e9da982023c Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 26 Feb 2024 10:46:57 +0100 Subject: [PATCH 28/39] add regression tests --- .../candidates-equal-modulo-norm-1.rs | 26 +++++++++++++++++++ .../candidates-equal-modulo-norm-2.rs | 26 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 tests/ui/traits/next-solver/assembly/candidates-equal-modulo-norm-1.rs create mode 100644 tests/ui/traits/next-solver/assembly/candidates-equal-modulo-norm-2.rs diff --git a/tests/ui/traits/next-solver/assembly/candidates-equal-modulo-norm-1.rs b/tests/ui/traits/next-solver/assembly/candidates-equal-modulo-norm-1.rs new file mode 100644 index 000000000000..3ac1639cfba0 --- /dev/null +++ b/tests/ui/traits/next-solver/assembly/candidates-equal-modulo-norm-1.rs @@ -0,0 +1,26 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// Regression test for trait-system-refactor-initiative#84. +// +// We try to infer `T::Rigid: Into` and have 2 candidates from where-clauses: +// +// - `Into` +// - `Into<::Assoc>` +// +// This causes ambiguity unless we normalize the alias in the second candidate +// to detect that they actually result in the same constraints. +trait Trait { + type Rigid: Elaborate + Into + Default; +} + +trait Elaborate: Into { + type Assoc; +} + +fn test() { + let rigid: T::Rigid = Default::default(); + drop(rigid.into()); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/assembly/candidates-equal-modulo-norm-2.rs b/tests/ui/traits/next-solver/assembly/candidates-equal-modulo-norm-2.rs new file mode 100644 index 000000000000..a1b736184f1c --- /dev/null +++ b/tests/ui/traits/next-solver/assembly/candidates-equal-modulo-norm-2.rs @@ -0,0 +1,26 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// Regression test for trait-system-refactor-initiative#86. This previously +// failed with ambiguity due to multiple candidates with different +// normalization. + +trait Bar { + type Item; + type Assoc: AsRef<[Self::Item]>; +} + +struct Foo { + t: ::Assoc, +} + +impl> Foo +where + ::Assoc: AsRef<[u32]>, +{ + fn hello(&self) { + println!("{}", self.t.as_ref().len()); + } +} + +fn main() {} From b4ca582b8986c36d23726dc292c41b06fe7f9c6b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Feb 2024 18:51:22 +0100 Subject: [PATCH 29/39] rename 'try' intrinsic to 'catch_unwind' --- .../src/intrinsics/mod.rs | 4 +-- .../rustc_codegen_gcc/src/intrinsic/mod.rs | 4 +-- compiler/rustc_codegen_llvm/src/intrinsic.rs | 8 +++--- .../rustc_hir_analysis/src/check/intrinsic.rs | 4 +-- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/intrinsics.rs | 25 +++++++++++++------ library/std/src/panicking.rs | 8 +++--- src/tools/miri/src/shims/intrinsics/mod.rs | 2 +- src/tools/miri/src/shims/panic.rs | 2 +- .../fail/function_calls/check_callback_abi.rs | 2 +- .../function_calls/check_callback_abi.stderr | 2 +- .../pass/function_calls/disable_abi_check.rs | 2 +- tests/assembly/wasm_exceptions.rs | 2 +- tests/codegen/wasm_exceptions.rs | 2 +- .../run-make/wasm-exceptions-nostd/src/lib.rs | 2 +- .../interior-mutability.stderr | 2 +- 16 files changed, 42 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 199d5df29e7d..84269ec29426 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -23,7 +23,7 @@ use rustc_middle::ty::layout::{HasParamEnv, ValidityRequirement}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::GenericArgsRef; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_span::symbol::{sym, Symbol}; pub(crate) use self::llvm::codegen_llvm_intrinsic_call; use crate::prelude::*; @@ -1132,7 +1132,7 @@ fn codegen_regular_intrinsic_call<'tcx>( ret.write_cvalue(fx, val); } - kw::Try => { + sym::catch_unwind => { intrinsic_args!(fx, args => (f, data, catch_fn); intrinsic); let f = f.load_scalar(fx); let data = data.load_scalar(fx); diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index f162ef831b76..d43f5d74757a 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -21,7 +21,7 @@ use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::ty::layout::LayoutOf; #[cfg(feature="master")] use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; -use rustc_span::{Span, Symbol, symbol::kw, sym}; +use rustc_span::{Span, Symbol, sym}; use rustc_target::abi::HasDataLayout; use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; use rustc_target::spec::PanicStrategy; @@ -129,7 +129,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { let res = self.context.new_call(None, builtin, &[a]); self.icmp(IntPredicate::IntEQ, res, self.const_i32(0)) } - kw::Try => { + sym::catch_unwind => { try_intrinsic( self, args[0].immediate(), diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 1eac2157cac3..e78c4d1e31de 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -17,7 +17,7 @@ use rustc_hir as hir; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf}; use rustc_middle::ty::{self, GenericArgsRef, Ty}; use rustc_middle::{bug, span_bug}; -use rustc_span::{sym, symbol::kw, Span, Symbol}; +use rustc_span::{sym, Span, Symbol}; use rustc_target::abi::{self, Align, HasDataLayout, Primitive}; use rustc_target::spec::{HasTargetSpec, PanicStrategy}; @@ -133,8 +133,8 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { } sym::unlikely => self .call_intrinsic("llvm.expect.i1", &[args[0].immediate(), self.const_bool(false)]), - kw::Try => { - try_intrinsic( + sym::catch_unwind => { + catch_unwind_intrinsic( self, args[0].immediate(), args[1].immediate(), @@ -457,7 +457,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { } } -fn try_intrinsic<'ll>( +fn catch_unwind_intrinsic<'ll>( bx: &mut Builder<'_, 'll, '_>, try_func: &'ll Value, data: &'ll Value, diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index d7277b22c841..9714a9b5ea39 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -12,7 +12,7 @@ use rustc_hir as hir; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; -use rustc_span::symbol::{kw, sym}; +use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; use rustc_target::spec::abi::Abi; @@ -445,7 +445,7 @@ pub fn check_intrinsic_type( ) } - kw::Try => { + sym::catch_unwind => { let mut_u8 = Ty::new_mut_ptr(tcx, tcx.types.u8); let try_fn_ty = ty::Binder::dummy(tcx.mk_fn_sig( [mut_u8], diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 609ab054da21..a66d38e5b537 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -487,6 +487,7 @@ symbols! { call_once, caller_location, capture_disjoint_fields, + catch_unwind, cause, cdylib, ceilf32, diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index f9d89795a998..6fd3895bb9c1 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -75,6 +75,9 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { unsafe { crate::ptr::drop_in_place(to_drop) } } +#[cfg(bootstrap)] +pub use self::r#try as catch_unwind; + extern "rust-intrinsic" { // N.B., these intrinsics take raw pointers because they mutate aliased // memory, which is not valid for either `&` or `&mut`. @@ -2382,16 +2385,24 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn variant_count() -> usize; - /// Rust's "try catch" construct which invokes the function pointer `try_fn` - /// with the data pointer `data`. - /// - /// The third argument is a function called if a panic occurs. This function - /// takes the data pointer and a pointer to the target-specific exception - /// object that was caught. For more information see the compiler's - /// source as well as std's catch implementation. + /// Rust's "try catch" construct for unwinding. Invokes the function pointer `try_fn` with the + /// data pointer `data`, and calls `catch_fn` if unwinding occurs while `try_fn` runs. /// /// `catch_fn` must not unwind. + /// + /// The third argument is a function called if an unwind occurs (both Rust unwinds and foreign + /// unwinds). This function takes the data pointer and a pointer to the target-specific + /// exception object that was caught. For more information, see the compiler's source as well as + /// std's `catch_unwind` implementation. + /// + /// The stable version of this intrinsic is `std::panic::catch_unwind`. #[rustc_nounwind] + #[cfg(not(bootstrap))] + pub fn catch_unwind(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32; + + /// For bootstrap only, see `catch_unwind`. + #[rustc_nounwind] + #[cfg(bootstrap)] pub fn r#try(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32; /// Emits a `!nontemporal` store according to LLVM (see their docs). diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index ef701d3867a1..464a46264cbd 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -508,12 +508,12 @@ pub unsafe fn r#try R>(f: F) -> Result> // Access to the union's fields: this is `std` and we know that the `r#try` // intrinsic fills in the `r` or `p` union field based on its return value. // - // The call to `intrinsics::r#try` is made safe by: + // The call to `intrinsics::catch_unwind` is made safe by: // - `do_call`, the first argument, can be called with the initial `data_ptr`. // - `do_catch`, the second argument, can be called with the `data_ptr` as well. // See their safety preconditions for more information unsafe { - return if intrinsics::r#try(do_call::, data_ptr, do_catch::) == 0 { + return if intrinsics::catch_unwind(do_call::, data_ptr, do_catch::) == 0 { Ok(ManuallyDrop::into_inner(data.r)) } else { Err(ManuallyDrop::into_inner(data.p)) @@ -540,7 +540,7 @@ pub unsafe fn r#try R>(f: F) -> Result> // Its must contains a valid `f` (type: F) value that can be use to fill // `data.r`. // - // This function cannot be marked as `unsafe` because `intrinsics::r#try` + // This function cannot be marked as `unsafe` because `intrinsics::catch_unwind` // expects normal function pointers. #[inline] fn do_call R, R>(data: *mut u8) { @@ -562,7 +562,7 @@ pub unsafe fn r#try R>(f: F) -> Result> // Since this uses `cleanup` it also hinges on a correct implementation of // `__rustc_panic_cleanup`. // - // This function cannot be marked as `unsafe` because `intrinsics::r#try` + // This function cannot be marked as `unsafe` because `intrinsics::catch_unwind` // expects normal function pointers. #[inline] #[rustc_nounwind] // `intrinsic::r#try` requires catch fn to be nounwind diff --git a/src/tools/miri/src/shims/intrinsics/mod.rs b/src/tools/miri/src/shims/intrinsics/mod.rs index 602e8b31b010..b67d588dbc9b 100644 --- a/src/tools/miri/src/shims/intrinsics/mod.rs +++ b/src/tools/miri/src/shims/intrinsics/mod.rs @@ -54,7 +54,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // Some intrinsics are special and need the "ret". match intrinsic_name { - "try" => return this.handle_try(args, dest, ret), + "catch_unwind" => return this.handle_catch_unwind(args, dest, ret), _ => {} } diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs index 4c054d8dc8ae..54f718c46cce 100644 --- a/src/tools/miri/src/shims/panic.rs +++ b/src/tools/miri/src/shims/panic.rs @@ -69,7 +69,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } /// Handles the `try` intrinsic, the underlying implementation of `std::panicking::try`. - fn handle_try( + fn handle_catch_unwind( &mut self, args: &[OpTy<'tcx, Provenance>], dest: &PlaceTy<'tcx, Provenance>, diff --git a/src/tools/miri/tests/fail/function_calls/check_callback_abi.rs b/src/tools/miri/tests/fail/function_calls/check_callback_abi.rs index 883d5ae8096b..fd667fbe454c 100644 --- a/src/tools/miri/tests/fail/function_calls/check_callback_abi.rs +++ b/src/tools/miri/tests/fail/function_calls/check_callback_abi.rs @@ -8,7 +8,7 @@ fn main() { unsafe { // Make sure we check the ABI when Miri itself invokes a function // as part of a shim implementation. - std::intrinsics::r#try( + std::intrinsics::catch_unwind( //~^ ERROR: calling a function with ABI C using caller ABI Rust std::mem::transmute::(try_fn), std::ptr::null_mut(), diff --git a/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr b/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr index f948d08bdbe2..501f17c86d69 100644 --- a/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr +++ b/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr @@ -1,7 +1,7 @@ error: Undefined Behavior: calling a function with ABI C using caller ABI Rust --> $DIR/check_callback_abi.rs:LL:CC | -LL | / std::intrinsics::r#try( +LL | / std::intrinsics::catch_unwind( LL | | LL | | std::mem::transmute::(try_fn), LL | | std::ptr::null_mut(), diff --git a/src/tools/miri/tests/pass/function_calls/disable_abi_check.rs b/src/tools/miri/tests/pass/function_calls/disable_abi_check.rs index e6251b535588..0f41047c6033 100644 --- a/src/tools/miri/tests/pass/function_calls/disable_abi_check.rs +++ b/src/tools/miri/tests/pass/function_calls/disable_abi_check.rs @@ -15,7 +15,7 @@ fn main() { unsafe { let _ = malloc(0); std::mem::transmute::(foo)(); - std::intrinsics::r#try( + std::intrinsics::catch_unwind( std::mem::transmute::(try_fn), std::ptr::null_mut(), |_, _| unreachable!(), diff --git a/tests/assembly/wasm_exceptions.rs b/tests/assembly/wasm_exceptions.rs index 2ca62a786880..45df444dca46 100644 --- a/tests/assembly/wasm_exceptions.rs +++ b/tests/assembly/wasm_exceptions.rs @@ -41,7 +41,7 @@ pub fn test_cleanup() { #[no_mangle] pub fn test_rtry() { unsafe { - core::intrinsics::r#try(|_| { + core::intrinsics::catch_unwind(|_| { may_panic(); }, core::ptr::null_mut(), |data, exception| { log_number(data as usize); diff --git a/tests/codegen/wasm_exceptions.rs b/tests/codegen/wasm_exceptions.rs index 48a7357bfd8d..66d2bbed709c 100644 --- a/tests/codegen/wasm_exceptions.rs +++ b/tests/codegen/wasm_exceptions.rs @@ -35,7 +35,7 @@ pub fn test_cleanup() { #[no_mangle] pub fn test_rtry() { unsafe { - core::intrinsics::r#try(|_| { + core::intrinsics::catch_unwind(|_| { may_panic(); }, core::ptr::null_mut(), |data, exception| { log_number(data as usize); diff --git a/tests/run-make/wasm-exceptions-nostd/src/lib.rs b/tests/run-make/wasm-exceptions-nostd/src/lib.rs index 7049d2fd9e0d..9d336510469c 100644 --- a/tests/run-make/wasm-exceptions-nostd/src/lib.rs +++ b/tests/run-make/wasm-exceptions-nostd/src/lib.rs @@ -39,7 +39,7 @@ pub extern "C" fn start() -> usize { let data = 0x1234usize as *mut u8; // Something to recognize unsafe { - core::intrinsics::r#try(|data: *mut u8| { + core::intrinsics::catch_unwind(|data: *mut u8| { let _log_on_drop = LogOnDrop; logging::log_str(&alloc::format!("`r#try` called with ptr {:?}", data)); diff --git a/tests/ui/interior-mutability/interior-mutability.stderr b/tests/ui/interior-mutability/interior-mutability.stderr index 7b08a6454052..29b250c1b07c 100644 --- a/tests/ui/interior-mutability/interior-mutability.stderr +++ b/tests/ui/interior-mutability/interior-mutability.stderr @@ -15,7 +15,7 @@ note: required because it's used within this closure | LL | catch_unwind(|| { x.set(23); }); | ^^ -note: required by a bound in `catch_unwind` +note: required by a bound in `std::panic::catch_unwind` --> $SRC_DIR/std/src/panic.rs:LL:COL error: aborting due to 1 previous error From a3c0f3af9ca4247016eaaf476321d6ab95d5739e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Feb 2024 18:54:41 +0100 Subject: [PATCH 30/39] =?UTF-8?q?miri:=20rename=20miri=5Fstart=5Fpanic=20?= =?UTF-8?q?=E2=86=92=20miri=5Fstart=5Funwind?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- library/panic_unwind/src/miri.rs | 6 +++--- src/tools/miri/src/concurrency/thread.rs | 2 +- src/tools/miri/src/shims/foreign_items.rs | 6 +++--- src/tools/miri/src/shims/panic.rs | 14 +++++++------- ...iri_start_panic.rs => bad_miri_start_unwind.rs} | 4 ++-- ...t_panic.stderr => bad_miri_start_unwind.stderr} | 8 ++++---- .../miri/tests/fail/panic/unwind_panic_abort.rs | 4 ++-- .../tests/fail/panic/unwind_panic_abort.stderr | 4 ++-- src/tools/miri/tests/utils/miri_extern.rs | 2 +- 9 files changed, 25 insertions(+), 25 deletions(-) rename src/tools/miri/tests/fail/panic/{bad_miri_start_panic.rs => bad_miri_start_unwind.rs} (72%) rename src/tools/miri/tests/fail/panic/{bad_miri_start_panic.stderr => bad_miri_start_unwind.stderr} (71%) diff --git a/library/panic_unwind/src/miri.rs b/library/panic_unwind/src/miri.rs index d941b73b5fac..4d21e846010e 100644 --- a/library/panic_unwind/src/miri.rs +++ b/library/panic_unwind/src/miri.rs @@ -8,14 +8,14 @@ type Payload = Box>; extern "Rust" { /// Miri-provided extern function to begin unwinding. - fn miri_start_panic(payload: *mut u8) -> !; + fn miri_start_unwind(payload: *mut u8) -> !; } pub unsafe fn panic(payload: Box) -> u32 { - // The payload we pass to `miri_start_panic` will be exactly the argument we get + // 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_panic(Box::into_raw(payload_box) as *mut u8) + miri_start_unwind(Box::into_raw(payload_box) as *mut u8) } pub unsafe fn cleanup(payload_box: *mut u8) -> Box { diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 64e1f3c5b557..822ba8bf922f 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -143,7 +143,7 @@ pub struct Thread<'mir, 'tcx> { join_status: ThreadJoinStatus, /// Stack of active panic payloads for the current thread. Used for storing - /// the argument of the call to `miri_start_panic` (the panic payload) when unwinding. + /// the argument of the call to `miri_start_unwind` (the panic payload) when unwinding. /// This is pointer-sized, and matches the `Payload` type in `src/libpanic_unwind/miri.rs`. /// /// In real unwinding, the payload gets passed as an argument to the landing pad, diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 0645c1f176ef..4ae607e98da8 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -68,9 +68,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let ret = match ret { None => match link_name.as_str() { - "miri_start_panic" => { - // `check_shim` happens inside `handle_miri_start_panic`. - this.handle_miri_start_panic(abi, link_name, args, unwind)?; + "miri_start_unwind" => { + // `check_shim` happens inside `handle_miri_start_unwind`. + this.handle_miri_start_unwind(abi, link_name, args, unwind)?; return Ok(None); } // This matches calls to the foreign item `panic_impl`. diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs index 54f718c46cce..65b5838cd143 100644 --- a/src/tools/miri/src/shims/panic.rs +++ b/src/tools/miri/src/shims/panic.rs @@ -3,9 +3,9 @@ //! The core pieces of the runtime are: //! - An implementation of `__rust_maybe_catch_panic` that pushes the invoked stack frame with //! some extra metadata derived from the panic-catching arguments of `__rust_maybe_catch_panic`. -//! - A hack in `libpanic_unwind` that calls the `miri_start_panic` intrinsic instead of the +//! - A hack in `libpanic_unwind` that calls the `miri_start_unwind` intrinsic instead of the //! target-native panic runtime. (This lives in the rustc repo.) -//! - An implementation of `miri_start_panic` that stores its argument (the panic payload), and then +//! - An implementation of `miri_start_unwind` that stores its argument (the panic payload), and then //! immediately returns, but on the *unwind* edge (not the normal return edge), thus initiating unwinding. //! - A hook executed each time a frame is popped, such that if the frame pushed by `__rust_maybe_catch_panic` //! gets popped *during unwinding*, we take the panic payload and store it according to the extra @@ -44,9 +44,9 @@ impl VisitProvenance for CatchUnwindData<'_> { impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { - /// Handles the special `miri_start_panic` intrinsic, which is called + /// Handles the special `miri_start_unwind` intrinsic, which is called /// by libpanic_unwind to delegate the actual unwinding process to Miri. - fn handle_miri_start_panic( + fn handle_miri_start_unwind( &mut self, abi: Abi, link_name: Symbol, @@ -55,7 +55,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - trace!("miri_start_panic: {:?}", this.frame().instance); + trace!("miri_start_unwind: {:?}", this.frame().instance); // Get the raw pointer stored in arg[0] (the panic payload). let [payload] = this.check_shim(abi, Abi::Rust, link_name, args)?; @@ -85,7 +85,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // what that is), and returns 1. // The `payload` is passed (by libstd) to `__rust_panic_cleanup`, which is then expected to // return a `Box`. - // In Miri, `miri_start_panic` is passed exactly that type, so we make the `payload` simply + // In Miri, `miri_start_unwind` is passed exactly that type, so we make the `payload` simply // a pointer to `Box`. // Get all the arguments. @@ -141,7 +141,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // We set the return value of `try` to 1, since there was a panic. this.write_scalar(Scalar::from_i32(1), &catch_unwind.dest)?; - // The Thread's `panic_payload` holds what was passed to `miri_start_panic`. + // The Thread's `panic_payload` holds what was passed to `miri_start_unwind`. // This is exactly the second argument we need to pass to `catch_fn`. let payload = this.active_thread_mut().panic_payloads.pop().unwrap(); diff --git a/src/tools/miri/tests/fail/panic/bad_miri_start_panic.rs b/src/tools/miri/tests/fail/panic/bad_miri_start_unwind.rs similarity index 72% rename from src/tools/miri/tests/fail/panic/bad_miri_start_panic.rs rename to src/tools/miri/tests/fail/panic/bad_miri_start_unwind.rs index 4b0ae60b1010..deca836a36c6 100644 --- a/src/tools/miri/tests/fail/panic/bad_miri_start_panic.rs +++ b/src/tools/miri/tests/fail/panic/bad_miri_start_unwind.rs @@ -3,10 +3,10 @@ #![feature(c_unwind)] extern "C" { - fn miri_start_panic(payload: *mut u8) -> !; + fn miri_start_unwind(payload: *mut u8) -> !; } fn main() { - unsafe { miri_start_panic(&mut 0) } + unsafe { miri_start_unwind(&mut 0) } //~^ ERROR: unwinding past a stack frame that does not allow unwinding } diff --git a/src/tools/miri/tests/fail/panic/bad_miri_start_panic.stderr b/src/tools/miri/tests/fail/panic/bad_miri_start_unwind.stderr similarity index 71% rename from src/tools/miri/tests/fail/panic/bad_miri_start_panic.stderr rename to src/tools/miri/tests/fail/panic/bad_miri_start_unwind.stderr index 2d96ae4b7de4..6c85aac050a2 100644 --- a/src/tools/miri/tests/fail/panic/bad_miri_start_panic.stderr +++ b/src/tools/miri/tests/fail/panic/bad_miri_start_unwind.stderr @@ -1,15 +1,15 @@ WARNING: the flag `-Zmiri-disable-abi-check` is deprecated and planned to be removed. If you have a use-case for it, please file an issue. error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding - --> $DIR/bad_miri_start_panic.rs:LL:CC + --> $DIR/bad_miri_start_unwind.rs:LL:CC | -LL | unsafe { miri_start_panic(&mut 0) } - | ^^^^^^^^^^^^^^^^^^^^^^^^ unwinding past a stack frame that does not allow unwinding +LL | unsafe { miri_start_unwind(&mut 0) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ unwinding past a stack frame that does not allow unwinding | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/bad_miri_start_panic.rs:LL:CC + = note: inside `main` at $DIR/bad_miri_start_unwind.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/panic/unwind_panic_abort.rs b/src/tools/miri/tests/fail/panic/unwind_panic_abort.rs index c21fa85a9043..88419b1395c7 100644 --- a/src/tools/miri/tests/fail/panic/unwind_panic_abort.rs +++ b/src/tools/miri/tests/fail/panic/unwind_panic_abort.rs @@ -3,11 +3,11 @@ //! Unwinding despite `-C panic=abort` is an error. extern "Rust" { - fn miri_start_panic(payload: *mut u8) -> !; + fn miri_start_unwind(payload: *mut u8) -> !; } fn main() { unsafe { - miri_start_panic(&mut 0); //~ ERROR: unwinding past a stack frame that does not allow unwinding + miri_start_unwind(&mut 0); //~ ERROR: unwinding past a stack frame that does not allow unwinding } } diff --git a/src/tools/miri/tests/fail/panic/unwind_panic_abort.stderr b/src/tools/miri/tests/fail/panic/unwind_panic_abort.stderr index 4739c7f2ac6b..26afe8830cfc 100644 --- a/src/tools/miri/tests/fail/panic/unwind_panic_abort.stderr +++ b/src/tools/miri/tests/fail/panic/unwind_panic_abort.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding --> $DIR/unwind_panic_abort.rs:LL:CC | -LL | miri_start_panic(&mut 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^ unwinding past a stack frame that does not allow unwinding +LL | miri_start_unwind(&mut 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ unwinding past a stack frame that does not allow unwinding | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/utils/miri_extern.rs b/src/tools/miri/tests/utils/miri_extern.rs index ff7990561f2c..e2983f6c71a7 100644 --- a/src/tools/miri/tests/utils/miri_extern.rs +++ b/src/tools/miri/tests/utils/miri_extern.rs @@ -56,7 +56,7 @@ extern "Rust" { /// /// This is internal and unstable and should not be used; we give it here /// just to be complete. - pub fn miri_start_panic(payload: *mut u8) -> !; + pub fn miri_start_unwind(payload: *mut u8) -> !; /// Miri-provided extern function to get the internal unique identifier for the allocation that a pointer /// points to. If this pointer is invalid (not pointing to an allocation), interpretation will abort. From 3b3514acecfb1642e49d17742dbb553044e0d899 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 26 Feb 2024 11:51:01 +0100 Subject: [PATCH 31/39] consider placeholders in `fn term_is_fully_unconstrained` --- .../src/solve/eval_ctxt/mod.rs | 86 +++++++++++-------- 1 file changed, 49 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index 7abe8eb1947c..ed428bb8e662 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -608,8 +608,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// Is the projection predicate is of the form `exists ::Assoc = T`. /// - /// This is the case if the `term` is an inference variable in the innermost universe - /// and does not occur in any other part of the predicate. + /// This is the case if the `term` does not occur in any other part of the predicate + /// and is able to name all other placeholder and inference variables. #[instrument(level = "debug", skip(self), ret)] pub(super) fn term_is_fully_unconstrained( &self, @@ -632,55 +632,67 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } }; - // Guard against `>::Assoc = ?0>`. struct ContainsTermOrNotNameable<'a, 'tcx> { term: ty::Term<'tcx>, universe_of_term: ty::UniverseIndex, infcx: &'a InferCtxt<'tcx>, } + + impl<'a, 'tcx> ContainsTermOrNotNameable<'a, 'tcx> { + fn check_nameable(&self, universe: ty::UniverseIndex) -> ControlFlow<()> { + if self.universe_of_term.can_name(universe) { + ControlFlow::Continue(()) + } else { + ControlFlow::Break(()) + } + } + } + impl<'tcx> TypeVisitor> for ContainsTermOrNotNameable<'_, 'tcx> { type BreakTy = (); fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { - if let Some(vid) = t.ty_vid() { - if let ty::TermKind::Ty(term) = self.term.unpack() - && let Some(term_vid) = term.ty_vid() - && self.infcx.root_var(vid) == self.infcx.root_var(term_vid) - { - ControlFlow::Break(()) - } else if self - .universe_of_term - .cannot_name(self.infcx.universe_of_ty(vid).unwrap()) - { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(()) + match *t.kind() { + ty::Infer(ty::TyVar(vid)) => { + if let ty::TermKind::Ty(term) = self.term.unpack() + && let Some(term_vid) = term.ty_vid() + && self.infcx.root_var(vid) == self.infcx.root_var(term_vid) + { + ControlFlow::Break(()) + } else { + self.check_nameable(self.infcx.universe_of_ty(vid).unwrap()) + } + } + ty::Placeholder(p) => self.check_nameable(p.universe), + _ => { + if t.has_non_region_infer() || t.has_placeholders() { + t.super_visit_with(self) + } else { + ControlFlow::Continue(()) + } } - } else if t.has_non_region_infer() { - t.super_visit_with(self) - } else { - ControlFlow::Continue(()) } } fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow { - if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = c.kind() { - if let ty::TermKind::Const(term) = self.term.unpack() - && let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind() - && self.infcx.root_const_var(vid) == self.infcx.root_const_var(term_vid) - { - ControlFlow::Break(()) - } else if self - .universe_of_term - .cannot_name(self.infcx.universe_of_ct(vid).unwrap()) - { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(()) + match c.kind() { + ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { + if let ty::TermKind::Const(term) = self.term.unpack() + && let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind() + && self.infcx.root_const_var(vid) == self.infcx.root_const_var(term_vid) + { + ControlFlow::Break(()) + } else { + self.check_nameable(self.infcx.universe_of_ct(vid).unwrap()) + } + } + ty::ConstKind::Placeholder(p) => self.check_nameable(p.universe), + _ => { + if c.has_non_region_infer() || c.has_placeholders() { + c.super_visit_with(self) + } else { + ControlFlow::Continue(()) + } } - } else if c.has_non_region_infer() { - c.super_visit_with(self) - } else { - ControlFlow::Continue(()) } } } From 67bd410cac0f8717630512188a16eb16e3fd5be9 Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Mon, 26 Feb 2024 12:00:42 -0500 Subject: [PATCH 32/39] Update books --- src/doc/book | 2 +- src/doc/edition-guide | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- src/doc/rustc-dev-guide | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/book b/src/doc/book index 71352deb2072..19c40bfd2d57 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 71352deb20727b4dda9ebfe8182709d5bf17dfea +Subproject commit 19c40bfd2d57641d962f3119a1c343355f1b3c5e diff --git a/src/doc/edition-guide b/src/doc/edition-guide index 76bd48a273a0..e1eead1181a6 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit 76bd48a273a0e0413a3bf22c699112d41497b99e +Subproject commit e1eead1181a691e56299294d5f1d62fe7a26d317 diff --git a/src/doc/reference b/src/doc/reference index 8227666de13f..3417f866932c 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 8227666de13f6e7bb32dea9dc42e841adb5ce4b7 +Subproject commit 3417f866932cb1c09c6be0f31d2a02ee01b4b95d diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index e188d5d466f7..57f1e708f5d5 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit e188d5d466f7f3ff9f1d518393235f4fe951be46 +Subproject commit 57f1e708f5d5850562bc385aaf610e6af14d6ec8 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index 1f30cc7cca9a..7b0ef5b0bea5 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit 1f30cc7cca9a3433bc1872abdc98960b36c21ca0 +Subproject commit 7b0ef5b0bea5e3ce3b9764aa5754a60e2cc05c52 From 580b003edd9653201583df2944875a3605739f96 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Mon, 26 Feb 2024 13:53:35 -0500 Subject: [PATCH 33/39] fix race between block initialization and receiver disconnection --- library/std/src/sync/mpmc/list.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sync/mpmc/list.rs b/library/std/src/sync/mpmc/list.rs index 406a331a3096..a1b275112a1e 100644 --- a/library/std/src/sync/mpmc/list.rs +++ b/library/std/src/sync/mpmc/list.rs @@ -547,7 +547,7 @@ impl Channel { } let mut head = self.head.index.load(Ordering::Acquire); - let mut block = self.head.block.load(Ordering::Acquire); + let mut block = self.head.block.swap(ptr::null_mut(), Ordering::AcqRel); // If we're going to be dropping messages we need to synchronize with initialization if head >> SHIFT != tail >> SHIFT { @@ -588,8 +588,8 @@ impl Channel { drop(Box::from_raw(block)); } } + head &= !MARK_BIT; - self.head.block.store(ptr::null_mut(), Ordering::Release); self.head.index.store(head, Ordering::Release); } From a1b93e8fed23825ce319b8bba8158e2f8d5d5335 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Mon, 26 Feb 2024 19:22:34 +0000 Subject: [PATCH 34/39] Rearrange `Vec::from_raw_parts{,_in}` doc argument order to match code argument order --- library/alloc/src/vec/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index b59699219eb8..7e07a793a66d 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -481,7 +481,7 @@ impl Vec { Self::with_capacity_in(capacity, Global) } - /// Creates a `Vec` directly from a pointer, a capacity, and a length. + /// Creates a `Vec` directly from a pointer, a length, and a capacity. /// /// # Safety /// @@ -672,7 +672,7 @@ impl Vec { Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 } } - /// Creates a `Vec` directly from a pointer, a capacity, a length, + /// Creates a `Vec` directly from a pointer, a length, a capacity, /// and an allocator. /// /// # Safety From 26bdf2900acad2091ab7e59296d3a457011ea770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Mon, 26 Feb 2024 19:24:49 +0000 Subject: [PATCH 35/39] Rearrange `String::from_raw_parts` doc argument order to match code argument order --- library/alloc/src/string.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 6dadbc8e3642..955438f49a10 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -896,7 +896,7 @@ impl String { self.vec.into_raw_parts() } - /// Creates a new `String` from a length, capacity, and pointer. + /// Creates a new `String` from a pointer, a length and a capacity. /// /// # Safety /// From dd24a462d517cf2a0667adf92aaa38502b71b61c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Mon, 26 Feb 2024 19:26:49 +0000 Subject: [PATCH 36/39] Document args returned from `Vec::into_raw_parts{,_with_alloc}` --- library/alloc/src/vec/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 7e07a793a66d..7bd19875584a 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -786,7 +786,7 @@ impl Vec { unsafe { Vec { buf: RawVec::from_raw_parts_in(ptr, capacity, alloc), len: length } } } - /// Decomposes a `Vec` into its raw components. + /// Decomposes a `Vec` into its raw components: `(pointer, length, capacity)`. /// /// Returns the raw pointer to the underlying data, the length of /// the vector (in elements), and the allocated capacity of the @@ -824,7 +824,7 @@ impl Vec { (me.as_mut_ptr(), me.len(), me.capacity()) } - /// Decomposes a `Vec` into its raw components. + /// Decomposes a `Vec` into its raw components: `(pointer, length, capacity, allocator)`. /// /// Returns the raw pointer to the underlying data, the length of the vector (in elements), /// the allocated capacity of the data (in elements), and the allocator. These are the same From bfeea294cc01c295ca5b54dcbfb59ee6953b4fc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Mon, 26 Feb 2024 19:31:51 +0000 Subject: [PATCH 37/39] Document args returned from `String::into_raw_parts` --- library/alloc/src/string.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 955438f49a10..1d3c04f7807a 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -864,7 +864,7 @@ impl String { } } - /// Decomposes a `String` into its raw components. + /// Decomposes a `String` into its raw components: `(pointer, length, capacity)`. /// /// Returns the raw pointer to the underlying data, the length of /// the string (in bytes), and the allocated capacity of the data From 1658ca082a1d510480a7c228b0b6bfb83863d0e9 Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Mon, 26 Feb 2024 21:47:10 +0100 Subject: [PATCH 38/39] Properly emit `expected ;` on `#[attr] expr` --- .../rustc_parse/src/parser/diagnostics.rs | 6 ++--- ...rom-trailing-outer-attribute-in-body-1.rs} | 0 ...trailing-outer-attribute-in-body-1.stderr} | 4 +-- ...from-trailing-outer-attribute-in-body-2.rs | 15 +++++++++++ ...-trailing-outer-attribute-in-body-2.stderr | 26 +++++++++++++++++++ 5 files changed, 45 insertions(+), 6 deletions(-) rename tests/ui/parser/attribute/{properly-recover-from-trailing-outer-attribute-in-body.rs => properly-recover-from-trailing-outer-attribute-in-body-1.rs} (100%) rename tests/ui/parser/attribute/{properly-recover-from-trailing-outer-attribute-in-body.stderr => properly-recover-from-trailing-outer-attribute-in-body-1.stderr} (97%) create mode 100644 tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs create mode 100644 tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index cc1f7c8ac7d5..995e140b3292 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -800,9 +800,8 @@ impl<'a> Parser<'a> { { Ok(next_attr) => next_attr, Err(inner_err) => { - err.cancel(); inner_err.cancel(); - return self.dcx().span_delayed_bug(expr.span, "not a tail expression"); + return err.emit(); } } && let ast::AttrKind::Normal(next_attr_kind) = next_attr.kind @@ -813,9 +812,8 @@ impl<'a> Parser<'a> { let next_expr = match snapshot.parse_expr() { Ok(next_expr) => next_expr, Err(inner_err) => { - err.cancel(); inner_err.cancel(); - return self.dcx().span_delayed_bug(expr.span, "not a tail expression"); + return err.emit(); } }; // We have for sure diff --git a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.rs b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-1.rs similarity index 100% rename from tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.rs rename to tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-1.rs diff --git a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.stderr b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-1.stderr similarity index 97% rename from tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.stderr rename to tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-1.stderr index dd0081cc2dff..dcc2e92c47ad 100644 --- a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.stderr +++ b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-1.stderr @@ -1,5 +1,5 @@ error: expected `;`, found `#` - --> $DIR/properly-recover-from-trailing-outer-attribute-in-body.rs:4:47 + --> $DIR/properly-recover-from-trailing-outer-attribute-in-body-1.rs:4:47 | LL | #[cfg(feature = )] | ------------------ only `;` terminated statements or tail expressions are allowed after this attribute @@ -18,7 +18,7 @@ LL | { [1, 2, 3].iter().map().collect::() } | + + error: expected statement after outer attribute - --> $DIR/properly-recover-from-trailing-outer-attribute-in-body.rs:5:5 + --> $DIR/properly-recover-from-trailing-outer-attribute-in-body-1.rs:5:5 | LL | #[attr] | ^^^^^^^ diff --git a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs new file mode 100644 index 000000000000..ad9e7ad707b5 --- /dev/null +++ b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs @@ -0,0 +1,15 @@ +// Issue #121647: recovery path leaving unemitted error behind + +macro_rules! the_macro { + ( $foo:stmt ; $bar:stmt ; ) => { + #[cfg()] + $foo //~ ERROR expected `;`, found `#` + + #[cfg(bar)] + $bar + }; +} + +fn main() { + the_macro!( (); (); ); +} diff --git a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr new file mode 100644 index 000000000000..7b9b8319674e --- /dev/null +++ b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr @@ -0,0 +1,26 @@ +error: expected `;`, found `#` + --> $DIR/properly-recover-from-trailing-outer-attribute-in-body-2.rs:6:13 + | +LL | #[cfg()] + | -------- only `;` terminated statements or tail expressions are allowed after this attribute +LL | $foo + | ^ expected `;` here +LL | +LL | #[cfg(bar)] + | - unexpected token +... +LL | the_macro!( (); (); ); + | --------------------- in this macro invocation + | + = note: this error originates in the macro `the_macro` (in Nightly builds, run with -Z macro-backtrace for more info) +help: add `;` here + | +LL | $foo; + | + +help: alternatively, consider surrounding the expression with a block + | +LL | the_macro!( { () }; (); ); + | + + + +error: aborting due to 1 previous error + From 42ce2e563aaa2fc3ebf710fd43c0e071cf90a20c Mon Sep 17 00:00:00 2001 From: The Miri Conjob Bot Date: Tue, 27 Feb 2024 04:59:39 +0000 Subject: [PATCH 39/39] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index e62c61b10431..37273d9183a0 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -0250ef2571185b05701ed9d74fc904c17508a397 +71ffdf7ff7ac6df5f9f64de7e780b8345797e8a0