From 13189f48cfd5f481110135a23e63d438e26c76d0 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 12 Feb 2026 11:38:22 +0000 Subject: [PATCH 01/11] use `?` instead of `*` for return types --- library/proc_macro/src/bridge/client.rs | 2 +- library/proc_macro/src/bridge/mod.rs | 2 +- library/proc_macro/src/bridge/server.rs | 8 +++----- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index 02a408802b6fa..696cd4ee3d887 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -98,7 +98,7 @@ pub(crate) use super::symbol::Symbol; macro_rules! define_client_side { ( - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* + $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* ) => { impl Methods { $(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)? { diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 6a9027046af00..603adf720789f 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -133,7 +133,7 @@ impl !Sync for BridgeConfig<'_> {} macro_rules! declare_tags { ( - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* + $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* ) => { #[allow(non_camel_case_types)] pub(super) enum ApiTags { diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index a3c6a232264e0..dc9aa5a72870c 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -60,7 +60,7 @@ struct Dispatcher { macro_rules! define_server { ( - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* + $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* ) => { pub trait Server { type TokenStream: 'static + Clone + Default; @@ -83,7 +83,7 @@ with_api!(define_server, Self::TokenStream, Self::Span, Self::Symbol); macro_rules! define_dispatcher { ( - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* + $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* ) => { // FIXME(eddyb) `pub` only for `ExecutionStrategy` below. pub trait DispatcherTrait { @@ -100,9 +100,7 @@ macro_rules! define_dispatcher { let mut call_method = || { $(let $arg = <$arg_ty>::decode(&mut reader, handle_store).unmark();)* let r = server.$method($($arg),*); - $( - let r: $ret_ty = Mark::mark(r); - )* + $(let r: $ret_ty = Mark::mark(r);)? r }; // HACK(eddyb) don't use `panic::catch_unwind` in a panic. From 2f24a5e491adcbe681df4db7874fa0e4c45d8c76 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 12 Feb 2026 11:38:33 +0000 Subject: [PATCH 02/11] remove `DispatcherTrait` --- library/proc_macro/src/bridge/server.rs | 34 +++++++++++-------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index dc9aa5a72870c..3ab9f40de750a 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -53,11 +53,6 @@ impl Decode<'_, '_, HandleStore> for MarkedSpan { } } -struct Dispatcher { - handle_store: HandleStore, - server: S, -} - macro_rules! define_server { ( $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* @@ -81,16 +76,17 @@ macro_rules! define_server { } with_api!(define_server, Self::TokenStream, Self::Span, Self::Symbol); +// FIXME(eddyb) `pub` only for `ExecutionStrategy` below. +pub struct Dispatcher { + handle_store: HandleStore, + server: S, +} + macro_rules! define_dispatcher { ( $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* ) => { - // FIXME(eddyb) `pub` only for `ExecutionStrategy` below. - pub trait DispatcherTrait { - fn dispatch(&mut self, buf: Buffer) -> Buffer; - } - - impl DispatcherTrait for Dispatcher { + impl Dispatcher { fn dispatch(&mut self, mut buf: Buffer) -> Buffer { let Dispatcher { handle_store, server } = self; @@ -126,9 +122,9 @@ macro_rules! define_dispatcher { with_api!(define_dispatcher, MarkedTokenStream, MarkedSpan, MarkedSymbol); pub trait ExecutionStrategy { - fn run_bridge_and_client( + fn run_bridge_and_client( &self, - dispatcher: &mut impl DispatcherTrait, + dispatcher: &mut Dispatcher, input: Buffer, run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, force_show_panics: bool, @@ -182,9 +178,9 @@ impl

ExecutionStrategy for MaybeCrossThread

where P: MessagePipe + Send + 'static, { - fn run_bridge_and_client( + fn run_bridge_and_client( &self, - dispatcher: &mut impl DispatcherTrait, + dispatcher: &mut Dispatcher, input: Buffer, run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, force_show_panics: bool, @@ -205,9 +201,9 @@ where pub struct SameThread; impl ExecutionStrategy for SameThread { - fn run_bridge_and_client( + fn run_bridge_and_client( &self, - dispatcher: &mut impl DispatcherTrait, + dispatcher: &mut Dispatcher, input: Buffer, run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, force_show_panics: bool, @@ -232,9 +228,9 @@ impl

ExecutionStrategy for CrossThread

where P: MessagePipe + Send + 'static, { - fn run_bridge_and_client( + fn run_bridge_and_client( &self, - dispatcher: &mut impl DispatcherTrait, + dispatcher: &mut Dispatcher, input: Buffer, run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, force_show_panics: bool, From e098327271327f86fb6aac22e64136f4a3268d31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maja=20K=C4=85dzio=C5=82ka?= Date: Tue, 10 Feb 2026 15:10:04 +0100 Subject: [PATCH 03/11] Don't ICE on layout error in vtable computation --- compiler/rustc_middle/src/ty/vtable.rs | 7 ++++--- .../vtable-try-as-dyn.full-debuginfo.stderr | 4 ++++ .../limits/vtable-try-as-dyn.no-debuginfo.stderr | 4 ++++ tests/ui/limits/vtable-try-as-dyn.rs | 15 +++++++++++++++ tests/ui/limits/vtable.rs | 8 ++++++++ tests/ui/limits/vtable.stderr | 4 ++++ 6 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 tests/ui/limits/vtable-try-as-dyn.full-debuginfo.stderr create mode 100644 tests/ui/limits/vtable-try-as-dyn.no-debuginfo.stderr create mode 100644 tests/ui/limits/vtable-try-as-dyn.rs create mode 100644 tests/ui/limits/vtable.rs create mode 100644 tests/ui/limits/vtable.stderr diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index a3e9054fdcb8b..edb1eaea30275 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -99,9 +99,10 @@ pub(super) fn vtable_allocation_provider<'tcx>( // This confirms that the layout computation for &dyn Trait has an accurate sizing. assert!(vtable_entries.len() >= vtable_min_entries(tcx, poly_trait_ref)); - let layout = tcx - .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) - .expect("failed to build vtable representation"); + let layout = match tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) { + Ok(layout) => layout, + Err(e) => tcx.dcx().emit_fatal(e.into_diagnostic()), + }; assert!(layout.is_sized(), "can't create a vtable for an unsized type"); let size = layout.size.bytes(); let align = layout.align.bytes(); diff --git a/tests/ui/limits/vtable-try-as-dyn.full-debuginfo.stderr b/tests/ui/limits/vtable-try-as-dyn.full-debuginfo.stderr new file mode 100644 index 0000000000000..a3772e509ed67 --- /dev/null +++ b/tests/ui/limits/vtable-try-as-dyn.full-debuginfo.stderr @@ -0,0 +1,4 @@ +error: values of the type `[u8; usize::MAX]` are too big for the target architecture + +error: aborting due to 1 previous error + diff --git a/tests/ui/limits/vtable-try-as-dyn.no-debuginfo.stderr b/tests/ui/limits/vtable-try-as-dyn.no-debuginfo.stderr new file mode 100644 index 0000000000000..a3772e509ed67 --- /dev/null +++ b/tests/ui/limits/vtable-try-as-dyn.no-debuginfo.stderr @@ -0,0 +1,4 @@ +error: values of the type `[u8; usize::MAX]` are too big for the target architecture + +error: aborting due to 1 previous error + diff --git a/tests/ui/limits/vtable-try-as-dyn.rs b/tests/ui/limits/vtable-try-as-dyn.rs new file mode 100644 index 0000000000000..4df4f92717f9c --- /dev/null +++ b/tests/ui/limits/vtable-try-as-dyn.rs @@ -0,0 +1,15 @@ +// At the time of writing, vtable.rs would ICE only with debuginfo disabled, while this testcase, +// originally reported as #152030, would ICE even with debuginfo enabled. +//@ revisions: no-debuginfo full-debuginfo +//@ compile-flags: --crate-type=lib --emit=mir +//@[no-debuginfo] compile-flags: -C debuginfo=0 +//@[full-debuginfo] compile-flags: -C debuginfo=2 +#![feature(try_as_dyn)] + +trait Trait {} +impl Trait for T {} + +//~? ERROR: values of the type `[u8; usize::MAX]` are too big for the target architecture +pub fn foo(x: &[u8; usize::MAX]) { + let _ = std::any::try_as_dyn::<[u8; usize::MAX], dyn Trait>(x); +} diff --git a/tests/ui/limits/vtable.rs b/tests/ui/limits/vtable.rs new file mode 100644 index 0000000000000..570eaaec491ca --- /dev/null +++ b/tests/ui/limits/vtable.rs @@ -0,0 +1,8 @@ +//@ compile-flags: --crate-type=lib --emit=mir -C debuginfo=0 +pub trait Trait {} +impl Trait for T {} + +//~? ERROR: values of the type `[u8; usize::MAX]` are too big for the target architecture +pub fn foo(x: &[u8; usize::MAX]) -> &dyn Trait { + x as &dyn Trait +} diff --git a/tests/ui/limits/vtable.stderr b/tests/ui/limits/vtable.stderr new file mode 100644 index 0000000000000..a3772e509ed67 --- /dev/null +++ b/tests/ui/limits/vtable.stderr @@ -0,0 +1,4 @@ +error: values of the type `[u8; usize::MAX]` are too big for the target architecture + +error: aborting due to 1 previous error + From 31053484a791cef24e04e8b9bb9e28366dd63e91 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 12 Feb 2026 12:14:14 +0000 Subject: [PATCH 04/11] replace `MessagePipe` trait with its impl --- compiler/rustc_expand/src/proc_macro.rs | 23 +--------- library/proc_macro/src/bridge/server.rs | 57 +++++++++++-------------- 2 files changed, 27 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index ea63ff7bfc46a..530e7b998d417 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -11,29 +11,8 @@ use {rustc_ast as ast, rustc_proc_macro as pm}; use crate::base::{self, *}; use crate::{errors, proc_macro_server}; -struct MessagePipe { - tx: std::sync::mpsc::SyncSender, - rx: std::sync::mpsc::Receiver, -} - -impl pm::bridge::server::MessagePipe for MessagePipe { - fn new() -> (Self, Self) { - let (tx1, rx1) = std::sync::mpsc::sync_channel(1); - let (tx2, rx2) = std::sync::mpsc::sync_channel(1); - (MessagePipe { tx: tx1, rx: rx2 }, MessagePipe { tx: tx2, rx: rx1 }) - } - - fn send(&mut self, value: T) { - self.tx.send(value).unwrap(); - } - - fn recv(&mut self) -> Option { - self.rx.recv().ok() - } -} - fn exec_strategy(sess: &Session) -> impl pm::bridge::server::ExecutionStrategy + 'static { - pm::bridge::server::MaybeCrossThread::>::new( + pm::bridge::server::MaybeCrossThread::new( sess.opts.unstable_opts.proc_macro_execution_strategy == ProcMacroExecutionStrategy::CrossThread, ) diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index 3ab9f40de750a..b5b63ead44642 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -1,7 +1,7 @@ //! Server-side traits. use std::cell::Cell; -use std::marker::PhantomData; +use std::sync::mpsc; use super::*; @@ -163,21 +163,17 @@ impl Drop for RunningSameThreadGuard { } } -pub struct MaybeCrossThread

{ +pub struct MaybeCrossThread { cross_thread: bool, - marker: PhantomData

, } -impl

MaybeCrossThread

{ +impl MaybeCrossThread { pub const fn new(cross_thread: bool) -> Self { - MaybeCrossThread { cross_thread, marker: PhantomData } + MaybeCrossThread { cross_thread } } } -impl

ExecutionStrategy for MaybeCrossThread

-where - P: MessagePipe + Send + 'static, -{ +impl ExecutionStrategy for MaybeCrossThread { fn run_bridge_and_client( &self, dispatcher: &mut Dispatcher, @@ -186,12 +182,7 @@ where force_show_panics: bool, ) -> Buffer { if self.cross_thread || ALREADY_RUNNING_SAME_THREAD.get() { - >::new().run_bridge_and_client( - dispatcher, - input, - run_client, - force_show_panics, - ) + CrossThread.run_bridge_and_client(dispatcher, input, run_client, force_show_panics) } else { SameThread.run_bridge_and_client(dispatcher, input, run_client, force_show_panics) } @@ -216,18 +207,9 @@ impl ExecutionStrategy for SameThread { } } -pub struct CrossThread

(PhantomData

); +pub struct CrossThread; -impl

CrossThread

{ - pub const fn new() -> Self { - CrossThread(PhantomData) - } -} - -impl

ExecutionStrategy for CrossThread

-where - P: MessagePipe + Send + 'static, -{ +impl ExecutionStrategy for CrossThread { fn run_bridge_and_client( &self, dispatcher: &mut Dispatcher, @@ -235,7 +217,7 @@ where run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, force_show_panics: bool, ) -> Buffer { - let (mut server, mut client) = P::new(); + let (mut server, mut client) = MessagePipe::new(); let join_handle = thread::spawn(move || { let mut dispatch = |b: Buffer| -> Buffer { @@ -255,18 +237,31 @@ where } /// A message pipe used for communicating between server and client threads. -pub trait MessagePipe: Sized { +struct MessagePipe { + tx: std::sync::mpsc::SyncSender, + rx: std::sync::mpsc::Receiver, +} + +impl MessagePipe { /// Creates a new pair of endpoints for the message pipe. - fn new() -> (Self, Self); + fn new() -> (Self, Self) { + let (tx1, rx1) = mpsc::sync_channel(1); + let (tx2, rx2) = mpsc::sync_channel(1); + (MessagePipe { tx: tx1, rx: rx2 }, MessagePipe { tx: tx2, rx: rx1 }) + } /// Send a message to the other endpoint of this pipe. - fn send(&mut self, value: T); + fn send(&mut self, value: T) { + self.tx.send(value).unwrap(); + } /// Receive a message from the other endpoint of this pipe. /// /// Returns `None` if the other end of the pipe has been destroyed, and no /// message was received. - fn recv(&mut self) -> Option; + fn recv(&mut self) -> Option { + self.rx.recv().ok() + } } fn run_server< From f601b29825f874ba05e67631ddb80a2b830cc03c Mon Sep 17 00:00:00 2001 From: cyrgani Date: Fri, 13 Feb 2026 11:24:50 +0000 Subject: [PATCH 05/11] inline `SameThread` and `CrossThread` --- compiler/rustc_expand/src/proc_macro.rs | 6 +- library/proc_macro/src/bridge/server.rs | 92 +++++++------------ .../proc-macro-srv/src/dylib/proc_macros.rs | 6 +- 3 files changed, 40 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 530e7b998d417..e678557008133 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -12,10 +12,10 @@ use crate::base::{self, *}; use crate::{errors, proc_macro_server}; fn exec_strategy(sess: &Session) -> impl pm::bridge::server::ExecutionStrategy + 'static { - pm::bridge::server::MaybeCrossThread::new( - sess.opts.unstable_opts.proc_macro_execution_strategy + pm::bridge::server::MaybeCrossThread { + cross_thread: sess.opts.unstable_opts.proc_macro_execution_strategy == ProcMacroExecutionStrategy::CrossThread, - ) + } } pub struct BangProcMacro { diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index b5b63ead44642..1151798fccf40 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -121,10 +121,13 @@ macro_rules! define_dispatcher { } with_api!(define_dispatcher, MarkedTokenStream, MarkedSpan, MarkedSymbol); +// This trait is currently only implemented and used once, inside of this crate. +// We keep it public to allow implementing more complex execution strategies in +// the future, such as wasm proc-macros. pub trait ExecutionStrategy { - fn run_bridge_and_client( + fn run_bridge_and_client( &self, - dispatcher: &mut Dispatcher, + dispatcher: &mut Dispatcher, input: Buffer, run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, force_show_panics: bool, @@ -164,82 +167,55 @@ impl Drop for RunningSameThreadGuard { } pub struct MaybeCrossThread { - cross_thread: bool, + pub cross_thread: bool, } -impl MaybeCrossThread { - pub const fn new(cross_thread: bool) -> Self { - MaybeCrossThread { cross_thread } - } -} +pub const SAME_THREAD: MaybeCrossThread = MaybeCrossThread { cross_thread: false }; +pub const CROSS_THREAD: MaybeCrossThread = MaybeCrossThread { cross_thread: true }; impl ExecutionStrategy for MaybeCrossThread { - fn run_bridge_and_client( + fn run_bridge_and_client( &self, - dispatcher: &mut Dispatcher, + dispatcher: &mut Dispatcher, input: Buffer, run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, force_show_panics: bool, ) -> Buffer { if self.cross_thread || ALREADY_RUNNING_SAME_THREAD.get() { - CrossThread.run_bridge_and_client(dispatcher, input, run_client, force_show_panics) - } else { - SameThread.run_bridge_and_client(dispatcher, input, run_client, force_show_panics) - } - } -} - -pub struct SameThread; - -impl ExecutionStrategy for SameThread { - fn run_bridge_and_client( - &self, - dispatcher: &mut Dispatcher, - input: Buffer, - run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer { - let _guard = RunningSameThreadGuard::new(); - - let mut dispatch = |buf| dispatcher.dispatch(buf); - - run_client(BridgeConfig { input, dispatch: (&mut dispatch).into(), force_show_panics }) - } -} - -pub struct CrossThread; + let (mut server, mut client) = MessagePipe::new(); + + let join_handle = thread::spawn(move || { + let mut dispatch = |b: Buffer| -> Buffer { + client.send(b); + client.recv().expect("server died while client waiting for reply") + }; + + run_client(BridgeConfig { + input, + dispatch: (&mut dispatch).into(), + force_show_panics, + }) + }); + + while let Some(b) = server.recv() { + server.send(dispatcher.dispatch(b)); + } -impl ExecutionStrategy for CrossThread { - fn run_bridge_and_client( - &self, - dispatcher: &mut Dispatcher, - input: Buffer, - run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer { - let (mut server, mut client) = MessagePipe::new(); + join_handle.join().unwrap() + } else { + let _guard = RunningSameThreadGuard::new(); - let join_handle = thread::spawn(move || { - let mut dispatch = |b: Buffer| -> Buffer { - client.send(b); - client.recv().expect("server died while client waiting for reply") - }; + let mut dispatch = |buf| dispatcher.dispatch(buf); run_client(BridgeConfig { input, dispatch: (&mut dispatch).into(), force_show_panics }) - }); - - while let Some(b) = server.recv() { - server.send(dispatcher.dispatch(b)); } - - join_handle.join().unwrap() } } /// A message pipe used for communicating between server and client threads. struct MessagePipe { - tx: std::sync::mpsc::SyncSender, - rx: std::sync::mpsc::Receiver, + tx: mpsc::SyncSender, + rx: mpsc::Receiver, } impl MessagePipe { diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/proc_macros.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/proc_macros.rs index 76c5097101c70..4065dbd0b49bc 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/proc_macros.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/proc_macros.rs @@ -30,7 +30,7 @@ impl ProcMacros { if *trait_name == macro_name => { let res = client.run( - &bridge::server::SameThread, + &bridge::server::SAME_THREAD, S::make_server(call_site, def_site, mixed_site, callback), macro_body, cfg!(debug_assertions), @@ -39,7 +39,7 @@ impl ProcMacros { } bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => { let res = client.run( - &bridge::server::SameThread, + &bridge::server::SAME_THREAD, S::make_server(call_site, def_site, mixed_site, callback), macro_body, cfg!(debug_assertions), @@ -48,7 +48,7 @@ impl ProcMacros { } bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => { let res = client.run( - &bridge::server::SameThread, + &bridge::server::SAME_THREAD, S::make_server(call_site, def_site, mixed_site, callback), parsed_attributes, macro_body, From ab13120882d43a6e4bef72ec1cd6750e24482041 Mon Sep 17 00:00:00 2001 From: Oscar Bray Date: Fri, 13 Feb 2026 13:16:21 +0000 Subject: [PATCH 06/11] Port #[rustc_proc_macro_decls] to the new attribute parser. --- .../rustc_attr_parsing/src/attributes/macro_attrs.rs | 9 +++++++++ compiler/rustc_attr_parsing/src/context.rs | 1 + compiler/rustc_hir/src/attrs/data_structures.rs | 3 +++ compiler/rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_interface/src/proc_macro_decls.rs | 7 +++---- compiler/rustc_passes/src/check_attr.rs | 2 +- 6 files changed, 18 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index d37915b1b80b2..00d40687fc85e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -206,3 +206,12 @@ impl SingleAttributeParser for CollapseDebugInfoParser { Some(AttributeKind::CollapseDebugInfo(info)) } } + +pub(crate) struct RustcProcMacroDeclsParser; + +impl NoArgsAttributeParser for RustcProcMacroDeclsParser { + const PATH: &[Symbol] = &[sym::rustc_proc_macro_decls]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Static)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcProcMacroDecls; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index c6f0914bfbdaf..f68b27dd58a6b 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -297,6 +297,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index e28ecd06b89bc..877f2b0afe495 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1288,6 +1288,9 @@ pub enum AttributeKind { /// Represents `#[rustc_preserve_ub_checks]` RustcPreserveUbChecks, + /// Represents `#[rustc_proc_macro_decls]` + RustcProcMacroDecls, + /// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint). RustcPubTransparent(Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index b4cf244bfb8aa..0d8e70a9f39b5 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -156,6 +156,7 @@ impl AttributeKind { RustcPassByValue(..) => Yes, RustcPassIndirectlyInNonRusticAbis(..) => No, RustcPreserveUbChecks => No, + RustcProcMacroDecls => No, RustcPubTransparent(..) => Yes, RustcReallocator => No, RustcRegions => No, diff --git a/compiler/rustc_interface/src/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs index a2c1f1dbeda6b..bd08faa1ed3a4 100644 --- a/compiler/rustc_interface/src/proc_macro_decls.rs +++ b/compiler/rustc_interface/src/proc_macro_decls.rs @@ -1,15 +1,14 @@ -use rustc_ast::attr; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::LocalDefId; +use rustc_hir::find_attr; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; -use rustc_span::sym; fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option { let mut decls = None; for id in tcx.hir_free_items() { - let attrs = tcx.hir_attrs(id.hir_id()); - if attr::contains_name(attrs, sym::rustc_proc_macro_decls) { + if find_attr!(tcx.hir_attrs(id.hir_id()), AttributeKind::RustcProcMacroDecls) { decls = Some(id.owner_id.def_id); } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 08f2597e874d8..9dcf1ae74d002 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -348,6 +348,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcPassByValue (..) | AttributeKind::RustcPassIndirectlyInNonRusticAbis(..) | AttributeKind::RustcPreserveUbChecks + | AttributeKind::RustcProcMacroDecls | AttributeKind::RustcReallocator | AttributeKind::RustcRegions | AttributeKind::RustcReservationImpl(..) @@ -406,7 +407,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::rustc_doc_primitive | sym::rustc_test_marker | sym::rustc_layout - | sym::rustc_proc_macro_decls | sym::rustc_autodiff | sym::rustc_capture_analysis | sym::rustc_mir From 87a2fc03936a9208ee09b27c31514dd390f951f6 Mon Sep 17 00:00:00 2001 From: okaneco <47607823+okaneco@users.noreply.github.com> Date: Wed, 11 Feb 2026 21:27:51 -0500 Subject: [PATCH 07/11] core: Implement feature `float_exact_integer_constants` Implement accepted ACP for `MAX_EXACT_INTEGER` and `MIN_EXACT_INTEGER` on `f16`, `f32`, `f64`, and `f128` Add tests to `coretests/tests/floats/mod.rs` --- library/core/src/num/f128.rs | 60 +++++++++++++++++ library/core/src/num/f16.rs | 60 +++++++++++++++++ library/core/src/num/f32.rs | 52 +++++++++++++++ library/core/src/num/f64.rs | 52 +++++++++++++++ library/coretests/tests/floats/mod.rs | 93 +++++++++++++++++++++++++++ library/coretests/tests/lib.rs | 1 + 6 files changed, 318 insertions(+) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index d114b821655bf..3fdb10dbffb84 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -275,6 +275,66 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] pub const NEG_INFINITY: f128 = -1.0_f128 / 0.0_f128; + /// Maximum integer that can be represented exactly in an [`f128`] value, + /// with no other integer converting to the same floating point value. + /// + /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, + /// there is a "one-to-one" mapping between [`i128`] and [`f128`] values. + /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f128`] and back to + /// [`i128`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f128`] value + /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a + /// "one-to-one" mapping. + /// + /// [`MAX_EXACT_INTEGER`]: f128::MAX_EXACT_INTEGER + /// [`MIN_EXACT_INTEGER`]: f128::MIN_EXACT_INTEGER + /// ``` + /// #![feature(f128)] + /// #![feature(float_exact_integer_constants)] + /// # #[cfg(target_has_reliable_f128)] { + /// let max_exact_int = f128::MAX_EXACT_INTEGER; + /// assert_eq!(max_exact_int, max_exact_int as f128 as i128); + /// assert_eq!(max_exact_int + 1, (max_exact_int + 1) as f128 as i128); + /// assert_ne!(max_exact_int + 2, (max_exact_int + 2) as f128 as i128); + /// + /// // Beyond `f128::MAX_EXACT_INTEGER`, multiple integers can map to one float value + /// assert_eq!((max_exact_int + 1) as f128, (max_exact_int + 2) as f128); + /// # } + /// ``` + // #[unstable(feature = "f128", issue = "116909")] + #[unstable(feature = "float_exact_integer_constants", issue = "152466")] + pub const MAX_EXACT_INTEGER: i128 = (1 << Self::MANTISSA_DIGITS) - 1; + + /// Minimum integer that can be represented exactly in an [`f128`] value, + /// with no other integer converting to the same floating point value. + /// + /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, + /// there is a "one-to-one" mapping between [`i128`] and [`f128`] values. + /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f128`] and back to + /// [`i128`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f128`] value + /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a + /// "one-to-one" mapping. + /// + /// This constant is equivalent to `-MAX_EXACT_INTEGER`. + /// + /// [`MAX_EXACT_INTEGER`]: f128::MAX_EXACT_INTEGER + /// [`MIN_EXACT_INTEGER`]: f128::MIN_EXACT_INTEGER + /// ``` + /// #![feature(f128)] + /// #![feature(float_exact_integer_constants)] + /// # #[cfg(target_has_reliable_f128)] { + /// let min_exact_int = f128::MIN_EXACT_INTEGER; + /// assert_eq!(min_exact_int, min_exact_int as f128 as i128); + /// assert_eq!(min_exact_int - 1, (min_exact_int - 1) as f128 as i128); + /// assert_ne!(min_exact_int - 2, (min_exact_int - 2) as f128 as i128); + /// + /// // Below `f128::MIN_EXACT_INTEGER`, multiple integers can map to one float value + /// assert_eq!((min_exact_int - 1) as f128, (min_exact_int - 2) as f128); + /// # } + /// ``` + // #[unstable(feature = "f128", issue = "116909")] + #[unstable(feature = "float_exact_integer_constants", issue = "152466")] + pub const MIN_EXACT_INTEGER: i128 = -Self::MAX_EXACT_INTEGER; + /// Sign bit pub(crate) const SIGN_MASK: u128 = 0x8000_0000_0000_0000_0000_0000_0000_0000; diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 373225c5806c1..5000aec34518a 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -269,6 +269,66 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] pub const NEG_INFINITY: f16 = -1.0_f16 / 0.0_f16; + /// Maximum integer that can be represented exactly in an [`f16`] value, + /// with no other integer converting to the same floating point value. + /// + /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, + /// there is a "one-to-one" mapping between [`i16`] and [`f16`] values. + /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f16`] and back to + /// [`i16`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f16`] value + /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a + /// "one-to-one" mapping. + /// + /// [`MAX_EXACT_INTEGER`]: f16::MAX_EXACT_INTEGER + /// [`MIN_EXACT_INTEGER`]: f16::MIN_EXACT_INTEGER + /// ``` + /// #![feature(f16)] + /// #![feature(float_exact_integer_constants)] + /// # #[cfg(target_has_reliable_f16)] { + /// let max_exact_int = f16::MAX_EXACT_INTEGER; + /// assert_eq!(max_exact_int, max_exact_int as f16 as i16); + /// assert_eq!(max_exact_int + 1, (max_exact_int + 1) as f16 as i16); + /// assert_ne!(max_exact_int + 2, (max_exact_int + 2) as f16 as i16); + /// + /// // Beyond `f16::MAX_EXACT_INTEGER`, multiple integers can map to one float value + /// assert_eq!((max_exact_int + 1) as f16, (max_exact_int + 2) as f16); + /// # } + /// ``` + // #[unstable(feature = "f16", issue = "116909")] + #[unstable(feature = "float_exact_integer_constants", issue = "152466")] + pub const MAX_EXACT_INTEGER: i16 = (1 << Self::MANTISSA_DIGITS) - 1; + + /// Minimum integer that can be represented exactly in an [`f16`] value, + /// with no other integer converting to the same floating point value. + /// + /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, + /// there is a "one-to-one" mapping between [`i16`] and [`f16`] values. + /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f16`] and back to + /// [`i16`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f16`] value + /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a + /// "one-to-one" mapping. + /// + /// This constant is equivalent to `-MAX_EXACT_INTEGER`. + /// + /// [`MAX_EXACT_INTEGER`]: f16::MAX_EXACT_INTEGER + /// [`MIN_EXACT_INTEGER`]: f16::MIN_EXACT_INTEGER + /// ``` + /// #![feature(f16)] + /// #![feature(float_exact_integer_constants)] + /// # #[cfg(target_has_reliable_f16)] { + /// let min_exact_int = f16::MIN_EXACT_INTEGER; + /// assert_eq!(min_exact_int, min_exact_int as f16 as i16); + /// assert_eq!(min_exact_int - 1, (min_exact_int - 1) as f16 as i16); + /// assert_ne!(min_exact_int - 2, (min_exact_int - 2) as f16 as i16); + /// + /// // Below `f16::MIN_EXACT_INTEGER`, multiple integers can map to one float value + /// assert_eq!((min_exact_int - 1) as f16, (min_exact_int - 2) as f16); + /// # } + /// ``` + // #[unstable(feature = "f16", issue = "116909")] + #[unstable(feature = "float_exact_integer_constants", issue = "152466")] + pub const MIN_EXACT_INTEGER: i16 = -Self::MAX_EXACT_INTEGER; + /// Sign bit pub(crate) const SIGN_MASK: u16 = 0x8000; diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index f3c7961931a1d..e108b24a7d451 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -513,6 +513,58 @@ impl f32 { #[stable(feature = "assoc_int_consts", since = "1.43.0")] pub const NEG_INFINITY: f32 = -1.0_f32 / 0.0_f32; + /// Maximum integer that can be represented exactly in an [`f32`] value, + /// with no other integer converting to the same floating point value. + /// + /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, + /// there is a "one-to-one" mapping between [`i32`] and [`f32`] values. + /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f32`] and back to + /// [`i32`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f32`] value + /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a + /// "one-to-one" mapping. + /// + /// [`MAX_EXACT_INTEGER`]: f32::MAX_EXACT_INTEGER + /// [`MIN_EXACT_INTEGER`]: f32::MIN_EXACT_INTEGER + /// ``` + /// #![feature(float_exact_integer_constants)] + /// let max_exact_int = f32::MAX_EXACT_INTEGER; + /// assert_eq!(max_exact_int, max_exact_int as f32 as i32); + /// assert_eq!(max_exact_int + 1, (max_exact_int + 1) as f32 as i32); + /// assert_ne!(max_exact_int + 2, (max_exact_int + 2) as f32 as i32); + /// + /// // Beyond `f32::MAX_EXACT_INTEGER`, multiple integers can map to one float value + /// assert_eq!((max_exact_int + 1) as f32, (max_exact_int + 2) as f32); + /// ``` + #[unstable(feature = "float_exact_integer_constants", issue = "152466")] + pub const MAX_EXACT_INTEGER: i32 = (1 << Self::MANTISSA_DIGITS) - 1; + + /// Minimum integer that can be represented exactly in an [`f32`] value, + /// with no other integer converting to the same floating point value. + /// + /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, + /// there is a "one-to-one" mapping between [`i32`] and [`f32`] values. + /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f32`] and back to + /// [`i32`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f32`] value + /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a + /// "one-to-one" mapping. + /// + /// This constant is equivalent to `-MAX_EXACT_INTEGER`. + /// + /// [`MAX_EXACT_INTEGER`]: f32::MAX_EXACT_INTEGER + /// [`MIN_EXACT_INTEGER`]: f32::MIN_EXACT_INTEGER + /// ``` + /// #![feature(float_exact_integer_constants)] + /// let min_exact_int = f32::MIN_EXACT_INTEGER; + /// assert_eq!(min_exact_int, min_exact_int as f32 as i32); + /// assert_eq!(min_exact_int - 1, (min_exact_int - 1) as f32 as i32); + /// assert_ne!(min_exact_int - 2, (min_exact_int - 2) as f32 as i32); + /// + /// // Below `f32::MIN_EXACT_INTEGER`, multiple integers can map to one float value + /// assert_eq!((min_exact_int - 1) as f32, (min_exact_int - 2) as f32); + /// ``` + #[unstable(feature = "float_exact_integer_constants", issue = "152466")] + pub const MIN_EXACT_INTEGER: i32 = -Self::MAX_EXACT_INTEGER; + /// Sign bit pub(crate) const SIGN_MASK: u32 = 0x8000_0000; diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index a6fd3b1cb5d07..c1ee50532875c 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -512,6 +512,58 @@ impl f64 { #[stable(feature = "assoc_int_consts", since = "1.43.0")] pub const NEG_INFINITY: f64 = -1.0_f64 / 0.0_f64; + /// Maximum integer that can be represented exactly in an [`f64`] value, + /// with no other integer converting to the same floating point value. + /// + /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, + /// there is a "one-to-one" mapping between [`i64`] and [`f64`] values. + /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f64`] and back to + /// [`i64`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f64`] value + /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a + /// "one-to-one" mapping. + /// + /// [`MAX_EXACT_INTEGER`]: f64::MAX_EXACT_INTEGER + /// [`MIN_EXACT_INTEGER`]: f64::MIN_EXACT_INTEGER + /// ``` + /// #![feature(float_exact_integer_constants)] + /// let max_exact_int = f64::MAX_EXACT_INTEGER; + /// assert_eq!(max_exact_int, max_exact_int as f64 as i64); + /// assert_eq!(max_exact_int + 1, (max_exact_int + 1) as f64 as i64); + /// assert_ne!(max_exact_int + 2, (max_exact_int + 2) as f64 as i64); + /// + /// // Beyond `f64::MAX_EXACT_INTEGER`, multiple integers can map to one float value + /// assert_eq!((max_exact_int + 1) as f64, (max_exact_int + 2) as f64); + /// ``` + #[unstable(feature = "float_exact_integer_constants", issue = "152466")] + pub const MAX_EXACT_INTEGER: i64 = (1 << Self::MANTISSA_DIGITS) - 1; + + /// Minimum integer that can be represented exactly in an [`f64`] value, + /// with no other integer converting to the same floating point value. + /// + /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, + /// there is a "one-to-one" mapping between [`i64`] and [`f64`] values. + /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f64`] and back to + /// [`i64`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f64`] value + /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a + /// "one-to-one" mapping. + /// + /// This constant is equivalent to `-MAX_EXACT_INTEGER`. + /// + /// [`MAX_EXACT_INTEGER`]: f64::MAX_EXACT_INTEGER + /// [`MIN_EXACT_INTEGER`]: f64::MIN_EXACT_INTEGER + /// ``` + /// #![feature(float_exact_integer_constants)] + /// let min_exact_int = f64::MIN_EXACT_INTEGER; + /// assert_eq!(min_exact_int, min_exact_int as f64 as i64); + /// assert_eq!(min_exact_int - 1, (min_exact_int - 1) as f64 as i64); + /// assert_ne!(min_exact_int - 2, (min_exact_int - 2) as f64 as i64); + /// + /// // Below `f64::MIN_EXACT_INTEGER`, multiple integers can map to one float value + /// assert_eq!((min_exact_int - 1) as f64, (min_exact_int - 2) as f64); + /// ``` + #[unstable(feature = "float_exact_integer_constants", issue = "152466")] + pub const MIN_EXACT_INTEGER: i64 = -Self::MAX_EXACT_INTEGER; + /// Sign bit pub(crate) const SIGN_MASK: u64 = 0x8000_0000_0000_0000; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 06fc3c96eafc8..61d9b28c02aa9 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -4,6 +4,8 @@ use std::ops::{Add, Div, Mul, Rem, Sub}; trait TestableFloat: Sized { /// Unsigned int with the same size, for converting to/from bits. type Int; + /// Signed int with the same size. + type SInt; /// Set the default tolerance for float comparison based on the type. const APPROX: Self; /// Allow looser tolerance for f32 on miri @@ -44,6 +46,7 @@ trait TestableFloat: Sized { impl TestableFloat for f16 { type Int = u16; + type SInt = i16; const APPROX: Self = 1e-3; const _180_TO_RADIANS_APPROX: Self = 1e-2; const PI_TO_DEGREES_APPROX: Self = 0.125; @@ -71,6 +74,7 @@ impl TestableFloat for f16 { impl TestableFloat for f32 { type Int = u32; + type SInt = i32; const APPROX: Self = 1e-6; /// Miri adds some extra errors to float functions; make sure the tests still pass. /// These values are purely used as a canary to test against and are thus not a stable guarantee Rust provides. @@ -100,6 +104,7 @@ impl TestableFloat for f32 { impl TestableFloat for f64 { type Int = u64; + type SInt = i64; const APPROX: Self = 1e-6; const ZERO: Self = 0.0; const ONE: Self = 1.0; @@ -125,6 +130,7 @@ impl TestableFloat for f64 { impl TestableFloat for f128 { type Int = u128; + type SInt = i128; const APPROX: Self = 1e-9; const ZERO: Self = 0.0; const ONE: Self = 1.0; @@ -1632,6 +1638,93 @@ float_test! { } } +// Test the `float_exact_integer_constants` feature +float_test! { + name: max_exact_integer_constant, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + // The maximum integer that converts to a unique floating point + // value. + const MAX_EXACT_INTEGER: ::SInt = Float::MAX_EXACT_INTEGER; + + let max_minus_one = (MAX_EXACT_INTEGER - 1) as Float as ::SInt; + let max_plus_one = (MAX_EXACT_INTEGER + 1) as Float as ::SInt; + let max_plus_two = (MAX_EXACT_INTEGER + 2) as Float as ::SInt; + + // This does an extra round trip back to float for the second operand in + // order to print the results if there is a mismatch + assert_biteq!((MAX_EXACT_INTEGER - 1) as Float, max_minus_one as Float); + assert_biteq!(MAX_EXACT_INTEGER as Float, MAX_EXACT_INTEGER as Float as ::SInt as Float); + assert_biteq!((MAX_EXACT_INTEGER + 1) as Float, max_plus_one as Float); + // The first non-unique conversion, where `max_plus_two` roundtrips to + // `max_plus_one` + assert_biteq!((MAX_EXACT_INTEGER + 1) as Float, (MAX_EXACT_INTEGER + 2) as Float); + assert_biteq!((MAX_EXACT_INTEGER + 2) as Float, max_plus_one as Float); + assert_biteq!((MAX_EXACT_INTEGER + 2) as Float, max_plus_two as Float); + + // Lossless roundtrips, for integers + assert!(MAX_EXACT_INTEGER - 1 == max_minus_one); + assert!(MAX_EXACT_INTEGER == MAX_EXACT_INTEGER as Float as ::SInt); + assert!(MAX_EXACT_INTEGER + 1 == max_plus_one); + // The first non-unique conversion, where `max_plus_two` roundtrips to + // one less than the starting value + assert!(MAX_EXACT_INTEGER + 2 != max_plus_two); + + // max-1 | max+0 | max+1 | max+2 + // After roundtripping, +1 and +2 will equal each other + assert!(max_minus_one != MAX_EXACT_INTEGER); + assert!(MAX_EXACT_INTEGER != max_plus_one); + assert!(max_plus_one == max_plus_two); + } +} + +float_test! { + name: min_exact_integer_constant, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + // The minimum integer that converts to a unique floating point + // value. + const MIN_EXACT_INTEGER: ::SInt = Float::MIN_EXACT_INTEGER; + + // Same logic as the `max` test, but we work our way leftward + // across the number line from (min_exact + 1) to (min_exact - 2). + let min_plus_one = (MIN_EXACT_INTEGER + 1) as Float as ::SInt; + let min_minus_one = (MIN_EXACT_INTEGER - 1) as Float as ::SInt; + let min_minus_two = (MIN_EXACT_INTEGER - 2) as Float as ::SInt; + + // This does an extra round trip back to float for the second operand in + // order to print the results if there is a mismatch + assert_biteq!((MIN_EXACT_INTEGER + 1) as Float, min_plus_one as Float); + assert_biteq!(MIN_EXACT_INTEGER as Float, MIN_EXACT_INTEGER as Float as ::SInt as Float); + assert_biteq!((MIN_EXACT_INTEGER - 1) as Float, min_minus_one as Float); + // The first non-unique conversion, which roundtrips to one + // greater than the starting value. + assert_biteq!((MIN_EXACT_INTEGER - 1) as Float, (MIN_EXACT_INTEGER - 2) as Float); + assert_biteq!((MIN_EXACT_INTEGER - 2) as Float, min_minus_one as Float); + assert_biteq!((MIN_EXACT_INTEGER - 2) as Float, min_minus_two as Float); + + // Lossless roundtrips, for integers + assert!(MIN_EXACT_INTEGER + 1 == min_plus_one); + assert!(MIN_EXACT_INTEGER == MIN_EXACT_INTEGER as Float as ::SInt); + assert!(MIN_EXACT_INTEGER - 1 == min_minus_one); + // The first non-unique conversion, which roundtrips to one + // greater than the starting value. + assert!(MIN_EXACT_INTEGER - 2 != min_minus_two); + + // min-2 | min-1 | min | min+1 + // After roundtripping, -2 and -1 will equal each other. + assert!(min_plus_one != MIN_EXACT_INTEGER); + assert!(MIN_EXACT_INTEGER != min_minus_one); + assert!(min_minus_one == min_minus_two); + } +} + // FIXME(f128): Uncomment and adapt these tests once the From<{u64,i64}> impls are added. // float_test! { // name: from_u64_i64, diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 3a30b6b7edcc8..d81b09d2d7141 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -52,6 +52,7 @@ #![feature(f16)] #![feature(f128)] #![feature(float_algebraic)] +#![feature(float_exact_integer_constants)] #![feature(float_minimum_maximum)] #![feature(flt2dec)] #![feature(fmt_internals)] From 6d854266ea4bb0d11444e19da4571f3df1da9683 Mon Sep 17 00:00:00 2001 From: okaneco <47607823+okaneco@users.noreply.github.com> Date: Thu, 12 Feb 2026 15:38:13 -0500 Subject: [PATCH 08/11] [cg_clif]: Fix codegen of f128 to i128 casts Correct name for intrinsic that converts f128 to u128 Use `to_signed` instead of `from_signed` to ensure proper intrinsic selected for u128/i128 --- compiler/rustc_codegen_cranelift/src/codegen_f16_f128.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_cranelift/src/codegen_f16_f128.rs b/compiler/rustc_codegen_cranelift/src/codegen_f16_f128.rs index 86bff32dc623c..d8977657e305d 100644 --- a/compiler/rustc_codegen_cranelift/src/codegen_f16_f128.rs +++ b/compiler/rustc_codegen_cranelift/src/codegen_f16_f128.rs @@ -208,7 +208,7 @@ pub(crate) fn codegen_cast( let ret_ty = if to_ty.bits() < 32 { types::I32 } else { to_ty }; let name = format!( "__fix{sign}tf{size}i", - sign = if from_signed { "" } else { "un" }, + sign = if to_signed { "" } else { "uns" }, size = match ret_ty { types::I32 => 's', types::I64 => 'd', From 8af02e230aac276d7eaa538729abca8618f02225 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Tue, 3 Feb 2026 01:08:44 +0900 Subject: [PATCH 09/11] mGCA: Validate const literal against expected type Co-authored-by: Boxy --- .../src/hir_ty_lowering/mod.rs | 27 ++++-- .../rustc_middle/src/mir/interpret/mod.rs | 38 ++++++++ compiler/rustc_middle/src/queries.rs | 2 +- compiler/rustc_middle/src/query/erase.rs | 4 + compiler/rustc_mir_build/src/thir/constant.rs | 89 ++++++++++++------- .../rustc_mir_build/src/thir/pattern/mod.rs | 17 +++- compiler/rustc_ty_utils/src/consts.rs | 5 +- .../byte-string-u8-validation.rs | 2 +- .../byte-string-u8-validation.stderr | 18 ++-- .../mismatch-raw-ptr-in-adt.stderr | 8 +- .../mgca/generic_const_type_mismatch.rs | 20 +++++ .../mgca/generic_const_type_mismatch.stderr | 8 ++ .../mgca/nonsensical-negated-literal.rs | 26 ++++++ .../mgca/nonsensical-negated-literal.stderr | 38 ++++++++ .../mgca/tuple_expr_type_mismatch.rs | 22 +++++ .../mgca/tuple_expr_type_mismatch.stderr | 38 ++++++++ .../mgca/type_const-mismatched-types.rs | 1 - .../mgca/type_const-mismatched-types.stderr | 10 +-- .../invalid-patterns.32bit.stderr | 52 +++++------ .../invalid-patterns.64bit.stderr | 48 +++++----- tests/ui/issues/issue-34373.rs | 1 + tests/ui/issues/issue-34373.stderr | 23 ++++- tests/ui/repeat-expr/repeat_count.stderr | 12 +-- ...ce-hir-wf-check-anon-const-issue-122989.rs | 2 + ...ir-wf-check-anon-const-issue-122989.stderr | 22 ++++- 25 files changed, 402 insertions(+), 131 deletions(-) create mode 100644 tests/ui/const-generics/mgca/generic_const_type_mismatch.rs create mode 100644 tests/ui/const-generics/mgca/generic_const_type_mismatch.stderr create mode 100644 tests/ui/const-generics/mgca/nonsensical-negated-literal.rs create mode 100644 tests/ui/const-generics/mgca/nonsensical-negated-literal.stderr create mode 100644 tests/ui/const-generics/mgca/tuple_expr_type_mismatch.rs create mode 100644 tests/ui/const-generics/mgca/tuple_expr_type_mismatch.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index f58461e5d0e13..e22aa990c3e7e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -35,7 +35,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::DynCompatibilityViolation; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::middle::stability::AllowUnstable; -use rustc_middle::mir::interpret::LitToConstInput; +use rustc_middle::mir::interpret::{LitToConstInput, const_lit_matches_ty}; use rustc_middle::ty::print::PrintPolyTraitRefExt as _; use rustc_middle::ty::{ self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, @@ -2803,8 +2803,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, ) -> Const<'tcx> { let tcx = self.tcx(); + if let LitKind::Err(guar) = *kind { + return ty::Const::new_error(tcx, guar); + } let input = LitToConstInput { lit: *kind, ty, neg }; - tcx.at(span).lit_to_const(input) + match tcx.at(span).lit_to_const(input) { + Some(value) => ty::Const::new_value(tcx, value.valtree, value.ty), + None => { + let e = tcx.dcx().span_err(span, "type annotations needed for the literal"); + ty::Const::new_error(tcx, e) + } + } } #[instrument(skip(self), level = "debug")] @@ -2833,11 +2842,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { _ => None, }; - lit_input - // Allow the `ty` to be an alias type, though we cannot handle it here, we just go through - // the more expensive anon const code path. - .filter(|l| !l.ty.has_aliases()) - .map(|l| tcx.at(expr.span).lit_to_const(l)) + lit_input.and_then(|l| { + if const_lit_matches_ty(tcx, &l.lit, l.ty, l.neg) { + tcx.at(expr.span) + .lit_to_const(l) + .map(|value| ty::Const::new_value(tcx, value.valtree, value.ty)) + } else { + None + } + }) } fn require_type_const_attribute( diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 9762e0f21da9f..f31610cd5e142 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -84,6 +84,44 @@ pub struct LitToConstInput<'tcx> { pub neg: bool, } +pub fn const_lit_matches_ty<'tcx>( + tcx: TyCtxt<'tcx>, + kind: &LitKind, + ty: Ty<'tcx>, + neg: bool, +) -> bool { + match (*kind, ty.kind()) { + (LitKind::Str(..), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => true, + (LitKind::Str(..), ty::Str) if tcx.features().deref_patterns() => true, + (LitKind::ByteStr(..), ty::Ref(_, inner_ty, _)) + if let ty::Slice(ty) | ty::Array(ty, _) = inner_ty.kind() + && matches!(ty.kind(), ty::Uint(ty::UintTy::U8)) => + { + true + } + (LitKind::ByteStr(..), ty::Slice(inner_ty) | ty::Array(inner_ty, _)) + if tcx.features().deref_patterns() + && matches!(inner_ty.kind(), ty::Uint(ty::UintTy::U8)) => + { + true + } + (LitKind::Byte(..), ty::Uint(ty::UintTy::U8)) => true, + (LitKind::CStr(..), ty::Ref(_, inner_ty, _)) + if matches!(inner_ty.kind(), ty::Adt(def, _) + if tcx.is_lang_item(def.did(), rustc_hir::LangItem::CStr)) => + { + true + } + (LitKind::Int(..), ty::Uint(_)) if !neg => true, + (LitKind::Int(..), ty::Int(_)) => true, + (LitKind::Bool(..), ty::Bool) => true, + (LitKind::Float(..), ty::Float(_)) => true, + (LitKind::Char(..), ty::Char) => true, + (LitKind::Err(..), _) => true, + _ => false, + } +} + #[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct AllocId(pub NonZero); diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 771c300989f2a..60a03cc66d72b 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -1412,7 +1412,7 @@ rustc_queries! { // FIXME get rid of this with valtrees query lit_to_const( key: LitToConstInput<'tcx> - ) -> ty::Const<'tcx> { + ) -> Option> { desc { "converting literal to const" } } diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 99b1f6d8c2515..fe0368525e277 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -256,6 +256,10 @@ impl Erasable for Option>> { type Storage = [u8; size_of::>>>()]; } +impl Erasable for Option> { + type Storage = [u8; size_of::>>()]; +} + impl Erasable for rustc_hir::MaybeOwner<'_> { type Storage = [u8; size_of::>()]; } diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index 96248499044aa..6b93cf8ec8f49 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -3,7 +3,7 @@ use rustc_ast::{self as ast, UintTy}; use rustc_hir::LangItem; use rustc_middle::bug; use rustc_middle::mir::interpret::LitToConstInput; -use rustc_middle::ty::{self, ScalarInt, TyCtxt, TypeVisitableExt as _}; +use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt as _}; use tracing::trace; use crate::builder::parse_float_into_scalar; @@ -11,11 +11,11 @@ use crate::builder::parse_float_into_scalar; pub(crate) fn lit_to_const<'tcx>( tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>, -) -> ty::Const<'tcx> { - let LitToConstInput { lit, ty, neg } = lit_input; +) -> Option> { + let LitToConstInput { lit, ty: expected_ty, neg } = lit_input; - if let Err(guar) = ty.error_reported() { - return ty::Const::new_error(tcx, guar); + if expected_ty.error_reported().is_err() { + return None; } let trunc = |n, width: ty::UintTy| { @@ -32,22 +32,17 @@ pub(crate) fn lit_to_const<'tcx>( .unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result)) }; - let valtree = match (lit, ty.kind()) { - (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => { + let (valtree, valtree_ty) = match (lit, expected_ty.kind()) { + (ast::LitKind::Str(s, _), _) => { let str_bytes = s.as_str().as_bytes(); - ty::ValTree::from_raw_bytes(tcx, str_bytes) - } - (ast::LitKind::Str(s, _), ty::Str) if tcx.features().deref_patterns() => { - // String literal patterns may have type `str` if `deref_patterns` is enabled, in order - // to allow `deref!("..."): String`. - let str_bytes = s.as_str().as_bytes(); - ty::ValTree::from_raw_bytes(tcx, str_bytes) + let valtree_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, tcx.types.str_); + (ty::ValTree::from_raw_bytes(tcx, str_bytes), valtree_ty) } (ast::LitKind::ByteStr(byte_sym, _), ty::Ref(_, inner_ty, _)) if let ty::Slice(ty) | ty::Array(ty, _) = inner_ty.kind() && let ty::Uint(UintTy::U8) = ty.kind() => { - ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()) + (ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty) } (ast::LitKind::ByteStr(byte_sym, _), ty::Slice(inner_ty) | ty::Array(inner_ty, _)) if tcx.features().deref_patterns() @@ -55,40 +50,66 @@ pub(crate) fn lit_to_const<'tcx>( { // Byte string literal patterns may have type `[u8]` or `[u8; N]` if `deref_patterns` is // enabled, in order to allow, e.g., `deref!(b"..."): Vec`. - ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()) + (ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty) } - (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => { - ty::ValTree::from_scalar_int(tcx, n.into()) + (ast::LitKind::ByteStr(byte_sym, _), _) => { + let valtree = ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()); + let valtree_ty = Ty::new_array(tcx, tcx.types.u8, byte_sym.as_byte_str().len() as u64); + (valtree, valtree_ty) } - (ast::LitKind::CStr(byte_sym, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) => + (ast::LitKind::Byte(n), _) => (ty::ValTree::from_scalar_int(tcx, n.into()), tcx.types.u8), + (ast::LitKind::CStr(byte_sym, _), _) + if let Some(cstr_def_id) = tcx.lang_items().get(LangItem::CStr) => { // A CStr is a newtype around a byte slice, so we create the inner slice here. // We need a branch for each "level" of the data structure. + let cstr_ty = tcx.type_of(cstr_def_id).skip_binder(); let bytes = ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()); - ty::ValTree::from_branches(tcx, [ty::Const::new_value(tcx, bytes, *inner_ty)]) + let valtree = + ty::ValTree::from_branches(tcx, [ty::Const::new_value(tcx, bytes, cstr_ty)]); + let valtree_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, cstr_ty); + (valtree, valtree_ty) } - (ast::LitKind::Int(n, _), ty::Uint(ui)) if !neg => { + (ast::LitKind::Int(n, ast::LitIntType::Unsigned(ui)), _) if !neg => { + let scalar_int = trunc(n.get(), ui); + (ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_uint(tcx, ui)) + } + (ast::LitKind::Int(_, ast::LitIntType::Unsigned(_)), _) if neg => return None, + (ast::LitKind::Int(n, ast::LitIntType::Signed(i)), _) => { + let scalar_int = + trunc(if neg { u128::wrapping_neg(n.get()) } else { n.get() }, i.to_unsigned()); + (ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_int(tcx, i)) + } + (ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), ty::Uint(ui)) if !neg => { let scalar_int = trunc(n.get(), *ui); - ty::ValTree::from_scalar_int(tcx, scalar_int) + (ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_uint(tcx, *ui)) } - (ast::LitKind::Int(n, _), ty::Int(i)) => { + (ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), ty::Int(i)) => { // Unsigned "negation" has the same bitwise effect as signed negation, // which gets the result we want without additional casts. let scalar_int = trunc(if neg { u128::wrapping_neg(n.get()) } else { n.get() }, i.to_unsigned()); - ty::ValTree::from_scalar_int(tcx, scalar_int) + (ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_int(tcx, *i)) + } + (ast::LitKind::Bool(b), _) => (ty::ValTree::from_scalar_int(tcx, b.into()), tcx.types.bool), + (ast::LitKind::Float(n, ast::LitFloatType::Suffixed(fty)), _) => { + let fty = match fty { + ast::FloatTy::F16 => ty::FloatTy::F16, + ast::FloatTy::F32 => ty::FloatTy::F32, + ast::FloatTy::F64 => ty::FloatTy::F64, + ast::FloatTy::F128 => ty::FloatTy::F128, + }; + let bits = parse_float_into_scalar(n, fty, neg)?; + (ty::ValTree::from_scalar_int(tcx, bits), Ty::new_float(tcx, fty)) } - (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int(tcx, b.into()), - (ast::LitKind::Float(n, _), ty::Float(fty)) => { - let bits = parse_float_into_scalar(n, *fty, neg).unwrap_or_else(|| { - tcx.dcx().bug(format!("couldn't parse float literal: {:?}", lit_input.lit)) - }); - ty::ValTree::from_scalar_int(tcx, bits) + (ast::LitKind::Float(n, ast::LitFloatType::Unsuffixed), ty::Float(fty)) => { + let bits = parse_float_into_scalar(n, *fty, neg)?; + (ty::ValTree::from_scalar_int(tcx, bits), Ty::new_float(tcx, *fty)) } - (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int(tcx, c.into()), - (ast::LitKind::Err(guar), _) => return ty::Const::new_error(tcx, guar), - _ => return ty::Const::new_misc_error(tcx), + (ast::LitKind::Char(c), _) => (ty::ValTree::from_scalar_int(tcx, c.into()), tcx.types.char), + (ast::LitKind::Err(_), _) => return None, + _ => return None, }; - ty::Const::new_value(tcx, valtree, ty) + Some(ty::Value { ty: valtree_ty, valtree }) } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 3641561567bce..a231f1fda4b44 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -8,13 +8,14 @@ use std::cmp::Ordering; use std::sync::Arc; use rustc_abi::{FieldIdx, Integer}; +use rustc_ast::LitKind; use rustc_data_structures::assert_matches; use rustc_errors::codes::*; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::{self as hir, RangeEnd}; use rustc_index::Idx; -use rustc_middle::mir::interpret::LitToConstInput; +use rustc_middle::mir::interpret::{LitToConstInput, const_lit_matches_ty}; use rustc_middle::thir::{ Ascription, DerefPatBorrowMode, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary, }; @@ -197,8 +198,6 @@ impl<'tcx> PatCtxt<'tcx> { expr: Option<&'tcx hir::PatExpr<'tcx>>, ty: Ty<'tcx>, ) -> Result<(), ErrorGuaranteed> { - use rustc_ast::ast::LitKind; - let Some(expr) = expr else { return Ok(()); }; @@ -696,7 +695,17 @@ impl<'tcx> PatCtxt<'tcx> { let pat_ty = self.typeck_results.node_type(pat.hir_id); let lit_input = LitToConstInput { lit: lit.node, ty: pat_ty, neg: *negated }; - let constant = self.tcx.at(expr.span).lit_to_const(lit_input); + let constant = const_lit_matches_ty(self.tcx, &lit.node, pat_ty, *negated) + .then(|| self.tcx.at(expr.span).lit_to_const(lit_input)) + .flatten() + .map(|v| ty::Const::new_value(self.tcx, v.valtree, pat_ty)) + .unwrap_or_else(|| { + ty::Const::new_error_with_message( + self.tcx, + expr.span, + "literal does not match expected type", + ) + }); self.const_to_pat(constant, pat_ty, expr.hir_id, lit.span) } } diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index f6d08bd458bdd..5029b33e5b6c2 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -59,7 +59,10 @@ fn recurse_build<'tcx>( } &ExprKind::Literal { lit, neg } => { let sp = node.span; - tcx.at(sp).lit_to_const(LitToConstInput { lit: lit.node, ty: node.ty, neg }) + match tcx.at(sp).lit_to_const(LitToConstInput { lit: lit.node, ty: node.ty, neg }) { + Some(value) => ty::Const::new_value(tcx, value.valtree, value.ty), + None => ty::Const::new_misc_error(tcx), + } } &ExprKind::NonHirLiteral { lit, user_ty: _ } => { let val = ty::ValTree::from_scalar_int(tcx, lit); diff --git a/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.rs b/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.rs index 703e63ae047ff..063a38c8aa01d 100644 --- a/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.rs +++ b/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.rs @@ -8,7 +8,7 @@ struct ConstBytes //~^ ERROR rustc_dump_predicates //~| NOTE Binder { value: ConstArgHasType(T/#0, &'static [*mut u8; 3_usize]), bound_vars: [] } -//~| NOTE Binder { value: TraitPredicate( as std::marker::Sized>, polarity:Positive), bound_vars: [] } +//~| NOTE Binder { value: TraitPredicate( as std::marker::Sized>, polarity:Positive), bound_vars: [] } where ConstBytes: Sized; //~^ ERROR mismatched types diff --git a/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.stderr b/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.stderr index f5f8a420a703e..d4b8ac7f021d0 100644 --- a/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.stderr +++ b/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.stderr @@ -1,12 +1,3 @@ -error: rustc_dump_predicates - --> $DIR/byte-string-u8-validation.rs:8:1 - | -LL | struct ConstBytes - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: Binder { value: ConstArgHasType(T/#0, &'static [*mut u8; 3_usize]), bound_vars: [] } - = note: Binder { value: TraitPredicate( as std::marker::Sized>, polarity:Positive), bound_vars: [] } - error[E0308]: mismatched types --> $DIR/byte-string-u8-validation.rs:13:16 | @@ -16,6 +7,15 @@ LL | ConstBytes: Sized; = note: expected reference `&'static [*mut u8; 3]` found reference `&'static [u8; 3]` +error: rustc_dump_predicates + --> $DIR/byte-string-u8-validation.rs:8:1 + | +LL | struct ConstBytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: Binder { value: ConstArgHasType(T/#0, &'static [*mut u8; 3_usize]), bound_vars: [] } + = note: Binder { value: TraitPredicate( as std::marker::Sized>, polarity:Positive), bound_vars: [] } + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.stderr b/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.stderr index 717e680ee5368..d7eec45bae0f3 100644 --- a/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.stderr +++ b/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.stderr @@ -8,19 +8,19 @@ LL | struct ConstBytes; = note: `[*mut u8; 3]` must implement `ConstParamTy_`, but it does not error[E0308]: mismatched types - --> $DIR/mismatch-raw-ptr-in-adt.rs:9:46 + --> $DIR/mismatch-raw-ptr-in-adt.rs:9:23 | LL | let _: ConstBytes = ConstBytes::; - | ^^^^^^ expected `&[*mut u8; 3]`, found `&[u8; 3]` + | ^^^^^^ expected `&[*mut u8; 3]`, found `&[u8; 3]` | = note: expected reference `&'static [*mut u8; 3]` found reference `&'static [u8; 3]` error[E0308]: mismatched types - --> $DIR/mismatch-raw-ptr-in-adt.rs:9:23 + --> $DIR/mismatch-raw-ptr-in-adt.rs:9:46 | LL | let _: ConstBytes = ConstBytes::; - | ^^^^^^ expected `&[*mut u8; 3]`, found `&[u8; 3]` + | ^^^^^^ expected `&[*mut u8; 3]`, found `&[u8; 3]` | = note: expected reference `&'static [*mut u8; 3]` found reference `&'static [u8; 3]` diff --git a/tests/ui/const-generics/mgca/generic_const_type_mismatch.rs b/tests/ui/const-generics/mgca/generic_const_type_mismatch.rs new file mode 100644 index 0000000000000..ffde84522a269 --- /dev/null +++ b/tests/ui/const-generics/mgca/generic_const_type_mismatch.rs @@ -0,0 +1,20 @@ +//! Regression test for +#![expect(incomplete_features)] +#![feature( + generic_const_items, + generic_const_parameter_types, + min_generic_const_args, + unsized_const_params +)] +use std::marker::ConstParamTy_; + +struct Foo { + field: T, +} + +#[type_const] +const WRAP : T = { + Foo::{field : 1} //~ ERROR: type annotations needed for the literal +}; + +fn main() {} diff --git a/tests/ui/const-generics/mgca/generic_const_type_mismatch.stderr b/tests/ui/const-generics/mgca/generic_const_type_mismatch.stderr new file mode 100644 index 0000000000000..10e37b327eec2 --- /dev/null +++ b/tests/ui/const-generics/mgca/generic_const_type_mismatch.stderr @@ -0,0 +1,8 @@ +error: type annotations needed for the literal + --> $DIR/generic_const_type_mismatch.rs:17:22 + | +LL | Foo::{field : 1} + | ^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/nonsensical-negated-literal.rs b/tests/ui/const-generics/mgca/nonsensical-negated-literal.rs new file mode 100644 index 0000000000000..cd68a2c0d4301 --- /dev/null +++ b/tests/ui/const-generics/mgca/nonsensical-negated-literal.rs @@ -0,0 +1,26 @@ +#![feature(adt_const_params, min_generic_const_args)] +#![expect(incomplete_features)] + +use std::marker::ConstParamTy; + +#[derive(Eq, PartialEq, ConstParamTy)] +struct Foo { + field: isize +} + +fn foo() {} + +fn main() { + foo::<{ Foo { field: -1_usize } }>(); + //~^ ERROR: type annotations needed for the literal + foo::<{ Foo { field: { -1_usize } } }>(); + //~^ ERROR: complex const arguments must be placed inside of a `const` block + foo::<{ Foo { field: -true } }>(); + //~^ ERROR: the constant `true` is not of type `isize` + foo::<{ Foo { field: { -true } } }>(); + //~^ ERROR: complex const arguments must be placed inside of a `const` block + foo::<{ Foo { field: -"<3" } }>(); + //~^ ERROR: the constant `"<3"` is not of type `isize` + foo::<{ Foo { field: { -"<3" } } }>(); + //~^ ERROR: complex const arguments must be placed inside of a `const` block +} diff --git a/tests/ui/const-generics/mgca/nonsensical-negated-literal.stderr b/tests/ui/const-generics/mgca/nonsensical-negated-literal.stderr new file mode 100644 index 0000000000000..43ed4b71e33e7 --- /dev/null +++ b/tests/ui/const-generics/mgca/nonsensical-negated-literal.stderr @@ -0,0 +1,38 @@ +error: complex const arguments must be placed inside of a `const` block + --> $DIR/nonsensical-negated-literal.rs:16:26 + | +LL | foo::<{ Foo { field: { -1_usize } } }>(); + | ^^^^^^^^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/nonsensical-negated-literal.rs:20:26 + | +LL | foo::<{ Foo { field: { -true } } }>(); + | ^^^^^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/nonsensical-negated-literal.rs:24:26 + | +LL | foo::<{ Foo { field: { -"<3" } } }>(); + | ^^^^^^^^^ + +error: type annotations needed for the literal + --> $DIR/nonsensical-negated-literal.rs:14:26 + | +LL | foo::<{ Foo { field: -1_usize } }>(); + | ^^^^^^^^ + +error: the constant `true` is not of type `isize` + --> $DIR/nonsensical-negated-literal.rs:18:13 + | +LL | foo::<{ Foo { field: -true } }>(); + | ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `bool` + +error: the constant `"<3"` is not of type `isize` + --> $DIR/nonsensical-negated-literal.rs:22:13 + | +LL | foo::<{ Foo { field: -"<3" } }>(); + | ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `&'static str` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/const-generics/mgca/tuple_expr_type_mismatch.rs b/tests/ui/const-generics/mgca/tuple_expr_type_mismatch.rs new file mode 100644 index 0000000000000..373cce1d62201 --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_expr_type_mismatch.rs @@ -0,0 +1,22 @@ +//! Regression test for +#![expect(incomplete_features)] +#![feature( + adt_const_params, + min_generic_const_args, + unsized_const_params +)] +fn foo() {} +fn bar() {} +fn qux() {} + +fn main() { + foo::<{ (1, true) }>(); + //~^ ERROR: type annotations needed for the literal + //~| ERROR: mismatched types: expected `i32`, found `bool` + bar::<{ (1_u32, [1, 2]) }>(); + //~^ ERROR: expected `i32`, found const array + //~| ERROR: mismatched types: expected `[u8; 2]`, found `u32` + qux::<{ (1i32, 'a') }>(); + //~^ ERROR: mismatched types: expected `char`, found `i32` + //~| ERROR: mismatched types: expected `i32`, found `char` +} diff --git a/tests/ui/const-generics/mgca/tuple_expr_type_mismatch.stderr b/tests/ui/const-generics/mgca/tuple_expr_type_mismatch.stderr new file mode 100644 index 0000000000000..13e2789ccb67a --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_expr_type_mismatch.stderr @@ -0,0 +1,38 @@ +error: type annotations needed for the literal + --> $DIR/tuple_expr_type_mismatch.rs:13:14 + | +LL | foo::<{ (1, true) }>(); + | ^ + +error: mismatched types: expected `i32`, found `bool` + --> $DIR/tuple_expr_type_mismatch.rs:13:17 + | +LL | foo::<{ (1, true) }>(); + | ^^^^ + +error: mismatched types: expected `[u8; 2]`, found `u32` + --> $DIR/tuple_expr_type_mismatch.rs:16:14 + | +LL | bar::<{ (1_u32, [1, 2]) }>(); + | ^^^^^ + +error: expected `i32`, found const array + --> $DIR/tuple_expr_type_mismatch.rs:16:21 + | +LL | bar::<{ (1_u32, [1, 2]) }>(); + | ^^^^^^ + +error: mismatched types: expected `char`, found `i32` + --> $DIR/tuple_expr_type_mismatch.rs:19:14 + | +LL | qux::<{ (1i32, 'a') }>(); + | ^^^^ + +error: mismatched types: expected `i32`, found `char` + --> $DIR/tuple_expr_type_mismatch.rs:19:20 + | +LL | qux::<{ (1i32, 'a') }>(); + | ^^^ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/const-generics/mgca/type_const-mismatched-types.rs b/tests/ui/const-generics/mgca/type_const-mismatched-types.rs index 460c5d7b21998..deac97383b04a 100644 --- a/tests/ui/const-generics/mgca/type_const-mismatched-types.rs +++ b/tests/ui/const-generics/mgca/type_const-mismatched-types.rs @@ -5,7 +5,6 @@ type const FREE: u32 = 5_usize; //~^ ERROR mismatched types type const FREE2: isize = FREE; -//~^ ERROR the constant `5` is not of type `isize` trait Tr { type const N: usize; diff --git a/tests/ui/const-generics/mgca/type_const-mismatched-types.stderr b/tests/ui/const-generics/mgca/type_const-mismatched-types.stderr index 152dd9ec0cca1..1c04ac5085693 100644 --- a/tests/ui/const-generics/mgca/type_const-mismatched-types.stderr +++ b/tests/ui/const-generics/mgca/type_const-mismatched-types.stderr @@ -1,9 +1,3 @@ -error: the constant `5` is not of type `isize` - --> $DIR/type_const-mismatched-types.rs:7:1 - | -LL | type const FREE2: isize = FREE; - | ^^^^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `u32` - error[E0308]: mismatched types --> $DIR/type_const-mismatched-types.rs:4:24 | @@ -17,11 +11,11 @@ LL + type const FREE: u32 = 5_u32; | error[E0308]: mismatched types - --> $DIR/type_const-mismatched-types.rs:15:27 + --> $DIR/type_const-mismatched-types.rs:18:22 | LL | type const N: usize = false; | ^^^^^ expected `usize`, found `bool` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr index cc6a813b747d9..b85856db9287e 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr @@ -1,4 +1,28 @@ -error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:31:21 + | +LL | get_flag::(); + | ^^^^ expected `char`, found `u8` + +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:33:14 + | +LL | get_flag::<7, 'c'>(); + | ^ expected `bool`, found integer + +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:35:14 + | +LL | get_flag::<42, 0x5ad>(); + | ^^ expected `bool`, found integer + +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:35:18 + | +LL | get_flag::<42, 0x5ad>(); + | ^^^^^ expected `char`, found `u8` + +error[E0080]: reading memory at ALLOC6[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory --> $DIR/invalid-patterns.rs:40:32 | LL | get_flag::(); @@ -30,7 +54,7 @@ LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character 42 │ B } -error[E0080]: reading memory at ALLOC1[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory +error[E0080]: reading memory at ALLOC12[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory --> $DIR/invalid-patterns.rs:44:58 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); @@ -40,30 +64,6 @@ LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character ff __ __ __ │ .░░░ } -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:31:21 - | -LL | get_flag::(); - | ^^^^ expected `char`, found `u8` - -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:33:14 - | -LL | get_flag::<7, 'c'>(); - | ^ expected `bool`, found integer - -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:35:14 - | -LL | get_flag::<42, 0x5ad>(); - | ^^ expected `bool`, found integer - -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:35:18 - | -LL | get_flag::<42, 0x5ad>(); - | ^^^^^ expected `char`, found `u8` - error: aborting due to 8 previous errors Some errors have detailed explanations: E0080, E0308. diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr index cc6a813b747d9..df7c2a0a86292 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr @@ -1,3 +1,27 @@ +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:31:21 + | +LL | get_flag::(); + | ^^^^ expected `char`, found `u8` + +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:33:14 + | +LL | get_flag::<7, 'c'>(); + | ^ expected `bool`, found integer + +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:35:14 + | +LL | get_flag::<42, 0x5ad>(); + | ^^ expected `bool`, found integer + +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:35:18 + | +LL | get_flag::<42, 0x5ad>(); + | ^^^^^ expected `char`, found `u8` + error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory --> $DIR/invalid-patterns.rs:40:32 | @@ -40,30 +64,6 @@ LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character ff __ __ __ │ .░░░ } -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:31:21 - | -LL | get_flag::(); - | ^^^^ expected `char`, found `u8` - -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:33:14 - | -LL | get_flag::<7, 'c'>(); - | ^ expected `bool`, found integer - -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:35:14 - | -LL | get_flag::<42, 0x5ad>(); - | ^^ expected `bool`, found integer - -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:35:18 - | -LL | get_flag::<42, 0x5ad>(); - | ^^^^^ expected `char`, found `u8` - error: aborting due to 8 previous errors Some errors have detailed explanations: E0080, E0308. diff --git a/tests/ui/issues/issue-34373.rs b/tests/ui/issues/issue-34373.rs index 5b05811a4eb3f..019cab42c6433 100644 --- a/tests/ui/issues/issue-34373.rs +++ b/tests/ui/issues/issue-34373.rs @@ -6,6 +6,7 @@ trait Trait { pub struct Foo>>; //~ ERROR cycle detected //~^ ERROR `T` is never used +//~| ERROR cycle detected type DefaultFoo = Foo; fn main() { diff --git a/tests/ui/issues/issue-34373.stderr b/tests/ui/issues/issue-34373.stderr index 03d7719313416..49365a701ceee 100644 --- a/tests/ui/issues/issue-34373.stderr +++ b/tests/ui/issues/issue-34373.stderr @@ -5,7 +5,26 @@ LL | pub struct Foo>>; | ^^^^^^^^^^ | note: ...which requires expanding type alias `DefaultFoo`... - --> $DIR/issue-34373.rs:9:19 + --> $DIR/issue-34373.rs:10:1 + | +LL | type DefaultFoo = Foo; + | ^^^^^^^^^^^^^^^ + = note: ...which again requires computing type of `Foo::T`, completing the cycle +note: cycle used when checking that `Foo` is well-formed + --> $DIR/issue-34373.rs:7:1 + | +LL | pub struct Foo>>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error[E0391]: cycle detected when computing type of `Foo::T` + --> $DIR/issue-34373.rs:7:34 + | +LL | pub struct Foo>>; + | ^^^^^^^^^^ + | +note: ...which requires expanding type alias `DefaultFoo`... + --> $DIR/issue-34373.rs:10:19 | LL | type DefaultFoo = Foo; | ^^^ @@ -26,7 +45,7 @@ LL | pub struct Foo>>; = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0391, E0392. For more information about an error, try `rustc --explain E0391`. diff --git a/tests/ui/repeat-expr/repeat_count.stderr b/tests/ui/repeat-expr/repeat_count.stderr index cf94ad41ee363..8d8702e981e6f 100644 --- a/tests/ui/repeat-expr/repeat_count.stderr +++ b/tests/ui/repeat-expr/repeat_count.stderr @@ -16,12 +16,6 @@ error[E0308]: mismatched types LL | let b = [0; ()]; | ^^ expected `usize`, found `()` -error[E0308]: mismatched types - --> $DIR/repeat_count.rs:33:17 - | -LL | let g = [0; G { g: () }]; - | ^^^^^^^^^^^ expected `usize`, found `G` - error[E0308]: mismatched types --> $DIR/repeat_count.rs:12:17 | @@ -68,6 +62,12 @@ LL - let f = [0; 4u8]; LL + let f = [0; 4usize]; | +error[E0308]: mismatched types + --> $DIR/repeat_count.rs:33:17 + | +LL | let g = [0; G { g: () }]; + | ^^^^^^^^^^^ expected `usize`, found `G` + error: aborting due to 9 previous errors Some errors have detailed explanations: E0308, E0435. diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs index f2b9f037ea5f3..13d7a800c51fd 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs @@ -4,11 +4,13 @@ trait Foo> { //~^ WARN trait objects without an explicit `dyn` are deprecated //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! //~| ERROR cycle detected when computing type of `Foo::N` + //~| ERROR `(dyn Bar<2> + 'static)` is forbidden as the type of a const generic parameter fn func() {} } trait Bar> {} //~^ WARN trait objects without an explicit `dyn` are deprecated //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! +//~| ERROR `(dyn Foo<2> + 'static)` is forbidden as the type of a const generic parameter fn main() {} diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr index 4024f57af4ffd..f9a855d3b93b7 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr @@ -13,7 +13,7 @@ LL | trait Foo> { | +++ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:10:20 + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:20 | LL | trait Bar> {} | ^^^^^^ @@ -32,7 +32,7 @@ LL | trait Foo> { | ^^^^^^^^^^^^^^^ | note: ...which requires computing type of `Bar::M`... - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:10:11 + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:11 | LL | trait Bar> {} | ^^^^^^^^^^^^^^^ @@ -44,6 +44,22 @@ LL | trait Foo> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 1 previous error; 2 warnings emitted +error: `(dyn Bar<2> + 'static)` is forbidden as the type of a const generic parameter + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:3:20 + | +LL | trait Foo> { + | ^^^^^^ + | + = note: the only supported types are integers, `bool`, and `char` + +error: `(dyn Foo<2> + 'static)` is forbidden as the type of a const generic parameter + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:20 + | +LL | trait Bar> {} + | ^^^^^^ + | + = note: the only supported types are integers, `bool`, and `char` + +error: aborting due to 3 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0391`. From b4ee9953d8dd037fcfce60a0d10c0da90ec81650 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Tue, 10 Feb 2026 16:01:13 +0000 Subject: [PATCH 10/11] modify error comment and bless test, delete tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.rs --- tests/crashes/133966.rs | 3 -- .../byte-string-u8-validation.rs | 2 + .../byte-string-u8-validation.stderr | 2 +- .../generic_const_exprs/issue-105257.rs | 6 +-- .../generic_const_exprs/lit_type_mismatch.rs | 22 ----------- .../lit_type_mismatch.stderr | 21 ---------- .../mgca/generic_const_type_mismatch.rs | 7 ++-- .../mgca/generic_const_type_mismatch.stderr | 6 +-- .../mgca/tuple_expr_type_mismatch.rs | 6 +-- .../mgca/tuple_expr_type_mismatch.stderr | 28 ++++--------- .../mgca/type_const-mismatched-types.rs | 4 +- .../mgca/type_const-mismatched-types.stderr | 26 +++++++++---- .../invalid-patterns.32bit.stderr | 4 +- .../type-dependent/type-mismatch.full.stderr | 14 ++++++- .../type-dependent/type-mismatch.min.stderr | 14 ++++++- .../type-dependent/type-mismatch.rs | 3 +- .../const-eval/array-len-mismatch-type.rs | 8 ++++ .../const-eval/array-len-mismatch-type.stderr | 39 +++++++++++++++++++ tests/ui/issues/issue-34373.rs | 6 +-- tests/ui/issues/issue-34373.stderr | 21 +--------- tests/ui/repeat-expr/repeat_count.rs | 19 +++++---- tests/ui/repeat-expr/repeat_count.stderr | 34 +++++++++------- 22 files changed, 158 insertions(+), 137 deletions(-) delete mode 100644 tests/crashes/133966.rs delete mode 100644 tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.rs delete mode 100644 tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.stderr create mode 100644 tests/ui/consts/const-eval/array-len-mismatch-type.rs create mode 100644 tests/ui/consts/const-eval/array-len-mismatch-type.stderr diff --git a/tests/crashes/133966.rs b/tests/crashes/133966.rs deleted file mode 100644 index 25a881ae99b4f..0000000000000 --- a/tests/crashes/133966.rs +++ /dev/null @@ -1,3 +0,0 @@ -//@ known-bug: #133966 -pub struct Data([[&'static str]; 5_i32]); -const _: &'static Data = unsafe { &*(&[] as *const Data) }; diff --git a/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.rs b/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.rs index 063a38c8aa01d..d49fb49d253cb 100644 --- a/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.rs +++ b/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.rs @@ -9,10 +9,12 @@ struct ConstBytes //~^ ERROR rustc_dump_predicates //~| NOTE Binder { value: ConstArgHasType(T/#0, &'static [*mut u8; 3_usize]), bound_vars: [] } //~| NOTE Binder { value: TraitPredicate( as std::marker::Sized>, polarity:Positive), bound_vars: [] } + where ConstBytes: Sized; //~^ ERROR mismatched types //~| NOTE expected `&[*mut u8; 3]`, found `&[u8; 3]` //~| NOTE expected reference `&'static [*mut u8; 3]` +//~| NOTE found reference `&'static [u8; 3]` fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.stderr b/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.stderr index d4b8ac7f021d0..1273a74102a24 100644 --- a/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.stderr +++ b/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/byte-string-u8-validation.rs:13:16 + --> $DIR/byte-string-u8-validation.rs:14:16 | LL | ConstBytes: Sized; | ^^^^^^ expected `&[*mut u8; 3]`, found `&[u8; 3]` diff --git a/tests/ui/const-generics/generic_const_exprs/issue-105257.rs b/tests/ui/const-generics/generic_const_exprs/issue-105257.rs index 85a28f2b3303b..947410cbe0dcc 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-105257.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-105257.rs @@ -2,9 +2,9 @@ #![expect(incomplete_features)] trait Trait { - fn fnc(&self) {} //~ERROR defaults for generic parameters are not allowed here - //~^ ERROR: mismatched types - fn foo() }>(&self) {} //~ERROR defaults for generic parameters are not allowed here + fn fnc(&self) {} //~ ERROR defaults for generic parameters are not allowed here + //~^ ERROR mismatched types + fn foo() }>(&self) {} //~ ERROR defaults for generic parameters are not allowed here } fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.rs b/tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.rs deleted file mode 100644 index 1ed0965e1bde1..0000000000000 --- a/tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.rs +++ /dev/null @@ -1,22 +0,0 @@ -//! ICE regression test for #114317 and #126182 -//! Type mismatches of literals cause errors int typeck, -//! but those errors cannot be propagated to the various -//! `lit_to_const` call sites. Now `lit_to_const` just delays -//! a bug and produces an error constant on its own. - -#![feature(adt_const_params)] -#![feature(generic_const_exprs)] -#![allow(incomplete_features)] - -struct A(C); -//~^ ERROR: generic parameters with a default must be trailing -//~| ERROR: mismatched types - -struct Cond; - -struct Thing>(T); -//~^ ERROR: mismatched types - -impl Thing {} - -fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.stderr b/tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.stderr deleted file mode 100644 index e4613e498b275..0000000000000 --- a/tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error: generic parameters with a default must be trailing - --> $DIR/lit_type_mismatch.rs:11:16 - | -LL | struct A(C); - | ^ - -error[E0308]: mismatched types - --> $DIR/lit_type_mismatch.rs:11:24 - | -LL | struct A(C); - | ^ expected `()`, found integer - -error[E0308]: mismatched types - --> $DIR/lit_type_mismatch.rs:17:23 - | -LL | struct Thing>(T); - | ^ expected `bool`, found integer - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/mgca/generic_const_type_mismatch.rs b/tests/ui/const-generics/mgca/generic_const_type_mismatch.rs index ffde84522a269..948b8ce72148f 100644 --- a/tests/ui/const-generics/mgca/generic_const_type_mismatch.rs +++ b/tests/ui/const-generics/mgca/generic_const_type_mismatch.rs @@ -1,6 +1,7 @@ //! Regression test for #![expect(incomplete_features)] #![feature( + adt_const_params, generic_const_items, generic_const_parameter_types, min_generic_const_args, @@ -12,9 +13,7 @@ struct Foo { field: T, } -#[type_const] -const WRAP : T = { - Foo::{field : 1} //~ ERROR: type annotations needed for the literal -}; +type const WRAP : T = Foo::{field : 1}; +//~^ ERROR: type annotations needed for the literal fn main() {} diff --git a/tests/ui/const-generics/mgca/generic_const_type_mismatch.stderr b/tests/ui/const-generics/mgca/generic_const_type_mismatch.stderr index 10e37b327eec2..fdb0995bff5d4 100644 --- a/tests/ui/const-generics/mgca/generic_const_type_mismatch.stderr +++ b/tests/ui/const-generics/mgca/generic_const_type_mismatch.stderr @@ -1,8 +1,8 @@ error: type annotations needed for the literal - --> $DIR/generic_const_type_mismatch.rs:17:22 + --> $DIR/generic_const_type_mismatch.rs:16:59 | -LL | Foo::{field : 1} - | ^ +LL | type const WRAP : T = Foo::{field : 1}; + | ^ error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/mgca/tuple_expr_type_mismatch.rs b/tests/ui/const-generics/mgca/tuple_expr_type_mismatch.rs index 373cce1d62201..4bf62b3a30708 100644 --- a/tests/ui/const-generics/mgca/tuple_expr_type_mismatch.rs +++ b/tests/ui/const-generics/mgca/tuple_expr_type_mismatch.rs @@ -12,11 +12,9 @@ fn qux() {} fn main() { foo::<{ (1, true) }>(); //~^ ERROR: type annotations needed for the literal - //~| ERROR: mismatched types: expected `i32`, found `bool` bar::<{ (1_u32, [1, 2]) }>(); //~^ ERROR: expected `i32`, found const array - //~| ERROR: mismatched types: expected `[u8; 2]`, found `u32` qux::<{ (1i32, 'a') }>(); - //~^ ERROR: mismatched types: expected `char`, found `i32` - //~| ERROR: mismatched types: expected `i32`, found `char` + //~^ ERROR: the constant `1` is not of type `char` + //~| ERROR: the constant `'a'` is not of type `i32 } diff --git a/tests/ui/const-generics/mgca/tuple_expr_type_mismatch.stderr b/tests/ui/const-generics/mgca/tuple_expr_type_mismatch.stderr index 13e2789ccb67a..4136c7337cd4e 100644 --- a/tests/ui/const-generics/mgca/tuple_expr_type_mismatch.stderr +++ b/tests/ui/const-generics/mgca/tuple_expr_type_mismatch.stderr @@ -4,35 +4,23 @@ error: type annotations needed for the literal LL | foo::<{ (1, true) }>(); | ^ -error: mismatched types: expected `i32`, found `bool` - --> $DIR/tuple_expr_type_mismatch.rs:13:17 - | -LL | foo::<{ (1, true) }>(); - | ^^^^ - -error: mismatched types: expected `[u8; 2]`, found `u32` - --> $DIR/tuple_expr_type_mismatch.rs:16:14 - | -LL | bar::<{ (1_u32, [1, 2]) }>(); - | ^^^^^ - error: expected `i32`, found const array - --> $DIR/tuple_expr_type_mismatch.rs:16:21 + --> $DIR/tuple_expr_type_mismatch.rs:15:21 | LL | bar::<{ (1_u32, [1, 2]) }>(); | ^^^^^^ -error: mismatched types: expected `char`, found `i32` - --> $DIR/tuple_expr_type_mismatch.rs:19:14 +error: the constant `1` is not of type `char` + --> $DIR/tuple_expr_type_mismatch.rs:17:13 | LL | qux::<{ (1i32, 'a') }>(); - | ^^^^ + | ^^^^^^^^^^^ expected `char`, found `i32` -error: mismatched types: expected `i32`, found `char` - --> $DIR/tuple_expr_type_mismatch.rs:19:20 +error: the constant `'a'` is not of type `i32` + --> $DIR/tuple_expr_type_mismatch.rs:17:13 | LL | qux::<{ (1i32, 'a') }>(); - | ^^^ + | ^^^^^^^^^^^ expected `i32`, found `char` -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/const-generics/mgca/type_const-mismatched-types.rs b/tests/ui/const-generics/mgca/type_const-mismatched-types.rs index deac97383b04a..c73785f9a3e38 100644 --- a/tests/ui/const-generics/mgca/type_const-mismatched-types.rs +++ b/tests/ui/const-generics/mgca/type_const-mismatched-types.rs @@ -2,9 +2,11 @@ #![feature(min_generic_const_args)] type const FREE: u32 = 5_usize; -//~^ ERROR mismatched types +//~^ ERROR the constant `5` is not of type `u32` +//~| ERROR mismatched types type const FREE2: isize = FREE; +//~^ ERROR the constant `5` is not of type `isize` trait Tr { type const N: usize; diff --git a/tests/ui/const-generics/mgca/type_const-mismatched-types.stderr b/tests/ui/const-generics/mgca/type_const-mismatched-types.stderr index 1c04ac5085693..f7f64c535f602 100644 --- a/tests/ui/const-generics/mgca/type_const-mismatched-types.stderr +++ b/tests/ui/const-generics/mgca/type_const-mismatched-types.stderr @@ -1,3 +1,21 @@ +error: the constant `5` is not of type `u32` + --> $DIR/type_const-mismatched-types.rs:4:1 + | +LL | type const FREE: u32 = 5_usize; + | ^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `usize` + +error: the constant `5` is not of type `isize` + --> $DIR/type_const-mismatched-types.rs:8:1 + | +LL | type const FREE2: isize = FREE; + | ^^^^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `usize` + +error[E0308]: mismatched types + --> $DIR/type_const-mismatched-types.rs:16:27 + | +LL | type const N: usize = false; + | ^^^^^ expected `usize`, found `bool` + error[E0308]: mismatched types --> $DIR/type_const-mismatched-types.rs:4:24 | @@ -10,12 +28,6 @@ LL - type const FREE: u32 = 5_usize; LL + type const FREE: u32 = 5_u32; | -error[E0308]: mismatched types - --> $DIR/type_const-mismatched-types.rs:18:22 - | -LL | type const N: usize = false; - | ^^^^^ expected `usize`, found `bool` - -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr index b85856db9287e..df7c2a0a86292 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr @@ -22,7 +22,7 @@ error[E0308]: mismatched types LL | get_flag::<42, 0x5ad>(); | ^^^^^ expected `char`, found `u8` -error[E0080]: reading memory at ALLOC6[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory +error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory --> $DIR/invalid-patterns.rs:40:32 | LL | get_flag::(); @@ -54,7 +54,7 @@ LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character 42 │ B } -error[E0080]: reading memory at ALLOC12[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory +error[E0080]: reading memory at ALLOC1[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory --> $DIR/invalid-patterns.rs:44:58 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); diff --git a/tests/ui/const-generics/type-dependent/type-mismatch.full.stderr b/tests/ui/const-generics/type-dependent/type-mismatch.full.stderr index 95d20de1b432e..9de140dab9eb6 100644 --- a/tests/ui/const-generics/type-dependent/type-mismatch.full.stderr +++ b/tests/ui/const-generics/type-dependent/type-mismatch.full.stderr @@ -1,3 +1,15 @@ +error: the constant `1` is not of type `u8` + --> $DIR/type-mismatch.rs:8:27 + | +LL | assert_eq!(R.method::<1u16>(), 1); + | ^^^^ expected `u8`, found `u16` + | +note: required by a const generic parameter in `R::method` + --> $DIR/type-mismatch.rs:5:15 + | +LL | fn method(&self) -> u8 { N } + | ^^^^^^^^^^^ required by this const generic parameter in `R::method` + error[E0308]: mismatched types --> $DIR/type-mismatch.rs:8:27 | @@ -10,6 +22,6 @@ LL - assert_eq!(R.method::<1u16>(), 1); LL + assert_eq!(R.method::<1u8>(), 1); | -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/type-dependent/type-mismatch.min.stderr b/tests/ui/const-generics/type-dependent/type-mismatch.min.stderr index 95d20de1b432e..9de140dab9eb6 100644 --- a/tests/ui/const-generics/type-dependent/type-mismatch.min.stderr +++ b/tests/ui/const-generics/type-dependent/type-mismatch.min.stderr @@ -1,3 +1,15 @@ +error: the constant `1` is not of type `u8` + --> $DIR/type-mismatch.rs:8:27 + | +LL | assert_eq!(R.method::<1u16>(), 1); + | ^^^^ expected `u8`, found `u16` + | +note: required by a const generic parameter in `R::method` + --> $DIR/type-mismatch.rs:5:15 + | +LL | fn method(&self) -> u8 { N } + | ^^^^^^^^^^^ required by this const generic parameter in `R::method` + error[E0308]: mismatched types --> $DIR/type-mismatch.rs:8:27 | @@ -10,6 +22,6 @@ LL - assert_eq!(R.method::<1u16>(), 1); LL + assert_eq!(R.method::<1u8>(), 1); | -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/type-dependent/type-mismatch.rs b/tests/ui/const-generics/type-dependent/type-mismatch.rs index 6ed5fdca30ae3..fc7ae994184be 100644 --- a/tests/ui/const-generics/type-dependent/type-mismatch.rs +++ b/tests/ui/const-generics/type-dependent/type-mismatch.rs @@ -6,5 +6,6 @@ impl R { } fn main() { assert_eq!(R.method::<1u16>(), 1); - //~^ ERROR mismatched types + //~^ ERROR the constant `1` is not of type `u8` + //~| ERROR mismatched types } diff --git a/tests/ui/consts/const-eval/array-len-mismatch-type.rs b/tests/ui/consts/const-eval/array-len-mismatch-type.rs new file mode 100644 index 0000000000000..463572c13e104 --- /dev/null +++ b/tests/ui/consts/const-eval/array-len-mismatch-type.rs @@ -0,0 +1,8 @@ +//! Regression test for +pub struct Data([[&'static str]; 5_i32]); +//~^ ERROR the constant `5` is not of type `usize` +//~| ERROR the size for values of type `[&'static str]` cannot be known at compilation time +//~| ERROR mismatched types +const _: &'static Data = unsafe { &*(&[] as *const Data) }; +//~^ ERROR the type `[[&str]; 5]` has an unknown layout +fn main() {} diff --git a/tests/ui/consts/const-eval/array-len-mismatch-type.stderr b/tests/ui/consts/const-eval/array-len-mismatch-type.stderr new file mode 100644 index 0000000000000..0f03006f00326 --- /dev/null +++ b/tests/ui/consts/const-eval/array-len-mismatch-type.stderr @@ -0,0 +1,39 @@ +error: the constant `5` is not of type `usize` + --> $DIR/array-len-mismatch-type.rs:2:17 + | +LL | pub struct Data([[&'static str]; 5_i32]); + | ^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `i32` + | + = note: the length of array `[[&'static str]; 5]` must be type `usize` + +error[E0277]: the size for values of type `[&'static str]` cannot be known at compilation time + --> $DIR/array-len-mismatch-type.rs:2:17 + | +LL | pub struct Data([[&'static str]; 5_i32]); + | ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[&'static str]` + = note: slice and array elements must have `Sized` type + +error[E0080]: the type `[[&str]; 5]` has an unknown layout + --> $DIR/array-len-mismatch-type.rs:6:39 + | +LL | const _: &'static Data = unsafe { &*(&[] as *const Data) }; + | ^^ evaluation of `_` failed here + +error[E0308]: mismatched types + --> $DIR/array-len-mismatch-type.rs:2:34 + | +LL | pub struct Data([[&'static str]; 5_i32]); + | ^^^^^ expected `usize`, found `i32` + | +help: change the type of the numeric literal from `i32` to `usize` + | +LL - pub struct Data([[&'static str]; 5_i32]); +LL + pub struct Data([[&'static str]; 5_usize]); + | + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0080, E0277, E0308. +For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/issues/issue-34373.rs b/tests/ui/issues/issue-34373.rs index 019cab42c6433..765bfc20a4517 100644 --- a/tests/ui/issues/issue-34373.rs +++ b/tests/ui/issues/issue-34373.rs @@ -4,9 +4,9 @@ trait Trait { fn foo(_: T) {} } -pub struct Foo>>; //~ ERROR cycle detected -//~^ ERROR `T` is never used -//~| ERROR cycle detected +pub struct Foo>>; +//~^ ERROR cycle detected when computing type of `Foo::T` +//~| ERROR type parameter `T` is never used type DefaultFoo = Foo; fn main() { diff --git a/tests/ui/issues/issue-34373.stderr b/tests/ui/issues/issue-34373.stderr index 49365a701ceee..6d68de8fb3b8a 100644 --- a/tests/ui/issues/issue-34373.stderr +++ b/tests/ui/issues/issue-34373.stderr @@ -1,22 +1,3 @@ -error[E0391]: cycle detected when computing type of `Foo::T` - --> $DIR/issue-34373.rs:7:34 - | -LL | pub struct Foo>>; - | ^^^^^^^^^^ - | -note: ...which requires expanding type alias `DefaultFoo`... - --> $DIR/issue-34373.rs:10:1 - | -LL | type DefaultFoo = Foo; - | ^^^^^^^^^^^^^^^ - = note: ...which again requires computing type of `Foo::T`, completing the cycle -note: cycle used when checking that `Foo` is well-formed - --> $DIR/issue-34373.rs:7:1 - | -LL | pub struct Foo>>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - error[E0391]: cycle detected when computing type of `Foo::T` --> $DIR/issue-34373.rs:7:34 | @@ -45,7 +26,7 @@ LL | pub struct Foo>>; = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0391, E0392. For more information about an error, try `rustc --explain E0391`. diff --git a/tests/ui/repeat-expr/repeat_count.rs b/tests/ui/repeat-expr/repeat_count.rs index 2febcdc07c2a1..b1e3a9d8cb3b6 100644 --- a/tests/ui/repeat-expr/repeat_count.rs +++ b/tests/ui/repeat-expr/repeat_count.rs @@ -21,16 +21,21 @@ fn main() { let f = [0; -4_isize]; //~^ ERROR mismatched types //~| NOTE expected `usize`, found `isize` - let f = [0_usize; -1_isize]; + //~| NOTE `-4_isize` cannot fit into type `usize` + let g = [0_usize; -1_isize]; //~^ ERROR mismatched types //~| NOTE expected `usize`, found `isize` - let f = [0; 4u8]; - //~^ ERROR mismatched types + //~| NOTE `-1_isize` cannot fit into type `usize` + let h = [0; 4u8]; + //~^ ERROR the constant `4` is not of type `usize` + //~| NOTE expected `usize`, found `u8` + //~| NOTE the length of array `[{integer}; 4]` must be type `usize` + //~| ERROR mismatched types //~| NOTE expected `usize`, found `u8` - struct G { - g: (), + struct I { + i: (), } - let g = [0; G { g: () }]; + let i = [0; I { i: () }]; //~^ ERROR mismatched types - //~| NOTE expected `usize`, found `G` + //~| NOTE expected `usize`, found `I` } diff --git a/tests/ui/repeat-expr/repeat_count.stderr b/tests/ui/repeat-expr/repeat_count.stderr index 8d8702e981e6f..5da9dbe032098 100644 --- a/tests/ui/repeat-expr/repeat_count.stderr +++ b/tests/ui/repeat-expr/repeat_count.stderr @@ -43,32 +43,40 @@ LL | let f = [0; -4_isize]; = note: `-4_isize` cannot fit into type `usize` error[E0308]: mismatched types - --> $DIR/repeat_count.rs:24:23 + --> $DIR/repeat_count.rs:25:23 | -LL | let f = [0_usize; -1_isize]; +LL | let g = [0_usize; -1_isize]; | ^^^^^^^^ expected `usize`, found `isize` | = note: `-1_isize` cannot fit into type `usize` +error: the constant `4` is not of type `usize` + --> $DIR/repeat_count.rs:29:13 + | +LL | let h = [0; 4u8]; + | ^^^^^^^^ expected `usize`, found `u8` + | + = note: the length of array `[{integer}; 4]` must be type `usize` + error[E0308]: mismatched types - --> $DIR/repeat_count.rs:27:17 + --> $DIR/repeat_count.rs:38:17 | -LL | let f = [0; 4u8]; +LL | let i = [0; I { i: () }]; + | ^^^^^^^^^^^ expected `usize`, found `I` + +error[E0308]: mismatched types + --> $DIR/repeat_count.rs:29:17 + | +LL | let h = [0; 4u8]; | ^^^ expected `usize`, found `u8` | help: change the type of the numeric literal from `u8` to `usize` | -LL - let f = [0; 4u8]; -LL + let f = [0; 4usize]; - | - -error[E0308]: mismatched types - --> $DIR/repeat_count.rs:33:17 +LL - let h = [0; 4u8]; +LL + let h = [0; 4usize]; | -LL | let g = [0; G { g: () }]; - | ^^^^^^^^^^^ expected `usize`, found `G` -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors Some errors have detailed explanations: E0308, E0435. For more information about an error, try `rustc --explain E0308`. From 01d48c62a5e6219f2893ac8eed40cf8ae38a7282 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 12 Feb 2026 01:50:19 +0000 Subject: [PATCH 11/11] Move LitToConstInput into ty::consts Relocate LitToConstInput and const_lit_matches_ty from mir::interpret to ty::consts::lit --- .../src/hir_ty_lowering/mod.rs | 5 +- .../rustc_middle/src/mir/interpret/mod.rs | 51 +---------------- compiler/rustc_middle/src/queries.rs | 6 +- compiler/rustc_middle/src/query/erase.rs | 2 +- compiler/rustc_middle/src/query/keys.rs | 2 +- compiler/rustc_middle/src/ty/consts.rs | 2 + compiler/rustc_middle/src/ty/consts/lit.rs | 55 +++++++++++++++++++ compiler/rustc_middle/src/ty/mod.rs | 5 +- .../src/builder/expr/as_constant.rs | 8 +-- compiler/rustc_mir_build/src/thir/constant.rs | 3 +- .../rustc_mir_build/src/thir/pattern/mod.rs | 5 +- compiler/rustc_ty_utils/src/consts.rs | 3 +- 12 files changed, 77 insertions(+), 70 deletions(-) create mode 100644 compiler/rustc_middle/src/ty/consts/lit.rs diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index e22aa990c3e7e..a897fa8a0dd53 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -35,11 +35,10 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::DynCompatibilityViolation; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::middle::stability::AllowUnstable; -use rustc_middle::mir::interpret::{LitToConstInput, const_lit_matches_ty}; use rustc_middle::ty::print::PrintPolyTraitRefExt as _; use rustc_middle::ty::{ - self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, - TypeSuperFoldable, TypeVisitableExt, TypingMode, Upcast, fold_regions, + self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, LitToConstInput, Ty, TyCtxt, + TypeSuperFoldable, TypeVisitableExt, TypingMode, Upcast, const_lit_matches_ty, fold_regions, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index f31610cd5e142..0abc3aec7e000 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -13,7 +13,7 @@ use std::num::NonZero; use std::{fmt, io}; use rustc_abi::{AddressSpace, Align, Endian, HasDataLayout, Size}; -use rustc_ast::{LitKind, Mutability}; +use rustc_ast::Mutability; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sharded::ShardedHashMap; use rustc_data_structures::sync::{AtomicU64, Lock}; @@ -73,55 +73,6 @@ impl<'tcx> GlobalId<'tcx> { } } -/// Input argument for `tcx.lit_to_const`. -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, HashStable)] -pub struct LitToConstInput<'tcx> { - /// The absolute value of the resultant constant. - pub lit: LitKind, - /// The type of the constant. - pub ty: Ty<'tcx>, - /// If the constant is negative. - pub neg: bool, -} - -pub fn const_lit_matches_ty<'tcx>( - tcx: TyCtxt<'tcx>, - kind: &LitKind, - ty: Ty<'tcx>, - neg: bool, -) -> bool { - match (*kind, ty.kind()) { - (LitKind::Str(..), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => true, - (LitKind::Str(..), ty::Str) if tcx.features().deref_patterns() => true, - (LitKind::ByteStr(..), ty::Ref(_, inner_ty, _)) - if let ty::Slice(ty) | ty::Array(ty, _) = inner_ty.kind() - && matches!(ty.kind(), ty::Uint(ty::UintTy::U8)) => - { - true - } - (LitKind::ByteStr(..), ty::Slice(inner_ty) | ty::Array(inner_ty, _)) - if tcx.features().deref_patterns() - && matches!(inner_ty.kind(), ty::Uint(ty::UintTy::U8)) => - { - true - } - (LitKind::Byte(..), ty::Uint(ty::UintTy::U8)) => true, - (LitKind::CStr(..), ty::Ref(_, inner_ty, _)) - if matches!(inner_ty.kind(), ty::Adt(def, _) - if tcx.is_lang_item(def.did(), rustc_hir::LangItem::CStr)) => - { - true - } - (LitKind::Int(..), ty::Uint(_)) if !neg => true, - (LitKind::Int(..), ty::Int(_)) => true, - (LitKind::Bool(..), ty::Bool) => true, - (LitKind::Float(..), ty::Float(_)) => true, - (LitKind::Char(..), ty::Char) => true, - (LitKind::Err(..), _) => true, - _ => false, - } -} - #[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct AllocId(pub NonZero); diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 60a03cc66d72b..68971df9eb8ea 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -112,7 +112,7 @@ use crate::middle::resolve_bound_vars::{ObjectLifetimeDefault, ResolveBoundVars, use crate::middle::stability::DeprecationEntry; use crate::mir::interpret::{ EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult, - EvalToValTreeResult, GlobalId, LitToConstInput, + EvalToValTreeResult, GlobalId, }; use crate::mir::mono::{ CodegenUnit, CollectionMode, MonoItem, MonoItemPartitions, NormalizationErrorInMono, @@ -135,8 +135,8 @@ use crate::ty::layout::ValidityRequirement; use crate::ty::print::PrintTraitRefExt; use crate::ty::util::AlwaysRequiresDrop; use crate::ty::{ - self, CrateInherentImpls, GenericArg, GenericArgsRef, PseudoCanonicalInput, SizedTraitKind, Ty, - TyCtxt, TyCtxtFeed, + self, CrateInherentImpls, GenericArg, GenericArgsRef, LitToConstInput, PseudoCanonicalInput, + SizedTraitKind, Ty, TyCtxt, TyCtxtFeed, }; use crate::{dep_graph, mir, thir}; diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index fe0368525e277..4d4833b4943e4 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -445,7 +445,6 @@ impl_erasable_for_single_lifetime_types! { rustc_middle::mir::DestructuredConstant, rustc_middle::mir::ConstAlloc, rustc_middle::mir::interpret::GlobalId, - rustc_middle::mir::interpret::LitToConstInput, rustc_middle::mir::interpret::EvalStaticInitializerRawResult, rustc_middle::mir::mono::MonoItemPartitions, rustc_middle::traits::query::MethodAutoderefStepsResult, @@ -470,6 +469,7 @@ impl_erasable_for_single_lifetime_types! { rustc_middle::ty::InstanceKind, rustc_middle::ty::layout::FnAbiError, rustc_middle::ty::layout::LayoutError, + rustc_middle::ty::LitToConstInput, rustc_middle::ty::ParamEnv, rustc_middle::ty::TypingEnv, rustc_middle::ty::Predicate, diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index cccb7d51bd3ed..2a1fe739134bb 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -87,7 +87,7 @@ impl<'tcx> Key for (Ty<'tcx>, Option>) { } } -impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> { +impl<'tcx> Key for ty::LitToConstInput<'tcx> { fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 3e17943a88574..aade274bfc98c 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -11,10 +11,12 @@ use crate::ty::{self, Ty, TyCtxt}; mod int; mod kind; +mod lit; mod valtree; pub use int::*; pub use kind::*; +pub use lit::*; use rustc_span::{DUMMY_SP, ErrorGuaranteed}; pub use valtree::*; diff --git a/compiler/rustc_middle/src/ty/consts/lit.rs b/compiler/rustc_middle/src/ty/consts/lit.rs new file mode 100644 index 0000000000000..3d41925131b40 --- /dev/null +++ b/compiler/rustc_middle/src/ty/consts/lit.rs @@ -0,0 +1,55 @@ +use rustc_ast::LitKind; +use rustc_hir; +use rustc_macros::HashStable; + +use crate::ty::{self, Ty, TyCtxt}; + +/// Input argument for `tcx.lit_to_const`. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, HashStable)] +pub struct LitToConstInput<'tcx> { + /// The absolute value of the resultant constant. + pub lit: LitKind, + /// The type of the constant. + pub ty: Ty<'tcx>, + /// If the constant is negative. + pub neg: bool, +} + +/// Checks whether a literal can be interpreted as a const of the given type. +pub fn const_lit_matches_ty<'tcx>( + tcx: TyCtxt<'tcx>, + kind: &LitKind, + ty: Ty<'tcx>, + neg: bool, +) -> bool { + match (*kind, ty.kind()) { + (LitKind::Str(..), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => true, + (LitKind::Str(..), ty::Str) if tcx.features().deref_patterns() => true, + (LitKind::ByteStr(..), ty::Ref(_, inner_ty, _)) + if let ty::Slice(ty) | ty::Array(ty, _) = inner_ty.kind() + && matches!(ty.kind(), ty::Uint(ty::UintTy::U8)) => + { + true + } + (LitKind::ByteStr(..), ty::Slice(inner_ty) | ty::Array(inner_ty, _)) + if tcx.features().deref_patterns() + && matches!(inner_ty.kind(), ty::Uint(ty::UintTy::U8)) => + { + true + } + (LitKind::Byte(..), ty::Uint(ty::UintTy::U8)) => true, + (LitKind::CStr(..), ty::Ref(_, inner_ty, _)) + if matches!(inner_ty.kind(), ty::Adt(def, _) + if tcx.is_lang_item(def.did(), rustc_hir::LangItem::CStr)) => + { + true + } + (LitKind::Int(..), ty::Uint(_)) if !neg => true, + (LitKind::Int(..), ty::Int(_)) => true, + (LitKind::Bool(..), ty::Bool) => true, + (LitKind::Float(..), ty::Float(_)) => true, + (LitKind::Char(..), ty::Char) => true, + (LitKind::Err(..), _) => true, + _ => false, + } +} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 37871aad4a775..0363977099254 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -76,8 +76,9 @@ pub use self::closure::{ place_to_string_for_capture, }; pub use self::consts::{ - AtomicOrdering, Const, ConstInt, ConstKind, ConstToValTreeResult, Expr, ExprKind, ScalarInt, - SimdAlign, UnevaluatedConst, ValTree, ValTreeKindExt, Value, + AtomicOrdering, Const, ConstInt, ConstKind, ConstToValTreeResult, Expr, ExprKind, + LitToConstInput, ScalarInt, SimdAlign, UnevaluatedConst, ValTree, ValTreeKindExt, Value, + const_lit_matches_ty, }; pub use self::context::{ CtxtInterners, CurrentGcx, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, TyCtxtFeed, tls, diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs index f50083abc8e47..ed5f0b2e8f759 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs @@ -1,14 +1,14 @@ -//! See docs in build/expr/mod.rs +//! See docs in builder/expr/mod.rs use rustc_abi::Size; use rustc_ast::{self as ast}; use rustc_hir::LangItem; -use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, LitToConstInput, Scalar}; +use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, Scalar}; use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty::{ - self, CanonicalUserType, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypeVisitableExt as _, - UserTypeAnnotationIndex, + self, CanonicalUserType, CanonicalUserTypeAnnotation, LitToConstInput, Ty, TyCtxt, + TypeVisitableExt as _, UserTypeAnnotationIndex, }; use rustc_middle::{bug, mir, span_bug}; use tracing::{instrument, trace}; diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index 6b93cf8ec8f49..b4eedb15033c8 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -2,8 +2,7 @@ use rustc_abi::Size; use rustc_ast::{self as ast, UintTy}; use rustc_hir::LangItem; use rustc_middle::bug; -use rustc_middle::mir::interpret::LitToConstInput; -use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt as _}; +use rustc_middle::ty::{self, LitToConstInput, ScalarInt, Ty, TyCtxt, TypeVisitableExt as _}; use tracing::trace; use crate::builder::parse_float_into_scalar; diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index a231f1fda4b44..acf20cb092e22 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -15,13 +15,14 @@ use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::{self as hir, RangeEnd}; use rustc_index::Idx; -use rustc_middle::mir::interpret::{LitToConstInput, const_lit_matches_ty}; use rustc_middle::thir::{ Ascription, DerefPatBorrowMode, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary, }; use rustc_middle::ty::adjustment::{PatAdjust, PatAdjustment}; use rustc_middle::ty::layout::IntegerExt; -use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt}; +use rustc_middle::ty::{ + self, CanonicalUserTypeAnnotation, LitToConstInput, Ty, TyCtxt, const_lit_matches_ty, +}; use rustc_middle::{bug, span_bug}; use rustc_span::ErrorGuaranteed; use tracing::{debug, instrument}; diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 5029b33e5b6c2..0edbe9624c4b6 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -1,12 +1,11 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; -use rustc_middle::mir::interpret::LitToConstInput; use rustc_middle::query::Providers; use rustc_middle::thir::visit; use rustc_middle::thir::visit::Visitor; use rustc_middle::ty::abstract_const::CastKind; -use rustc_middle::ty::{self, Expr, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, Expr, LitToConstInput, TyCtxt, TypeVisitableExt}; use rustc_middle::{mir, thir}; use rustc_span::Span; use tracing::instrument;