From f80ef134bc30c7feb2567b9ca141b78ea92fea5b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 10 Jun 2026 16:45:49 +0200 Subject: [PATCH 01/11] Make generate_proc_macro_decls_symbol a standalone function It doesn't access the Session anyway. --- compiler/rustc_codegen_ssa/src/back/linker.rs | 2 +- compiler/rustc_metadata/src/creader.rs | 5 ++--- compiler/rustc_session/src/session.rs | 8 ++++---- compiler/rustc_symbol_mangling/src/lib.rs | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index d40340e4d8c09..bde285c5c18fd 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1862,7 +1862,7 @@ fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<(String, Symbol } let stable_crate_id = tcx.stable_crate_id(LOCAL_CRATE); - let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id); + let proc_macro_decls_name = rustc_session::generate_proc_macro_decls_symbol(stable_crate_id); vec![(proc_macro_decls_name, SymbolExportKind::Data)] } diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index d18764bc6814a..470539b343e0b 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -653,7 +653,7 @@ impl CStore { None => (&source, &crate_root), }; let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate"); - Some(self.dlsym_proc_macros(tcx.sess, dlsym_dylib, dlsym_root.stable_crate_id())?) + Some(self.dlsym_proc_macros(dlsym_dylib, dlsym_root.stable_crate_id())?) } else { None }; @@ -948,11 +948,10 @@ impl CStore { fn dlsym_proc_macros( &self, - sess: &Session, path: &Path, stable_crate_id: StableCrateId, ) -> Result<&'static [ProcMacroClient], CrateError> { - let sym_name = sess.generate_proc_macro_decls_symbol(stable_crate_id); + let sym_name = rustc_session::generate_proc_macro_decls_symbol(stable_crate_id); debug!("trying to dlsym proc_macros {} for symbol `{}`", path.display(), sym_name); unsafe { diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 64818f0114b61..cddf3ad1453f1 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -416,10 +416,6 @@ impl Session { self.target.debuginfo_kind == DebuginfoKind::Dwarf } - pub fn generate_proc_macro_decls_symbol(&self, stable_crate_id: StableCrateId) -> String { - format!("__rustc_proc_macro_decls_{:08x}__", stable_crate_id.as_u64()) - } - pub fn target_filesearch(&self) -> &filesearch::FileSearch { &self.target_filesearch } @@ -1140,6 +1136,10 @@ pub fn build_session( sess } +pub fn generate_proc_macro_decls_symbol(stable_crate_id: StableCrateId) -> String { + format!("__rustc_proc_macro_decls_{:08x}__", stable_crate_id.as_u64()) +} + /// Validate command line arguments with a `Session`. /// /// If it is useful to have a Session available already for validating a commandline argument, you diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index c052037f05b39..c3b0bd6f40410 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -165,7 +165,7 @@ fn compute_symbol_name<'tcx>( if let Some(def_id) = def_id.as_local() { if tcx.proc_macro_decls_static(()) == Some(def_id) { let stable_crate_id = tcx.stable_crate_id(LOCAL_CRATE); - return tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id); + return rustc_session::generate_proc_macro_decls_symbol(stable_crate_id); } } From f80c17e5d3f47da9462d37382b1ecb79096586b3 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 10 Jun 2026 16:57:49 +0200 Subject: [PATCH 02/11] Extract load_symbol_from_dylib and dlsym_proc_macros into a new module --- compiler/rustc_metadata/src/creader.rs | 139 +------------------- compiler/rustc_metadata/src/host_dylib.rs | 147 ++++++++++++++++++++++ compiler/rustc_metadata/src/lib.rs | 3 +- 3 files changed, 150 insertions(+), 139 deletions(-) create mode 100644 compiler/rustc_metadata/src/host_dylib.rs diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 470539b343e0b..066f827b9826e 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -1,10 +1,8 @@ //! Validates all used crates and extern libraries and loads their metadata use std::collections::BTreeMap; -use std::error::Error; use std::path::Path; use std::str::FromStr; -use std::time::Duration; use std::{cmp, env, iter}; use rustc_ast::expand::allocator::{ALLOC_ERROR_HANDLER, AllocatorKind, global_fn_name}; @@ -15,7 +13,6 @@ use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{self, FreezeReadGuard, FreezeWriteGuard}; use rustc_data_structures::unord::UnordMap; use rustc_expand::base::SyntaxExtension; -use rustc_fs_util::try_canonicalize; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE, LocalDefId, StableCrateId}; use rustc_hir::definitions::Definitions; @@ -951,27 +948,7 @@ impl CStore { path: &Path, stable_crate_id: StableCrateId, ) -> Result<&'static [ProcMacroClient], CrateError> { - let sym_name = rustc_session::generate_proc_macro_decls_symbol(stable_crate_id); - debug!("trying to dlsym proc_macros {} for symbol `{}`", path.display(), sym_name); - - unsafe { - // FIXME(bjorn3) this depends on the unstable slice memory layout - let result = load_symbol_from_dylib::<*const &[ProcMacroClient]>(path, &sym_name); - match result { - Ok(result) => { - debug!("loaded dlsym proc_macros {} for symbol `{}`", path.display(), sym_name); - Ok(*result) - } - Err(err) => { - debug!( - "failed to dlsym proc_macros {} for symbol `{}`", - path.display(), - sym_name - ); - Err(err.into()) - } - } - } + Ok(crate::host_dylib::dlsym_proc_macros(path, stable_crate_id)?) } fn inject_panic_runtime(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) { @@ -1408,117 +1385,3 @@ fn fn_spans(krate: &ast::Crate, name: Symbol) -> Vec { visit::walk_crate(&mut f, krate); f.spans } - -fn format_dlopen_err(e: &(dyn std::error::Error + 'static)) -> String { - e.sources().map(|e| format!(": {e}")).collect() -} - -fn attempt_load_dylib(path: &Path) -> Result { - #[cfg(target_os = "aix")] - if let Some(ext) = path.extension() - && ext.eq("a") - { - // On AIX, we ship all libraries as .a big_af archive - // the expected format is lib.a(libname.so) for the actual - // dynamic library - let library_name = path.file_stem().expect("expect a library name"); - let mut archive_member = std::ffi::OsString::from("a("); - archive_member.push(library_name); - archive_member.push(".so)"); - let new_path = path.with_extension(archive_member); - - // On AIX, we need RTLD_MEMBER to dlopen an archived shared - let flags = libc::RTLD_LAZY | libc::RTLD_LOCAL | libc::RTLD_MEMBER; - return unsafe { libloading::os::unix::Library::open(Some(&new_path), flags) } - .map(|lib| lib.into()); - } - - unsafe { libloading::Library::new(&path) } -} - -// On Windows the compiler would sometimes intermittently fail to open the -// proc-macro DLL with `Error::LoadLibraryExW`. It is suspected that something in the -// system still holds a lock on the file, so we retry a few times before calling it -// an error. -fn load_dylib(path: &Path, max_attempts: usize) -> Result { - assert!(max_attempts > 0); - - let mut last_error = None; - - for attempt in 0..max_attempts { - debug!("Attempt to load proc-macro `{}`.", path.display()); - match attempt_load_dylib(path) { - Ok(lib) => { - if attempt > 0 { - debug!( - "Loaded proc-macro `{}` after {} attempts.", - path.display(), - attempt + 1 - ); - } - return Ok(lib); - } - Err(err) => { - // Only try to recover from this specific error. - if !matches!(err, libloading::Error::LoadLibraryExW { .. }) { - debug!("Failed to load proc-macro `{}`. Not retrying", path.display()); - let err = format_dlopen_err(&err); - // We include the path of the dylib in the error ourselves, so - // if it's in the error, we strip it. - if let Some(err) = err.strip_prefix(&format!(": {}", path.display())) { - return Err(err.to_string()); - } - return Err(err); - } - - last_error = Some(err); - std::thread::sleep(Duration::from_millis(100)); - debug!("Failed to load proc-macro `{}`. Retrying.", path.display()); - } - } - } - - debug!("Failed to load proc-macro `{}` even after {} attempts.", path.display(), max_attempts); - - let last_error = last_error.unwrap(); - let message = if let Some(src) = last_error.source() { - format!("{} ({src}) (retried {max_attempts} times)", format_dlopen_err(&last_error)) - } else { - format!("{} (retried {max_attempts} times)", format_dlopen_err(&last_error)) - }; - Err(message) -} - -pub enum DylibError { - DlOpen(String, String), - DlSym(String, String), -} - -impl From for CrateError { - fn from(err: DylibError) -> CrateError { - match err { - DylibError::DlOpen(path, err) => CrateError::DlOpen(path, err), - DylibError::DlSym(path, err) => CrateError::DlSym(path, err), - } - } -} - -pub unsafe fn load_symbol_from_dylib( - path: &Path, - sym_name: &str, -) -> Result { - // Make sure the path contains a / or the linker will search for it. - let path = try_canonicalize(path).unwrap(); - let lib = - load_dylib(&path, 5).map_err(|err| DylibError::DlOpen(path.display().to_string(), err))?; - - let sym = unsafe { lib.get::(sym_name.as_bytes()) } - .map_err(|err| DylibError::DlSym(path.display().to_string(), format_dlopen_err(&err)))?; - - // Intentionally leak the dynamic library. We can't ever unload it - // since the library can make things that will live arbitrarily long. - let sym = unsafe { sym.into_raw() }; - std::mem::forget(lib); - - Ok(*sym) -} diff --git a/compiler/rustc_metadata/src/host_dylib.rs b/compiler/rustc_metadata/src/host_dylib.rs new file mode 100644 index 0000000000000..9bd2a57fcd285 --- /dev/null +++ b/compiler/rustc_metadata/src/host_dylib.rs @@ -0,0 +1,147 @@ +use std::error::Error; +use std::path::Path; +use std::time::Duration; + +use rustc_fs_util::try_canonicalize; +use rustc_proc_macro::bridge::client::Client as ProcMacroClient; +use rustc_session::StableCrateId; +use tracing::debug; + +use crate::locator::CrateError; + +fn format_dlopen_err(e: &(dyn std::error::Error + 'static)) -> String { + e.sources().map(|e| format!(": {e}")).collect() +} + +fn attempt_load_dylib(path: &Path) -> Result { + #[cfg(target_os = "aix")] + if let Some(ext) = path.extension() + && ext.eq("a") + { + // On AIX, we ship all libraries as .a big_af archive + // the expected format is lib.a(libname.so) for the actual + // dynamic library + let library_name = path.file_stem().expect("expect a library name"); + let mut archive_member = std::ffi::OsString::from("a("); + archive_member.push(library_name); + archive_member.push(".so)"); + let new_path = path.with_extension(archive_member); + + // On AIX, we need RTLD_MEMBER to dlopen an archived shared + let flags = libc::RTLD_LAZY | libc::RTLD_LOCAL | libc::RTLD_MEMBER; + return unsafe { libloading::os::unix::Library::open(Some(&new_path), flags) } + .map(|lib| lib.into()); + } + + unsafe { libloading::Library::new(&path) } +} + +// On Windows the compiler would sometimes intermittently fail to open the +// proc-macro DLL with `Error::LoadLibraryExW`. It is suspected that something in the +// system still holds a lock on the file, so we retry a few times before calling it +// an error. +fn load_dylib(path: &Path, max_attempts: usize) -> Result { + assert!(max_attempts > 0); + + let mut last_error = None; + + for attempt in 0..max_attempts { + debug!("Attempt to load proc-macro `{}`.", path.display()); + match attempt_load_dylib(path) { + Ok(lib) => { + if attempt > 0 { + debug!( + "Loaded proc-macro `{}` after {} attempts.", + path.display(), + attempt + 1 + ); + } + return Ok(lib); + } + Err(err) => { + // Only try to recover from this specific error. + if !matches!(err, libloading::Error::LoadLibraryExW { .. }) { + debug!("Failed to load proc-macro `{}`. Not retrying", path.display()); + let err = format_dlopen_err(&err); + // We include the path of the dylib in the error ourselves, so + // if it's in the error, we strip it. + if let Some(err) = err.strip_prefix(&format!(": {}", path.display())) { + return Err(err.to_string()); + } + return Err(err); + } + + last_error = Some(err); + std::thread::sleep(Duration::from_millis(100)); + debug!("Failed to load proc-macro `{}`. Retrying.", path.display()); + } + } + } + + debug!("Failed to load proc-macro `{}` even after {} attempts.", path.display(), max_attempts); + + let last_error = last_error.unwrap(); + let message = if let Some(src) = last_error.source() { + format!("{} ({src}) (retried {max_attempts} times)", format_dlopen_err(&last_error)) + } else { + format!("{} (retried {max_attempts} times)", format_dlopen_err(&last_error)) + }; + Err(message) +} + +pub enum DylibError { + DlOpen(String, String), + DlSym(String, String), +} + +impl From for CrateError { + fn from(err: DylibError) -> CrateError { + match err { + DylibError::DlOpen(path, err) => CrateError::DlOpen(path, err), + DylibError::DlSym(path, err) => CrateError::DlSym(path, err), + } + } +} + +pub unsafe fn load_symbol_from_dylib( + path: &Path, + sym_name: &str, +) -> Result { + // Make sure the path contains a / or the linker will search for it. + let path = try_canonicalize(path).unwrap(); + let lib = + load_dylib(&path, 5).map_err(|err| DylibError::DlOpen(path.display().to_string(), err))?; + + let sym = unsafe { lib.get::(sym_name.as_bytes()) } + .map_err(|err| DylibError::DlSym(path.display().to_string(), format_dlopen_err(&err)))?; + + // Intentionally leak the dynamic library. We can't ever unload it + // since the library can make things that will live arbitrarily long. + let sym = unsafe { sym.into_raw() }; + std::mem::forget(lib); + + Ok(*sym) +} + +pub(crate) fn dlsym_proc_macros( + path: &Path, + stable_crate_id: StableCrateId, +) -> Result<&'static [ProcMacroClient], DylibError> { + let sym_name = rustc_session::generate_proc_macro_decls_symbol(stable_crate_id); + debug!("trying to dlsym proc_macros {} for symbol `{}`", path.display(), sym_name); + + unsafe { + // FIXME(bjorn3) this depends on the unstable slice memory layout + let result = crate::load_symbol_from_dylib::<*const &[ProcMacroClient]>(path, &sym_name); + match result { + Ok(result) => { + debug!("loaded dlsym proc_macros {} for symbol `{}`", path.display(), sym_name); + Ok(*result) + } + Err(err) => { + debug!("failed to dlsym proc_macros {} for symbol `{}`", path.display(), sym_name); + Err(err.into()) + } + } + } +} diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index ebaff2a2d8f97..b16482d9eb6fb 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -17,6 +17,7 @@ pub use rmeta::provide; mod dependency_format; mod eii; mod foreign_modules; +mod host_dylib; mod native_libs; mod rmeta; @@ -25,8 +26,8 @@ pub mod errors; pub mod fs; pub mod locator; -pub use creader::{DylibError, load_symbol_from_dylib}; pub use fs::{METADATA_FILENAME, emit_wrapper_file}; +pub use host_dylib::{DylibError, load_symbol_from_dylib}; pub use native_libs::{ NativeLibSearchFallback, find_native_static_library, try_find_native_dynamic_library, try_find_native_static_library, walk_native_lib_search_dirs, From 88c2f7db56d5e6d0b19f7e1d5f477d03e077d94a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 10 Jun 2026 17:00:29 +0200 Subject: [PATCH 03/11] Move proc-macro dlopen from proc-macro-srv to rustc_metadata This will make it easier to change how proc-macros are implemented on the rustc side. For example allowing support for wasm proc-macros without duplicating the implementation between proc-macro-srv and rustc. --- compiler/rustc_metadata/src/locator.rs | 32 ++-- src/tools/rust-analyzer/Cargo.lock | 34 +--- src/tools/rust-analyzer/Cargo.toml | 9 - .../crates/proc-macro-srv/Cargo.toml | 6 - .../crates/proc-macro-srv/src/dylib.rs | 169 +----------------- .../proc-macro-srv/src/dylib/proc_macros.rs | 8 +- .../crates/proc-macro-srv/src/lib.rs | 3 +- 7 files changed, 34 insertions(+), 227 deletions(-) diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index e8b78fdbea3ff..9def206c2f3a1 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -213,7 +213,7 @@ //! metadata::locator or metadata::creader for all the juicy details! use std::borrow::Cow; -use std::io::{Result as IoResult, Write}; +use std::io::{self, Result as IoResult, Write}; use std::ops::Deref; use std::path::{Path, PathBuf}; use std::{cmp, fmt}; @@ -224,6 +224,7 @@ use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned}; use rustc_data_structures::svh::Svh; use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_fs_util::try_canonicalize; +use rustc_proc_macro::bridge::client::Client as ProcMacroClient; use rustc_session::cstore::CrateSource; use rustc_session::filesearch::FileSearch; use rustc_session::search_paths::PathKind; @@ -821,7 +822,7 @@ fn get_metadata_section<'p>( crate_name: Option, ) -> Result> { if !filename.exists() { - return Err(MetadataError::NotPresent(filename.into())); + return Err(MetadataError::NotPresent(filename)); } let raw_bytes = match flavor { CrateFlavor::Rlib => { @@ -978,18 +979,29 @@ fn get_flavor_from_path(path: &Path) -> CrateFlavor { } } -/// A function to get information about all macros inside a proc-macro crate. +/// A function to fetch about all macros inside a proc-macro crate. /// /// Used by rust-analyzer-proc-macro-srv. -pub fn get_proc_macro_info<'p>( +pub fn get_proc_macros( target: &Target, - path: &'p Path, + path: &Path, metadata_loader: &dyn MetadataLoader, cfg_version: &'static str, -) -> Result, MetadataError<'p>> { +) -> IoResult> { let metadata = - get_metadata_section(target, CrateFlavor::Dylib, path, metadata_loader, cfg_version, None)?; - Ok(metadata.get_proc_macro_info()) + get_metadata_section(target, CrateFlavor::Dylib, path, metadata_loader, cfg_version, None) + .map_err(|err| io::Error::other(err.to_string()))?; + let stable_crate_id = metadata.get_root().stable_crate_id(); + + let clients = crate::host_dylib::dlsym_proc_macros(path, stable_crate_id).map_err(|err| { + let (crate::DylibError::DlOpen(path, err) | crate::DylibError::DlSym(path, err)) = err; + io::Error::other(format!("{path}{err}")) + })?; + + let proc_macro_info = metadata.get_proc_macro_info(); + assert_eq!(proc_macro_info.len(), clients.len()); + + Ok(clients.into_iter().copied().zip(proc_macro_info).collect()) } // ------------------------------------------ Error reporting ------------------------------------- @@ -1039,9 +1051,9 @@ pub(crate) enum CrateError { } #[derive(Debug)] -pub enum MetadataError<'a> { +pub(crate) enum MetadataError<'a> { /// The file was missing. - NotPresent(Cow<'a, Path>), + NotPresent(&'a Path), /// The file was present and invalid. LoadFailure(String), /// The file was present, but compiled with a different rustc version. diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 5e39dfe87004b..477ecfba2f752 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -90,7 +90,7 @@ dependencies = [ "cfg-if", "libc", "miniz_oxide", - "object 0.37.3", + "object", "rustc-demangle", "windows-link", ] @@ -1416,16 +1416,6 @@ version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" -[[package]] -name = "libloading" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" -dependencies = [ - "cfg-if", - "windows-link", -] - [[package]] name = "libmimalloc-sys" version = "0.1.49" @@ -1589,15 +1579,6 @@ version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" -[[package]] -name = "memmap2" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" -dependencies = [ - "libc", -] - [[package]] name = "memoffset" version = "0.9.1" @@ -1756,15 +1737,6 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - [[package]] name = "object" version = "0.37.3" @@ -1992,11 +1964,7 @@ version = "0.0.0" dependencies = [ "expect-test", "intern", - "libc", - "libloading", "line-index 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "memmap2", - "object 0.36.7", "paths", "proc-macro-test", "span", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 37e5dbb444223..3e2815e87560b 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -116,17 +116,8 @@ expect-test = "1.5.1" indexmap = { version = "2.9.0", features = ["serde"] } itertools = "0.14.0" libc = "0.2.172" -libloading = "0.8.8" -memmap2 = "0.9.5" nohash-hasher = "0.2.0" oorandom = "11.1.5" -object = { version = "0.36.7", default-features = false, features = [ - "std", - "read_core", - "elf", - "macho", - "pe", -] } postcard = { version = "1.1.3", features = ["alloc"] } process-wrap = { version = "9.1.0", features = ["std"] } pulldown-cmark-to-cmark = "10.0.4" diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml index 72d394d37bfd4..f5d40a4b9ffc2 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml @@ -13,9 +13,6 @@ rust-version.workspace = true doctest = false [dependencies] -object.workspace = true -libloading.workspace = true -memmap2.workspace = true temp-dir.workspace = true paths.workspace = true @@ -24,9 +21,6 @@ span = { path = "../span", version = "0.0.0", default-features = false} intern.workspace = true -[target.'cfg(unix)'.dependencies] -libc.workspace = true - [dev-dependencies] expect-test.workspace = true line-index.workspace = true diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs index f654d21cfe26d..1978a68dd959c 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs @@ -4,22 +4,18 @@ mod proc_macros; use rustc_codegen_ssa::back::metadata::DefaultMetadataLoader; use rustc_interface::util::rustc_version_str; -use rustc_metadata::locator::MetadataError; use rustc_proc_macro::bridge; use rustc_session::config::host_tuple; use rustc_target::spec::{Target, TargetTuple}; use std::path::Path; -use std::{fmt, fs, io, time::SystemTime}; +use std::{fs, io, time::SystemTime}; use temp_dir::TempDir; -use libloading::Library; -use object::Object; use paths::{Utf8Path, Utf8PathBuf}; use crate::{ PanicMessage, ProcMacroClientHandle, ProcMacroKind, ProcMacroSrvSpan, TrackedEnv, - dylib::proc_macros::{ProcMacroClients, ProcMacros}, - token_stream::TokenStream, + dylib::proc_macros::ProcMacros, token_stream::TokenStream, }; pub(crate) struct Expander { @@ -28,10 +24,7 @@ pub(crate) struct Expander { } impl Expander { - pub(crate) fn new( - temp_dir: &TempDir, - lib: &Utf8Path, - ) -> Result { + pub(crate) fn new(temp_dir: &TempDir, lib: &Utf8Path) -> io::Result { // Some libraries for dynamic loading require canonicalized path even when it is // already absolute let lib = lib.canonicalize_utf8()?; @@ -78,61 +71,17 @@ impl Expander { } } -#[derive(Debug)] -pub enum LoadProcMacroDylibError { - Io(io::Error), - LibLoading(libloading::Error), - MetadataError(MetadataError<'static>), -} - -impl fmt::Display for LoadProcMacroDylibError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Io(e) => e.fmt(f), - Self::LibLoading(e) => e.fmt(f), - Self::MetadataError(e) => e.fmt(f), - } - } -} - -impl From for LoadProcMacroDylibError { - fn from(e: io::Error) -> Self { - LoadProcMacroDylibError::Io(e) - } -} - -impl From for LoadProcMacroDylibError { - fn from(e: libloading::Error) -> Self { - LoadProcMacroDylibError::LibLoading(e) - } -} - -impl From> for LoadProcMacroDylibError { - fn from(e: MetadataError<'_>) -> Self { - LoadProcMacroDylibError::MetadataError(match e { - MetadataError::NotPresent(path) => MetadataError::NotPresent(path.into_owned().into()), - MetadataError::LoadFailure(err) => MetadataError::LoadFailure(err), - MetadataError::VersionMismatch { expected_version, found_version } => { - MetadataError::VersionMismatch { expected_version, found_version } - } - }) - } -} - struct ProcMacroLibrary { - // this contains references to the library, so make sure this drops before _lib proc_macros: ProcMacros, - // Hold on to the library so it doesn't unload - _lib: Library, } impl ProcMacroLibrary { - fn open(path: &Utf8Path) -> Result { - let proc_macro_kinds = rustc_span::create_default_session_globals_then(|| { + fn open(path: &Utf8Path) -> io::Result { + let proc_macros = rustc_span::create_default_session_globals_then(|| { let (target, _) = Target::search(&TargetTuple::from_tuple(host_tuple()), Path::new(""), false) .unwrap(); - rustc_metadata::locator::get_proc_macro_info( + rustc_metadata::locator::get_proc_macros( &target, path.as_ref(), &DefaultMetadataLoader, @@ -140,63 +89,10 @@ impl ProcMacroLibrary { ) })?; - let file = fs::File::open(path)?; - #[allow(clippy::undocumented_unsafe_blocks)] // FIXME - let file = unsafe { memmap2::Mmap::map(&file) }?; - let obj = object::File::parse(&*file) - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; - let symbol_name = - find_registrar_symbol(&obj).map_err(invalid_data_err)?.ok_or_else(|| { - invalid_data_err(format!("Cannot find registrar symbol in file {path}")) - })?; - - // SAFETY: We have verified the validity of the dylib as a proc-macro library - let lib = unsafe { load_library(path) }.map_err(invalid_data_err)?; - // SAFETY: We have verified the validity of the dylib as a proc-macro library - // The 'static lifetime is a lie, it's actually the lifetime of the library but unavoidable - // due to self-referentiality - // But we make sure that we do not drop it before the symbol is dropped - let proc_macros = - unsafe { lib.get::<&'static &'static ProcMacroClients>(symbol_name.as_bytes()) }; - match proc_macros { - Ok(proc_macros) => Ok(ProcMacroLibrary { - proc_macros: ProcMacros::new(*proc_macros, proc_macro_kinds), - _lib: lib, - }), - Err(e) => Err(e.into()), - } + Ok(ProcMacroLibrary { proc_macros: ProcMacros::new(proc_macros) }) } } -fn invalid_data_err(e: impl Into>) -> io::Error { - io::Error::new(io::ErrorKind::InvalidData, e) -} - -fn is_derive_registrar_symbol(symbol: &str) -> bool { - const NEW_REGISTRAR_SYMBOL: &str = "_rustc_proc_macro_decls_"; - symbol.contains(NEW_REGISTRAR_SYMBOL) -} - -fn find_registrar_symbol(obj: &object::File<'_>) -> object::Result> { - Ok(obj - .exports()? - .into_iter() - .map(|export| export.name()) - .filter_map(|sym| String::from_utf8(sym.into()).ok()) - .find(|sym| is_derive_registrar_symbol(sym)) - .map(|sym| { - // From MacOS docs: - // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dlsym.3.html - // Unlike other dyld API's, the symbol name passed to dlsym() must NOT be - // prepended with an underscore. - if cfg!(target_os = "macos") && sym.starts_with('_') { - sym[1..].to_owned() - } else { - sym - } - })) -} - /// Copy the dylib to temp directory to prevent locking in Windows #[cfg(windows)] fn ensure_file_with_lock_free_access( @@ -233,54 +129,3 @@ fn ensure_file_with_lock_free_access( ) -> io::Result { Ok(path.to_owned()) } - -/// Loads dynamic library in platform dependent manner. -/// -/// For unix, you have to use RTLD_DEEPBIND flag to escape problems described -/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample) -/// and [here](https://github.com/rust-lang/rust/issues/60593). -/// -/// Usage of RTLD_DEEPBIND -/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample/issues/1) -/// -/// It seems that on Windows that behaviour is default, so we do nothing in that case. -/// -/// # Safety -/// -/// The caller is responsible for ensuring that the path is valid proc-macro library -#[cfg(windows)] -unsafe fn load_library(file: &Utf8Path) -> Result { - // SAFETY: The caller is responsible for ensuring that the path is valid proc-macro library - unsafe { Library::new(file) } -} - -/// Loads dynamic library in platform dependent manner. -/// -/// For unix, you have to use RTLD_DEEPBIND flag to escape problems described -/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample) -/// and [here](https://github.com/rust-lang/rust/issues/60593). -/// -/// Usage of RTLD_DEEPBIND -/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample/issues/1) -/// -/// It seems that on Windows that behaviour is default, so we do nothing in that case. -/// -/// # Safety -/// -/// The caller is responsible for ensuring that the path is valid proc-macro library -#[cfg(unix)] -unsafe fn load_library(file: &Utf8Path) -> Result { - // not defined by POSIX, different values on mips vs other targets - #[cfg(target_env = "gnu")] - use libc::RTLD_DEEPBIND; - use libloading::os::unix::Library as UnixLibrary; - // defined by POSIX - use libloading::os::unix::RTLD_NOW; - - // MUSL and bionic don't have it.. - #[cfg(not(target_env = "gnu"))] - const RTLD_DEEPBIND: std::os::raw::c_int = 0x0; - - // SAFETY: The caller is responsible for ensuring that the path is valid proc-macro library - unsafe { UnixLibrary::open(Some(file), RTLD_NOW | RTLD_DEEPBIND).map(|lib| lib.into()) } -} 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 ef6752d81698d..4976298d5fcd1 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 @@ -4,9 +4,6 @@ use crate::{ }; use rustc_proc_macro::bridge; -#[repr(transparent)] -pub(crate) struct ProcMacroClients([bridge::client::Client]); - impl From for crate::PanicMessage { fn from(p: bridge::PanicMessage) -> Self { Self { message: p.into_string() } @@ -17,10 +14,9 @@ pub(crate) struct ProcMacros(Vec<(bridge::client::Client, rustc_metadata::ProcMa impl ProcMacros { pub(super) fn new( - clients: &ProcMacroClients, - kinds: Vec, + macros: Vec<(bridge::client::Client, rustc_metadata::ProcMacroKind)>, ) -> Self { - ProcMacros(clients.0.iter().copied().zip(kinds).collect::>()) + ProcMacros(macros) } pub(crate) fn expand<'a, S: ProcMacroSrvSpan>( diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index b8cd3621d698f..2a3a1bc002601 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -10,9 +10,10 @@ #![cfg(feature = "in-rust-tree")] #![feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span, rustc_private)] -#![expect(unreachable_pub, internal_features, clippy::disallowed_types, clippy::print_stderr)] +#![expect(internal_features, clippy::disallowed_types, clippy::print_stderr)] #![allow(unused_features, unused_crate_dependencies)] #![deny(deprecated_safe, clippy::undocumented_unsafe_blocks)] +#![cfg_attr(test, expect(unreachable_pub))] extern crate rustc_codegen_ssa; extern crate rustc_driver as _; From 48fea6230a358b7364d27f041745f194d78bcc1a Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 18 Jun 2026 23:00:55 +0000 Subject: [PATCH 04/11] Update actions/download-artifact action to v8.0.1 --- .github/workflows/dependencies.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml index be0db12b52f3a..f62b8e542652b 100644 --- a/.github/workflows/dependencies.yml +++ b/.github/workflows/dependencies.yml @@ -94,11 +94,11 @@ jobs: uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - name: download Cargo.lock from update job - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: Cargo-lock - name: download cargo-update log from update job - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: cargo-updates From d81944d256bebe668a08b32c4f477da852fde2ad Mon Sep 17 00:00:00 2001 From: Amy Kwan Date: Fri, 19 Jun 2026 19:32:12 +0000 Subject: [PATCH 05/11] Update backtrace submodule to pick up AIX related fixes. --- library/backtrace | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/backtrace b/library/backtrace index 28ec93b503bf0..d902726a1dcdc 160000 --- a/library/backtrace +++ b/library/backtrace @@ -1 +1 @@ -Subproject commit 28ec93b503bf0410745bc3d571bf3dc1caac3019 +Subproject commit d902726a1dcdc1e1c66f73d1162181b5423c645b From 93741ff905300d2a56fe6bc4c750795483e8f0bb Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 20 Jun 2026 17:27:13 +0200 Subject: [PATCH 06/11] Adjust `InvalidTarget` emitting for diagnostic attributes --- compiler/rustc_attr_parsing/src/target_checking.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index 1c2716c911b7b..9903c6aa68d01 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -129,6 +129,7 @@ impl<'sess> AttributeParser<'sess> { let allowed_targets = allowed_targets.allowed_targets(); let (applied, only) = allowed_targets_applied(allowed_targets, cx.target, cx.features); + let is_diagnostic_attr = cx.attr_path.segments[0] == sym::diagnostic; let diag = InvalidTarget { span: cx.attr_span.clone(), @@ -138,7 +139,7 @@ impl<'sess> AttributeParser<'sess> { applied: DiagArgValue::StrListSepByAnd(applied.into_iter().map(Cow::Owned).collect()), attribute_args, help: Self::target_checking_help(attribute_args, cx), - previously_accepted: matches!(result, AllowedResult::Warn), + previously_accepted: matches!(result, AllowedResult::Warn) && !is_diagnostic_attr, on_macro_call: matches!(cx.target, Target::MacroCall), }; @@ -156,6 +157,8 @@ impl<'sess> AttributeParser<'sess> { .contains(&cx.target) { rustc_session::lint::builtin::USELESS_DEPRECATED + } else if is_diagnostic_attr { + rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES } else { rustc_session::lint::builtin::UNUSED_ATTRIBUTES }; From 9e09aee5b6b88c5f5f047c26024dbe44f9d9f762 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 20 Jun 2026 17:31:42 +0200 Subject: [PATCH 07/11] Use the new logic for the diagnostic attributes --- .../attributes/diagnostic/do_not_recommend.rs | 21 ++--- .../src/attributes/diagnostic/on_const.rs | 20 ++--- .../src/attributes/diagnostic/on_move.rs | 16 ++-- .../attributes/diagnostic/on_type_error.rs | 15 ++-- .../attributes/diagnostic/on_unimplemented.rs | 15 +--- .../src/attributes/diagnostic/on_unknown.rs | 23 ++---- .../diagnostic/on_unmatched_args.rs | 14 +--- .../rustc_attr_parsing/src/diagnostics.rs | 39 ---------- .../traits/on_unimplemented.rs | 5 ++ .../incorrect-locations.current.stderr | 62 +++++++-------- .../incorrect-locations.next.stderr | 62 +++++++-------- .../do_not_recommend/incorrect-locations.rs | 18 ++--- .../on_const/misplaced_attr.rs | 6 +- .../on_const/misplaced_attr.stderr | 35 ++++----- .../on_move/report_warning_on_non_adt.rs | 2 +- .../on_move/report_warning_on_non_adt.stderr | 3 +- .../report_warning_on_non_adt.rs | 12 +-- .../report_warning_on_non_adt.stderr | 23 ++++-- ...options_of_the_internal_rustc_attribute.rs | 2 +- ...ons_of_the_internal_rustc_attribute.stderr | 3 +- ...o_not_fail_parsing_on_invalid_options_1.rs | 2 +- ...t_fail_parsing_on_invalid_options_1.stderr | 3 +- .../on_unimplemented/on_impl_trait.rs | 2 +- .../on_unimplemented/on_impl_trait.stderr | 3 +- .../on_unknown/incorrect_locations.rs | 22 +++--- .../on_unknown/incorrect_locations.stderr | 76 ++++++++----------- .../incorrect_unstable_positions.rs | 2 +- .../incorrect_unstable_positions.stderr | 6 +- .../report_warning_on_non_macro.rs | 2 +- .../report_warning_on_non_macro.stderr | 3 +- 30 files changed, 197 insertions(+), 320 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs index 5b61e83b5e6bd..85708273a409b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs @@ -1,16 +1,14 @@ use rustc_feature::AttributeStability; use rustc_hir::Target; use rustc_hir::attrs::AttributeKind; -use rustc_session::lint::builtin::{ - MALFORMED_DIAGNOSTIC_ATTRIBUTES, MISPLACED_DIAGNOSTIC_ATTRIBUTES, -}; +use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES; use rustc_span::{Symbol, sym}; +use crate::attributes::prelude::Allow; use crate::attributes::{OnDuplicate, SingleAttributeParser}; use crate::context::AcceptContext; -use crate::diagnostics::IncorrectDoNotRecommendLocation; use crate::parser::ArgParser; -use crate::target_checking::{ALL_TARGETS, AllowedTargets}; +use crate::target_checking::AllowedTargets; use crate::{AttributeTemplate, template}; pub(crate) struct DoNotRecommendParser; @@ -18,7 +16,8 @@ impl SingleAttributeParser for DoNotRecommendParser { const PATH: &[Symbol] = &[sym::diagnostic, sym::do_not_recommend]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; // "Allowed" on any target, noop on all but trait impls - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowListWarnRest(&[Allow(Target::Impl { of_trait: true })]); const TEMPLATE: AttributeTemplate = template!(Word /*doesn't matter */); const STABILITY: AttributeStability = AttributeStability::Stable; @@ -32,16 +31,6 @@ impl SingleAttributeParser for DoNotRecommendParser { ); } - if !matches!(cx.target, Target::Impl { of_trait: true }) { - let target_span = cx.target_span; - cx.emit_lint( - MISPLACED_DIAGNOSTIC_ATTRIBUTES, - IncorrectDoNotRecommendLocation { target_span }, - attr_span, - ); - return None; - } - Some(AttributeKind::DoNotRecommend) } } diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs index 42159e8057f14..dc8260ae944ef 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs @@ -1,10 +1,8 @@ use rustc_feature::AttributeStability; use rustc_hir::attrs::diagnostic::Directive; -use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES; use crate::attributes::diagnostic::*; use crate::attributes::prelude::*; -use crate::diagnostics::DiagnosticOnConstOnlyForTraitImpls; #[derive(Default)] pub(crate) struct OnConstParser { span: Option, @@ -26,18 +24,6 @@ impl AttributeParser for OnConstParser { let span = cx.attr_span; this.span = Some(span); - // FIXME(mejrs) no constness field on `Target`, - // so non-constness is still checked in check_attr.rs - if !matches!(cx.target, Target::Impl { of_trait: true }) { - let target_span = cx.target_span; - cx.emit_lint( - MISPLACED_DIAGNOSTIC_ATTRIBUTES, - DiagnosticOnConstOnlyForTraitImpls { target_span }, - span, - ); - return; - } - let mode = Mode::DiagnosticOnConst; let Some(items) = parse_list(cx, args, mode) else { return }; @@ -51,7 +37,11 @@ impl AttributeParser for OnConstParser { // "Allowed" on all targets; noop on anything but non-const trait impls; // this linted on in parser. - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + // FIXME(mejrs) no constness field on `Target`, + // so non-constness is still checked in check_attr.rs + Allow(Target::Impl { of_trait: true }), + ]); fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option { if let Some(span) = self.span { diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs index 38d2e7f8f53e6..ec77ede4127f5 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs @@ -1,14 +1,12 @@ use rustc_feature::AttributeStability; use rustc_hir::attrs::AttributeKind; -use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES; use rustc_span::sym; use crate::attributes::diagnostic::*; use crate::attributes::prelude::*; use crate::context::AcceptContext; -use crate::diagnostics::DiagnosticOnMoveOnlyForAdt; use crate::parser::ArgParser; -use crate::target_checking::{ALL_TARGETS, AllowedTargets}; +use crate::target_checking::AllowedTargets; use crate::template; #[derive(Default)] @@ -28,11 +26,6 @@ impl OnMoveParser { let span = cx.attr_span; self.span = Some(span); - if !matches!(cx.target, Target::Enum | Target::Struct | Target::Union) { - cx.emit_lint(MISPLACED_DIAGNOSTIC_ATTRIBUTES, DiagnosticOnMoveOnlyForAdt, span); - return; - } - let Some(items) = parse_list(cx, args, mode) else { return }; if let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) { @@ -50,8 +43,11 @@ impl AttributeParser for OnMoveParser { }, )]; - // "Allowed" for all targets but noop if used on not-adt. - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + Allow(Target::Enum), + Allow(Target::Struct), + Allow(Target::Union), + ]); fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option { if let Some(_span) = self.span { diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_type_error.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_type_error.rs index a1d7ff2004c2c..d5636b23a09b1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_type_error.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_type_error.rs @@ -1,14 +1,12 @@ use rustc_hir::attrs::AttributeKind; -use rustc_lint_defs::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES; use rustc_span::sym; use crate::attributes::AttributeStability; use crate::attributes::diagnostic::*; use crate::attributes::prelude::*; use crate::context::AcceptContext; -use crate::diagnostics::DiagnosticOnTypeErrorOnlyForAdt; use crate::parser::ArgParser; -use crate::target_checking::{ALL_TARGETS, AllowedTargets}; +use crate::target_checking::AllowedTargets; use crate::template; #[derive(Default)] @@ -26,11 +24,6 @@ impl OnTypeErrorParser { let span = cx.attr_span; self.span = Some(span); - if !matches!(cx.target, Target::Enum | Target::Struct | Target::Union) { - cx.emit_lint(MISPLACED_DIAGNOSTIC_ATTRIBUTES, DiagnosticOnTypeErrorOnlyForAdt, span); - return; - } - let Some(items) = parse_list(cx, args, mode) else { return }; if let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) { @@ -49,7 +42,11 @@ impl AttributeParser for OnTypeErrorParser { }, )]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + Allow(Target::Enum), + Allow(Target::Struct), + Allow(Target::Union), + ]); fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option { if let Some(span) = self.span { diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unimplemented.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unimplemented.rs index b06bf88dc7ab8..86a96f7093587 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unimplemented.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unimplemented.rs @@ -1,10 +1,8 @@ use rustc_feature::AttributeStability; use rustc_hir::attrs::diagnostic::Directive; -use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES; use crate::attributes::diagnostic::*; use crate::attributes::prelude::*; -use crate::diagnostics::DiagnosticOnUnimplementedOnlyForTraits; #[derive(Default)] pub(crate) struct OnUnimplementedParser { @@ -17,15 +15,6 @@ impl OnUnimplementedParser { let span = cx.attr_span; self.span = Some(span); - if !matches!(cx.target, Target::Trait) { - cx.emit_lint( - MISPLACED_DIAGNOSTIC_ATTRIBUTES, - DiagnosticOnUnimplementedOnlyForTraits, - span, - ); - return; - } - let Some(items) = parse_list(cx, args, mode) else { return }; if let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) { @@ -56,8 +45,8 @@ impl AttributeParser for OnUnimplementedParser { }, ), ]; - //FIXME attribute is not parsed for non-traits but diagnostics are issued in `check_attr.rs` - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowListWarnRest(&[Allow(Target::Trait)]); fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option { if let Some(_span) = self.span { diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs index f1e4b8415185e..fc05ae9150d15 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs @@ -1,11 +1,8 @@ use rustc_feature::AttributeStability; use rustc_hir::attrs::diagnostic::Directive; -use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES; -use crate::ShouldEmit; use crate::attributes::diagnostic::*; use crate::attributes::prelude::*; -use crate::diagnostics::DiagnosticOnUnknownInvalidTarget; #[derive(Default)] pub(crate) struct OnUnknownParser { @@ -25,20 +22,6 @@ impl OnUnknownParser { let span = cx.attr_span; self.span = Some(span); - // At early parsing we get passed `Target::Crate` regardless of the item we're on. - // Therefore, only do target checking if we can emit. - let early = matches!(cx.should_emit, ShouldEmit::Nothing); - - if !early && !matches!(cx.target, Target::Use | Target::Mod | Target::Crate) { - let target_span = cx.target_span; - cx.emit_lint( - MISPLACED_DIAGNOSTIC_ATTRIBUTES, - DiagnosticOnUnknownInvalidTarget { target_span }, - span, - ); - return; - } - let Some(items) = parse_list(cx, args, mode) else { return }; if let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) { @@ -57,7 +40,11 @@ impl AttributeParser for OnUnknownParser { }, )]; // "Allowed" for all targets, but noop for all but use statements. - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + Allow(Target::Use), + Allow(Target::Mod), + Allow(Target::Crate), + ]); fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option { if let Some(_span) = self.span { diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unmatched_args.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unmatched_args.rs index 17b9fcd52d225..44975cd49c93f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unmatched_args.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unmatched_args.rs @@ -1,10 +1,8 @@ use rustc_feature::AttributeStability; use rustc_hir::attrs::diagnostic::Directive; -use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES; use crate::attributes::diagnostic::*; use crate::attributes::prelude::*; -use crate::diagnostics::DiagnosticOnUnmatchedArgsOnlyForMacros; #[derive(Default)] pub(crate) struct OnUnmatchedArgsParser { @@ -25,15 +23,6 @@ impl AttributeParser for OnUnmatchedArgsParser { let span = cx.attr_span; this.span = Some(span); - if !matches!(cx.target, Target::MacroDef) { - cx.emit_lint( - MISPLACED_DIAGNOSTIC_ATTRIBUTES, - DiagnosticOnUnmatchedArgsOnlyForMacros, - span, - ); - return; - } - let mode = Mode::DiagnosticOnUnmatchedArgs; let Some(items) = parse_list(cx, args, mode) else { return }; @@ -44,7 +33,8 @@ impl AttributeParser for OnUnmatchedArgsParser { }, )]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowListWarnRest(&[Allow(Target::MacroDef)]); fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option { if let Some(_span) = self.span { diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index 8ffd2281a582f..b22fe88a4de3d 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -279,45 +279,6 @@ pub(crate) struct UnknownCrateTypesSuggestion { pub snippet: Symbol, } -#[derive(Diagnostic)] -#[diag("`#[diagnostic::on_const]` can only be applied to non-const trait implementations")] -pub(crate) struct DiagnosticOnConstOnlyForTraitImpls { - #[label("not a trait implementation")] - pub target_span: Span, -} - -#[derive(Diagnostic)] -#[diag("`#[diagnostic::on_move]` can only be applied to enums, structs or unions")] -pub(crate) struct DiagnosticOnMoveOnlyForAdt; - -#[derive(Diagnostic)] -#[diag("`#[diagnostic::on_unimplemented]` can only be applied to trait definitions")] -pub(crate) struct DiagnosticOnUnimplementedOnlyForTraits; - -#[derive(Diagnostic)] -#[diag( - "`#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations" -)] -pub(crate) struct DiagnosticOnUnknownInvalidTarget { - #[label("not an import or module")] - pub target_span: Span, -} - -#[derive(Diagnostic)] -#[diag("`#[diagnostic::on_unmatched_args]` can only be applied to macro definitions")] -pub(crate) struct DiagnosticOnUnmatchedArgsOnlyForMacros; - -#[derive(Diagnostic)] -#[diag("`#[diagnostic::on_type_error]` can only be applied to enums, structs or unions")] -pub(crate) struct DiagnosticOnTypeErrorOnlyForAdt; - -#[derive(Diagnostic)] -#[diag("`#[diagnostic::do_not_recommend]` can only be placed on trait implementations")] -pub(crate) struct IncorrectDoNotRecommendLocation { - #[label("not a trait implementation")] - pub target_span: Span, -} - #[derive(Diagnostic)] #[diag("malformed `doc` attribute input")] #[warning( diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index ff62defea38f6..53eebfd377171 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -40,6 +40,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if trait_pred.polarity() != ty::PredicatePolarity::Positive { return CustomDiagnostic::default(); } + // This is needed as `on_unimplemented` is currently not allowed on trait aliases, + // but the "not allowed" is a warning, and this check ensures the attribute has no effect + if self.tcx.is_trait_alias(trait_pred.def_id()) { + return CustomDiagnostic::default(); + } let (filter_options, format_args) = self.on_unimplemented_components(trait_pred, obligation, long_ty_path); if let Some(command) = find_attr!(self.tcx, trait_pred.def_id(), OnUnimplemented {directive, ..} => directive.as_deref()).flatten() { diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.current.stderr index b43a67a656127..4a131b9c2a2a6 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.current.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.current.stderr @@ -1,85 +1,75 @@ -warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations +warning: `#[diagnostic::do_not_recommend]` attribute cannot be used on constants --> $DIR/incorrect-locations.rs:7:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | const CONST: () = (); - | --------------------- not a trait implementation | + = help: `#[diagnostic::do_not_recommend]` can only be applied to trait impl blocks = note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default -warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations +warning: `#[diagnostic::do_not_recommend]` attribute cannot be used on statics --> $DIR/incorrect-locations.rs:11:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | static STATIC: () = (); - | ----------------------- not a trait implementation + | + = help: `#[diagnostic::do_not_recommend]` can only be applied to trait impl blocks -warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations +warning: `#[diagnostic::do_not_recommend]` attribute cannot be used on type aliases --> $DIR/incorrect-locations.rs:15:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | type Type = (); - | --------------- not a trait implementation + | + = help: `#[diagnostic::do_not_recommend]` can only be applied to trait impl blocks -warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations +warning: `#[diagnostic::do_not_recommend]` attribute cannot be used on enums --> $DIR/incorrect-locations.rs:19:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | enum Enum {} - | ------------ not a trait implementation + | + = help: `#[diagnostic::do_not_recommend]` can only be applied to trait impl blocks -warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations +warning: `#[diagnostic::do_not_recommend]` attribute cannot be used on inherent impl blocks --> $DIR/incorrect-locations.rs:23:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | impl Enum {} - | ------------ not a trait implementation + | + = help: `#[diagnostic::do_not_recommend]` can only be applied to trait impl blocks -warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations +warning: `#[diagnostic::do_not_recommend]` attribute cannot be used on foreign modules --> $DIR/incorrect-locations.rs:27:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | extern "C" {} - | ------------- not a trait implementation + | + = help: `#[diagnostic::do_not_recommend]` can only be applied to trait impl blocks -warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations +warning: `#[diagnostic::do_not_recommend]` attribute cannot be used on functions --> $DIR/incorrect-locations.rs:31:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | fn fun() {} - | ----------- not a trait implementation + | + = help: `#[diagnostic::do_not_recommend]` can only be applied to trait impl blocks -warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations +warning: `#[diagnostic::do_not_recommend]` attribute cannot be used on structs --> $DIR/incorrect-locations.rs:35:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | struct Struct {} - | ---------------- not a trait implementation + | + = help: `#[diagnostic::do_not_recommend]` can only be applied to trait impl blocks -warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations +warning: `#[diagnostic::do_not_recommend]` attribute cannot be used on traits --> $DIR/incorrect-locations.rs:39:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | trait Trait {} - | -------------- not a trait implementation + | + = help: `#[diagnostic::do_not_recommend]` can only be applied to trait impl blocks warning: 9 warnings emitted diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.next.stderr index b43a67a656127..4a131b9c2a2a6 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.next.stderr @@ -1,85 +1,75 @@ -warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations +warning: `#[diagnostic::do_not_recommend]` attribute cannot be used on constants --> $DIR/incorrect-locations.rs:7:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | const CONST: () = (); - | --------------------- not a trait implementation | + = help: `#[diagnostic::do_not_recommend]` can only be applied to trait impl blocks = note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default -warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations +warning: `#[diagnostic::do_not_recommend]` attribute cannot be used on statics --> $DIR/incorrect-locations.rs:11:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | static STATIC: () = (); - | ----------------------- not a trait implementation + | + = help: `#[diagnostic::do_not_recommend]` can only be applied to trait impl blocks -warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations +warning: `#[diagnostic::do_not_recommend]` attribute cannot be used on type aliases --> $DIR/incorrect-locations.rs:15:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | type Type = (); - | --------------- not a trait implementation + | + = help: `#[diagnostic::do_not_recommend]` can only be applied to trait impl blocks -warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations +warning: `#[diagnostic::do_not_recommend]` attribute cannot be used on enums --> $DIR/incorrect-locations.rs:19:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | enum Enum {} - | ------------ not a trait implementation + | + = help: `#[diagnostic::do_not_recommend]` can only be applied to trait impl blocks -warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations +warning: `#[diagnostic::do_not_recommend]` attribute cannot be used on inherent impl blocks --> $DIR/incorrect-locations.rs:23:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | impl Enum {} - | ------------ not a trait implementation + | + = help: `#[diagnostic::do_not_recommend]` can only be applied to trait impl blocks -warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations +warning: `#[diagnostic::do_not_recommend]` attribute cannot be used on foreign modules --> $DIR/incorrect-locations.rs:27:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | extern "C" {} - | ------------- not a trait implementation + | + = help: `#[diagnostic::do_not_recommend]` can only be applied to trait impl blocks -warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations +warning: `#[diagnostic::do_not_recommend]` attribute cannot be used on functions --> $DIR/incorrect-locations.rs:31:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | fn fun() {} - | ----------- not a trait implementation + | + = help: `#[diagnostic::do_not_recommend]` can only be applied to trait impl blocks -warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations +warning: `#[diagnostic::do_not_recommend]` attribute cannot be used on structs --> $DIR/incorrect-locations.rs:35:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | struct Struct {} - | ---------------- not a trait implementation + | + = help: `#[diagnostic::do_not_recommend]` can only be applied to trait impl blocks -warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations +warning: `#[diagnostic::do_not_recommend]` attribute cannot be used on traits --> $DIR/incorrect-locations.rs:39:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | trait Trait {} - | -------------- not a trait implementation + | + = help: `#[diagnostic::do_not_recommend]` can only be applied to trait impl blocks warning: 9 warnings emitted diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs index e716457eaedf4..fc1ba5863b2d3 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs @@ -5,39 +5,39 @@ //@ reference: attributes.diagnostic.do_not_recommend.allowed-positions #[diagnostic::do_not_recommend] -//~^WARN `#[diagnostic::do_not_recommend]` can only be placed +//~^WARN cannot be used on const CONST: () = (); #[diagnostic::do_not_recommend] -//~^WARN `#[diagnostic::do_not_recommend]` can only be placed +//~^WARN cannot be used on static STATIC: () = (); #[diagnostic::do_not_recommend] -//~^WARN `#[diagnostic::do_not_recommend]` can only be placed +//~^WARN cannot be used on type Type = (); #[diagnostic::do_not_recommend] -//~^WARN `#[diagnostic::do_not_recommend]` can only be placed +//~^WARN cannot be used on enum Enum {} #[diagnostic::do_not_recommend] -//~^WARN `#[diagnostic::do_not_recommend]` can only be placed +//~^WARN cannot be used on impl Enum {} #[diagnostic::do_not_recommend] -//~^WARN `#[diagnostic::do_not_recommend]` can only be placed +//~^WARN cannot be used on extern "C" {} #[diagnostic::do_not_recommend] -//~^WARN `#[diagnostic::do_not_recommend]` can only be placed +//~^WARN cannot be used on fn fun() {} #[diagnostic::do_not_recommend] -//~^WARN `#[diagnostic::do_not_recommend]` can only be placed +//~^WARN cannot be used on struct Struct {} #[diagnostic::do_not_recommend] -//~^WARN `#[diagnostic::do_not_recommend]` can only be placed +//~^WARN cannot be used on trait Trait {} #[diagnostic::do_not_recommend] diff --git a/tests/ui/diagnostic_namespace/on_const/misplaced_attr.rs b/tests/ui/diagnostic_namespace/on_const/misplaced_attr.rs index 940d4623cba86..21b7dc32f6f8e 100644 --- a/tests/ui/diagnostic_namespace/on_const/misplaced_attr.rs +++ b/tests/ui/diagnostic_namespace/on_const/misplaced_attr.rs @@ -2,7 +2,7 @@ #![deny(misplaced_diagnostic_attributes)] #[diagnostic::on_const(message = "tadaa", note = "boing")] -//~^ ERROR: `#[diagnostic::on_const]` can only be applied to non-const trait implementations +//~^ ERROR: cannot be used on pub struct Foo; #[diagnostic::on_const(message = "tadaa", note = "boing")] @@ -14,7 +14,7 @@ const impl PartialEq for Foo { } #[diagnostic::on_const(message = "tadaa", note = "boing")] -//~^ ERROR: `#[diagnostic::on_const]` can only be applied to non-const trait implementations +//~^ ERROR: cannot be used on impl Foo { fn eq(&self, _other: &Foo) -> bool { true @@ -23,7 +23,7 @@ impl Foo { impl PartialOrd for Foo { #[diagnostic::on_const(message = "tadaa", note = "boing")] - //~^ ERROR: `#[diagnostic::on_const]` can only be applied to non-const trait implementations + //~^ ERROR: cannot be used on fn partial_cmp(&self, other: &Foo) -> Option { None } diff --git a/tests/ui/diagnostic_namespace/on_const/misplaced_attr.stderr b/tests/ui/diagnostic_namespace/on_const/misplaced_attr.stderr index b585451cdd859..89df20ccfc668 100644 --- a/tests/ui/diagnostic_namespace/on_const/misplaced_attr.stderr +++ b/tests/ui/diagnostic_namespace/on_const/misplaced_attr.stderr @@ -13,38 +13,29 @@ note: the lint level is defined here LL | #![deny(misplaced_diagnostic_attributes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `#[diagnostic::on_const]` can only be applied to non-const trait implementations +error: `#[diagnostic::on_const]` attribute cannot be used on structs --> $DIR/misplaced_attr.rs:4:1 | LL | #[diagnostic::on_const(message = "tadaa", note = "boing")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | pub struct Foo; - | --------------- not a trait implementation + | + = help: `#[diagnostic::on_const]` can only be applied to trait impl blocks -error: `#[diagnostic::on_const]` can only be applied to non-const trait implementations +error: `#[diagnostic::on_const]` attribute cannot be used on inherent impl blocks --> $DIR/misplaced_attr.rs:16:1 | -LL | #[diagnostic::on_const(message = "tadaa", note = "boing")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | / impl Foo { -LL | | fn eq(&self, _other: &Foo) -> bool { -LL | | true -LL | | } -LL | | } - | |_- not a trait implementation +LL | #[diagnostic::on_const(message = "tadaa", note = "boing")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[diagnostic::on_const]` can only be applied to trait impl blocks -error: `#[diagnostic::on_const]` can only be applied to non-const trait implementations +error: `#[diagnostic::on_const]` attribute cannot be used on trait methods in impl blocks --> $DIR/misplaced_attr.rs:25:5 | -LL | #[diagnostic::on_const(message = "tadaa", note = "boing")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | / fn partial_cmp(&self, other: &Foo) -> Option { -LL | | None -LL | | } - | |_____- not a trait implementation +LL | #[diagnostic::on_const(message = "tadaa", note = "boing")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[diagnostic::on_const]` can only be applied to trait impl blocks error: aborting due to 4 previous errors diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.rs index 33e78ea5fc1fe..8de8a29be77aa 100644 --- a/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.rs +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.rs @@ -7,7 +7,7 @@ struct Foo; #[diagnostic::on_move( -//~^WARN `#[diagnostic::on_move]` can only be applied to enums, structs or unions +//~^WARN `#[diagnostic::on_move]` attribute cannot be used on traits message = "Foo", label = "Bar", )] diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.stderr index 29c987fba48f1..821feabe4de98 100644 --- a/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.stderr +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.stderr @@ -1,4 +1,4 @@ -warning: `#[diagnostic::on_move]` can only be applied to enums, structs or unions +warning: `#[diagnostic::on_move]` attribute cannot be used on traits --> $DIR/report_warning_on_non_adt.rs:9:1 | LL | / #[diagnostic::on_move( @@ -8,6 +8,7 @@ LL | | label = "Bar", LL | | )] | |__^ | + = help: `#[diagnostic::on_move]` can only be applied to data types = note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default error[E0382]: Foo diff --git a/tests/ui/diagnostic_namespace/on_type_error/report_warning_on_non_adt.rs b/tests/ui/diagnostic_namespace/on_type_error/report_warning_on_non_adt.rs index 8bcb916dac365..038862ee820a5 100644 --- a/tests/ui/diagnostic_namespace/on_type_error/report_warning_on_non_adt.rs +++ b/tests/ui/diagnostic_namespace/on_type_error/report_warning_on_non_adt.rs @@ -1,30 +1,30 @@ #![feature(diagnostic_on_type_error)] #[diagnostic::on_type_error(note = "custom on_type_error note: not an ADT")] -//~^ WARN `#[diagnostic::on_type_error]` can only be applied to enums, structs or unions +//~^ WARN cannot be used on fn function() {} #[diagnostic::on_type_error(note = "custom on_type_error note: not an ADT")] -//~^ WARN `#[diagnostic::on_type_error]` can only be applied to enums, structs or unions +//~^ WARN cannot be used on static STATIC: i32 = 0; #[diagnostic::on_type_error(note = "custom on_type_error note: not an ADT")] -//~^ WARN `#[diagnostic::on_type_error]` can only be applied to enums, structs or unions +//~^ WARN cannot be used on mod module {} #[diagnostic::on_type_error(note = "custom on_type_error note: not an ADT")] -//~^ WARN `#[diagnostic::on_type_error]` can only be applied to enums, structs or unions +//~^ WARN cannot be used on trait Trait {} #[diagnostic::on_type_error(note = "custom on_type_error note: not an ADT")] -//~^ WARN `#[diagnostic::on_type_error]` can only be applied to enums, structs or unions +//~^ WARN cannot be used on type TypeAlias = i32; struct SomeStruct; impl SomeStruct { #[diagnostic::on_type_error(note = "custom on_type_error note: not an ADT")] - //~^ WARN `#[diagnostic::on_type_error]` can only be applied to enums, structs or unions + //~^ WARN cannot be used on fn method() {} } diff --git a/tests/ui/diagnostic_namespace/on_type_error/report_warning_on_non_adt.stderr b/tests/ui/diagnostic_namespace/on_type_error/report_warning_on_non_adt.stderr index b3eafa8244a5c..a79d396397042 100644 --- a/tests/ui/diagnostic_namespace/on_type_error/report_warning_on_non_adt.stderr +++ b/tests/ui/diagnostic_namespace/on_type_error/report_warning_on_non_adt.stderr @@ -1,40 +1,51 @@ -warning: `#[diagnostic::on_type_error]` can only be applied to enums, structs or unions +warning: `#[diagnostic::on_type_error]` attribute cannot be used on functions --> $DIR/report_warning_on_non_adt.rs:3:1 | LL | #[diagnostic::on_type_error(note = "custom on_type_error note: not an ADT")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: `#[diagnostic::on_type_error]` can only be applied to data types = note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default -warning: `#[diagnostic::on_type_error]` can only be applied to enums, structs or unions +warning: `#[diagnostic::on_type_error]` attribute cannot be used on statics --> $DIR/report_warning_on_non_adt.rs:7:1 | LL | #[diagnostic::on_type_error(note = "custom on_type_error note: not an ADT")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[diagnostic::on_type_error]` can only be applied to data types -warning: `#[diagnostic::on_type_error]` can only be applied to enums, structs or unions +warning: `#[diagnostic::on_type_error]` attribute cannot be used on modules --> $DIR/report_warning_on_non_adt.rs:11:1 | LL | #[diagnostic::on_type_error(note = "custom on_type_error note: not an ADT")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[diagnostic::on_type_error]` can only be applied to data types -warning: `#[diagnostic::on_type_error]` can only be applied to enums, structs or unions +warning: `#[diagnostic::on_type_error]` attribute cannot be used on traits --> $DIR/report_warning_on_non_adt.rs:15:1 | LL | #[diagnostic::on_type_error(note = "custom on_type_error note: not an ADT")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[diagnostic::on_type_error]` can only be applied to data types -warning: `#[diagnostic::on_type_error]` can only be applied to enums, structs or unions +warning: `#[diagnostic::on_type_error]` attribute cannot be used on type aliases --> $DIR/report_warning_on_non_adt.rs:19:1 | LL | #[diagnostic::on_type_error(note = "custom on_type_error note: not an ADT")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[diagnostic::on_type_error]` can only be applied to data types -warning: `#[diagnostic::on_type_error]` can only be applied to enums, structs or unions +warning: `#[diagnostic::on_type_error]` attribute cannot be used on inherent methods --> $DIR/report_warning_on_non_adt.rs:26:5 | LL | #[diagnostic::on_type_error(note = "custom on_type_error note: not an ADT")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[diagnostic::on_type_error]` can only be applied to data types error[E0308]: mismatched types --> $DIR/report_warning_on_non_adt.rs:38:25 diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs index aa4e14fb04f2f..03eddef2a5400 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs @@ -20,7 +20,7 @@ trait Foo {} trait Bar {} #[diagnostic::on_unimplemented(message = "Not allowed to apply it on a impl")] -//~^WARN #[diagnostic::on_unimplemented]` can only be applied to trait definitions +//~^WARN cannot be used on impl Bar for i32 {} // cannot use special rustc_on_unimplement symbols diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr index 7ab7f25ee6964..4059bcaec7573 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr @@ -152,12 +152,13 @@ LL | #[diagnostic::on_unimplemented = "Message"] | = help: only `message`, `note` and `label` are allowed as options -warning: `#[diagnostic::on_unimplemented]` can only be applied to trait definitions +warning: `#[diagnostic::on_unimplemented]` attribute cannot be used on trait impl blocks --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:22:1 | LL | #[diagnostic::on_unimplemented(message = "Not allowed to apply it on a impl")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: `#[diagnostic::on_unimplemented]` can only be applied to traits = note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default warning: format specifiers are not permitted in diagnostic attributes diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs index 14763d21a2bea..dd78f7f5a9f35 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs @@ -5,7 +5,7 @@ trait Foo {} #[diagnostic::on_unimplemented(message = "Baz")] -//~^WARN `#[diagnostic::on_unimplemented]` can only be applied to trait definitions +//~^WARN cannot be used on struct Bar {} #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")] diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr index d5c7f25efbc29..739bd598e9c69 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr @@ -16,12 +16,13 @@ LL | #[diagnostic::on_unimplemented(unsupported = "foo")] = help: only `message`, `note` and `label` are allowed as options = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default -warning: `#[diagnostic::on_unimplemented]` can only be applied to trait definitions +warning: `#[diagnostic::on_unimplemented]` attribute cannot be used on structs --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:7:1 | LL | #[diagnostic::on_unimplemented(message = "Baz")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: `#[diagnostic::on_unimplemented]` can only be applied to traits = note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default warning: malformed `diagnostic::on_unimplemented` attribute diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/on_impl_trait.rs b/tests/ui/diagnostic_namespace/on_unimplemented/on_impl_trait.rs index 1ffa604b2bc06..658cc53246c13 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/on_impl_trait.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/on_impl_trait.rs @@ -6,7 +6,7 @@ trait Test {} #[diagnostic::on_unimplemented(message = "blah", label = "blah", note = "blah")] -//~^ WARN `#[diagnostic::on_unimplemented]` can only be applied to trait definitions +//~^ WARN cannot be used on trait Alias = Test; // Use trait alias as bound on type parameter. diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/on_impl_trait.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/on_impl_trait.stderr index e9d0c6e5daf55..a9a38da242268 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/on_impl_trait.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/on_impl_trait.stderr @@ -1,9 +1,10 @@ -warning: `#[diagnostic::on_unimplemented]` can only be applied to trait definitions +warning: `#[diagnostic::on_unimplemented]` attribute cannot be used on trait aliases --> $DIR/on_impl_trait.rs:8:1 | LL | #[diagnostic::on_unimplemented(message = "blah", label = "blah", note = "blah")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: `#[diagnostic::on_unimplemented]` can only be applied to traits = note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default error[E0277]: the trait bound `{integer}: Alias` is not satisfied diff --git a/tests/ui/diagnostic_namespace/on_unknown/incorrect_locations.rs b/tests/ui/diagnostic_namespace/on_unknown/incorrect_locations.rs index ec32bf5ba54f7..f82e52f2f6a3e 100644 --- a/tests/ui/diagnostic_namespace/on_unknown/incorrect_locations.rs +++ b/tests/ui/diagnostic_namespace/on_unknown/incorrect_locations.rs @@ -3,47 +3,47 @@ #![feature(diagnostic_on_unknown)] #[diagnostic::on_unknown(message = "foo")] -//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations +//~^WARN cannot be used on extern crate std as other_std; #[diagnostic::on_unknown(message = "foo")] -//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations +//~^WARN cannot be used on const CONST: () = (); #[diagnostic::on_unknown(message = "foo")] -//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations +//~^WARN cannot be used on static STATIC: () = (); #[diagnostic::on_unknown(message = "foo")] -//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations +//~^WARN cannot be used on type Type = (); #[diagnostic::on_unknown(message = "foo")] -//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations +//~^WARN cannot be used on enum Enum {} #[diagnostic::on_unknown(message = "foo")] -//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations +//~^WARN cannot be used on impl Enum {} #[diagnostic::on_unknown(message = "foo")] -//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations +//~^WARN cannot be used on extern "C" {} #[diagnostic::on_unknown(message = "foo")] -//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations +//~^WARN cannot be used on fn fun() {} #[diagnostic::on_unknown(message = "foo")] -//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations +//~^WARN cannot be used on struct Struct {} #[diagnostic::on_unknown(message = "foo")] -//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations +//~^WARN cannot be used on trait Trait {} #[diagnostic::on_unknown(message = "foo")] -//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations +//~^WARN cannot be used on impl Trait for i32 {} #[diagnostic::on_unknown(message = "foo")] diff --git a/tests/ui/diagnostic_namespace/on_unknown/incorrect_locations.stderr b/tests/ui/diagnostic_namespace/on_unknown/incorrect_locations.stderr index c812e99260660..81508568d0e0e 100644 --- a/tests/ui/diagnostic_namespace/on_unknown/incorrect_locations.stderr +++ b/tests/ui/diagnostic_namespace/on_unknown/incorrect_locations.stderr @@ -1,103 +1,91 @@ -warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations +warning: `#[diagnostic::on_unknown]` attribute cannot be used on extern crates --> $DIR/incorrect_locations.rs:5:1 | LL | #[diagnostic::on_unknown(message = "foo")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | extern crate std as other_std; - | ------------------------------ not an import or module | + = help: `#[diagnostic::on_unknown]` can be applied to crates, modules, and use statements = note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default -warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations +warning: `#[diagnostic::on_unknown]` attribute cannot be used on constants --> $DIR/incorrect_locations.rs:9:1 | LL | #[diagnostic::on_unknown(message = "foo")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | const CONST: () = (); - | --------------------- not an import or module + | + = help: `#[diagnostic::on_unknown]` can be applied to crates, modules, and use statements -warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations +warning: `#[diagnostic::on_unknown]` attribute cannot be used on statics --> $DIR/incorrect_locations.rs:13:1 | LL | #[diagnostic::on_unknown(message = "foo")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | static STATIC: () = (); - | ----------------------- not an import or module + | + = help: `#[diagnostic::on_unknown]` can be applied to crates, modules, and use statements -warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations +warning: `#[diagnostic::on_unknown]` attribute cannot be used on type aliases --> $DIR/incorrect_locations.rs:17:1 | LL | #[diagnostic::on_unknown(message = "foo")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | type Type = (); - | --------------- not an import or module + | + = help: `#[diagnostic::on_unknown]` can be applied to crates, modules, and use statements -warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations +warning: `#[diagnostic::on_unknown]` attribute cannot be used on enums --> $DIR/incorrect_locations.rs:21:1 | LL | #[diagnostic::on_unknown(message = "foo")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | enum Enum {} - | ------------ not an import or module + | + = help: `#[diagnostic::on_unknown]` can be applied to crates, modules, and use statements -warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations +warning: `#[diagnostic::on_unknown]` attribute cannot be used on inherent impl blocks --> $DIR/incorrect_locations.rs:25:1 | LL | #[diagnostic::on_unknown(message = "foo")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | impl Enum {} - | ------------ not an import or module + | + = help: `#[diagnostic::on_unknown]` can be applied to crates, modules, and use statements -warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations +warning: `#[diagnostic::on_unknown]` attribute cannot be used on foreign modules --> $DIR/incorrect_locations.rs:29:1 | LL | #[diagnostic::on_unknown(message = "foo")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | extern "C" {} - | ------------- not an import or module + | + = help: `#[diagnostic::on_unknown]` can be applied to crates, modules, and use statements -warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations +warning: `#[diagnostic::on_unknown]` attribute cannot be used on functions --> $DIR/incorrect_locations.rs:33:1 | LL | #[diagnostic::on_unknown(message = "foo")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | fn fun() {} - | ----------- not an import or module + | + = help: `#[diagnostic::on_unknown]` can be applied to crates, modules, and use statements -warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations +warning: `#[diagnostic::on_unknown]` attribute cannot be used on structs --> $DIR/incorrect_locations.rs:37:1 | LL | #[diagnostic::on_unknown(message = "foo")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | struct Struct {} - | ---------------- not an import or module + | + = help: `#[diagnostic::on_unknown]` can be applied to crates, modules, and use statements -warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations +warning: `#[diagnostic::on_unknown]` attribute cannot be used on traits --> $DIR/incorrect_locations.rs:41:1 | LL | #[diagnostic::on_unknown(message = "foo")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | trait Trait {} - | -------------- not an import or module + | + = help: `#[diagnostic::on_unknown]` can be applied to crates, modules, and use statements -warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations +warning: `#[diagnostic::on_unknown]` attribute cannot be used on trait impl blocks --> $DIR/incorrect_locations.rs:45:1 | LL | #[diagnostic::on_unknown(message = "foo")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | impl Trait for i32 {} - | --------------------- not an import or module + | + = help: `#[diagnostic::on_unknown]` can be applied to crates, modules, and use statements warning: 11 warnings emitted diff --git a/tests/ui/diagnostic_namespace/on_unknown/incorrect_unstable_positions.rs b/tests/ui/diagnostic_namespace/on_unknown/incorrect_unstable_positions.rs index 7795d346f22b3..0191c66dd7e80 100644 --- a/tests/ui/diagnostic_namespace/on_unknown/incorrect_unstable_positions.rs +++ b/tests/ui/diagnostic_namespace/on_unknown/incorrect_unstable_positions.rs @@ -6,6 +6,6 @@ fn main() { #[diagnostic::on_unknown(message = "anonymous block")] - //~^ WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations + //~^ WARN cannot be used on {} } diff --git a/tests/ui/diagnostic_namespace/on_unknown/incorrect_unstable_positions.stderr b/tests/ui/diagnostic_namespace/on_unknown/incorrect_unstable_positions.stderr index daa6688abf2d5..dc02dc4272487 100644 --- a/tests/ui/diagnostic_namespace/on_unknown/incorrect_unstable_positions.stderr +++ b/tests/ui/diagnostic_namespace/on_unknown/incorrect_unstable_positions.stderr @@ -1,12 +1,10 @@ -warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements and module declarations +warning: `#[diagnostic::on_unknown]` attribute cannot be used on expressions --> $DIR/incorrect_unstable_positions.rs:8:5 | LL | #[diagnostic::on_unknown(message = "anonymous block")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | {} - | -- not an import or module | + = help: `#[diagnostic::on_unknown]` can be applied to crates, modules, and use statements = note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default warning: 1 warning emitted diff --git a/tests/ui/diagnostic_namespace/on_unmatched_args/report_warning_on_non_macro.rs b/tests/ui/diagnostic_namespace/on_unmatched_args/report_warning_on_non_macro.rs index 28b6e0cbe3be7..537e7c292c99a 100644 --- a/tests/ui/diagnostic_namespace/on_unmatched_args/report_warning_on_non_macro.rs +++ b/tests/ui/diagnostic_namespace/on_unmatched_args/report_warning_on_non_macro.rs @@ -2,7 +2,7 @@ #![feature(diagnostic_on_unmatched_args)] #[diagnostic::on_unmatched_args(message = "not allowed here")] -//~^ WARN `#[diagnostic::on_unmatched_args]` can only be applied to macro definitions +//~^ WARN cannot be used on struct Foo; fn main() { diff --git a/tests/ui/diagnostic_namespace/on_unmatched_args/report_warning_on_non_macro.stderr b/tests/ui/diagnostic_namespace/on_unmatched_args/report_warning_on_non_macro.stderr index 10c6fd9ce8bea..bd94410ff72f7 100644 --- a/tests/ui/diagnostic_namespace/on_unmatched_args/report_warning_on_non_macro.stderr +++ b/tests/ui/diagnostic_namespace/on_unmatched_args/report_warning_on_non_macro.stderr @@ -1,9 +1,10 @@ -warning: `#[diagnostic::on_unmatched_args]` can only be applied to macro definitions +warning: `#[diagnostic::on_unmatched_args]` attribute cannot be used on structs --> $DIR/report_warning_on_non_macro.rs:4:1 | LL | #[diagnostic::on_unmatched_args(message = "not allowed here")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: `#[diagnostic::on_unmatched_args]` can only be applied to macro defs = note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default warning: 1 warning emitted From 48e7c2859b1cc3fb1205aaa86e73ff7da21bf7e6 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 12 Jun 2026 20:56:01 +0200 Subject: [PATCH 08/11] rebuild LLVM when `bootstrap.toml` config changes --- src/bootstrap/src/core/build_steps/llvm.rs | 10 +-- src/bootstrap/src/core/builder/mod.rs | 10 +++ src/bootstrap/src/core/config/config.rs | 8 +- src/bootstrap/src/core/config/toml/llvm.rs | 87 ++++++++++++++++++++++ 4 files changed, 109 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 087a395a067f0..9891f54907c7c 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -169,7 +169,7 @@ pub fn prebuilt_llvm_config( generate_smart_stamp_hash( builder, &builder.config.src.join("src/llvm-project"), - builder.in_tree_llvm_info.sha().unwrap_or_default(), + &builder.llvm_cache_key(), ) }); @@ -999,7 +999,7 @@ impl Step for OmpOffload { generate_smart_stamp_hash( builder, &builder.config.src.join("src/llvm-project/offload"), - builder.in_tree_llvm_info.sha().unwrap_or_default(), + &builder.llvm_cache_key(), ) }); let stamp = BuildStamp::new(&out_dir).with_prefix("offload").add_stamp(smart_stamp_hash); @@ -1166,8 +1166,8 @@ impl Step for Enzyme { // Enzyme links against LLVM. If we update the LLVM submodule libLLVM might get a new // version number, in which case Enzyme will now fail to find LLVM. By including the LLVM // hash into the Enzyme hash we force a rebuild of Enzyme when updating LLVM. - let enzyme_hash_input = builder.in_tree_llvm_info.sha().unwrap_or_default().to_owned() - + builder.enzyme_info.sha().unwrap_or_default(); + let enzyme_hash_input = + builder.llvm_cache_key() + builder.enzyme_info.sha().unwrap_or_default(); static STAMP_HASH_MEMO: OnceLock = OnceLock::new(); let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| { @@ -1430,7 +1430,7 @@ impl Step for Sanitizers { generate_smart_stamp_hash( builder, &builder.config.src.join("src/llvm-project/compiler-rt"), - builder.in_tree_llvm_info.sha().unwrap_or_default(), + &builder.llvm_cache_key(), ) }); diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 2e640220efd8e..166ab171631a6 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -1686,6 +1686,16 @@ Alternatively, you can set `build.local-rebuild=true` and use a stage0 compiler pub fn exec_ctx(&self) -> &ExecutionContext { &self.config.exec_ctx } + + /// When to rebuild LLVM. Currently includes the LLVM commit hash and the configuration from + /// bootstrap.toml. + pub(crate) fn llvm_cache_key(&self) -> String { + format!( + "sha={sha}\nkey={key}", + sha = self.in_tree_llvm_info.sha().unwrap_or_default(), + key = self.config.llvm_cache_key, + ) + } } /// Return qualified step name, e.g. `compile::Rustc`. diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 5a9c7264c006f..0297907057ef9 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -156,6 +156,9 @@ pub struct Config { pub backtrace_on_ice: bool, // llvm codegen options + /// Key used to decide when to rebuild LLVM. + pub llvm_cache_key: String, + pub llvm_assertions: bool, pub llvm_tests: bool, pub llvm_enzyme: bool, @@ -595,6 +598,8 @@ impl Config { rustflags: rust_rustflags, } = toml.rust.unwrap_or_default(); + let llvm = toml.llvm.unwrap_or_default(); + let llvm_cache_key = llvm.cache_key(); let Llvm { optimize: llvm_optimize, thin_lto: llvm_thin_lto, @@ -625,7 +630,7 @@ impl Config { enable_warnings: llvm_enable_warnings, download_ci_llvm: llvm_download_ci_llvm, build_config: llvm_build_config, - } = toml.llvm.unwrap_or_default(); + } = llvm; let Dist { sign_folder: dist_sign_folder, @@ -1401,6 +1406,7 @@ impl Config { llvm_assertions, llvm_bitcode_linker_enabled: rust_llvm_bitcode_linker.unwrap_or(false), llvm_build_config: llvm_build_config.clone().unwrap_or(Default::default()), + llvm_cache_key, llvm_cflags, llvm_clang: llvm_clang.unwrap_or(false), llvm_clang_cl, diff --git a/src/bootstrap/src/core/config/toml/llvm.rs b/src/bootstrap/src/core/config/toml/llvm.rs index 5f08884e4ef71..e54c17c63aaae 100644 --- a/src/bootstrap/src/core/config/toml/llvm.rs +++ b/src/bootstrap/src/core/config/toml/llvm.rs @@ -43,6 +43,93 @@ define_config! { } } +impl Llvm { + /// A key that is used to determine whether LLVM should be rebuilt. + pub(crate) fn cache_key(&self) -> String { + let helper = || { + let mut key = String::with_capacity(512); + + let Self { + optimize, + thin_lto, + release_debuginfo, + assertions, + tests, + enzyme, + plugins, + static_libstdcpp, + libzstd, + ninja, + targets, + experimental_targets, + link_jobs: _, + link_shared, + version_suffix, + clang_cl, + cflags, + cxxflags, + ldflags, + use_libcxx, + use_linker, + allow_old_toolchain, + offload, + polly, + offload_clang_dir, + clang, + enable_warnings: _, + build_config, + download_ci_llvm: _, + } = self; + + use std::fmt::Write; + write!(key, "{:?}", optimize)?; + write!(key, "{:?}", thin_lto)?; + write!(key, "{:?}", release_debuginfo)?; + write!(key, "{:?}", assertions)?; + write!(key, "{:?}", tests)?; + write!(key, "{:?}", enzyme)?; + write!(key, "{:?}", plugins)?; + write!(key, "{:?}", static_libstdcpp)?; + write!(key, "{:?}", libzstd)?; + write!(key, "{:?}", ninja)?; + write!(key, "{:?}", targets)?; + write!(key, "{:?}", experimental_targets)?; + write!(key, "{:?}", link_shared)?; + write!(key, "{:?}", version_suffix)?; + write!(key, "{:?}", clang_cl)?; + write!(key, "{:?}", cflags)?; + write!(key, "{:?}", cxxflags)?; + write!(key, "{:?}", ldflags)?; + write!(key, "{:?}", use_libcxx)?; + write!(key, "{:?}", use_linker)?; + write!(key, "{:?}", allow_old_toolchain)?; + write!(key, "{:?}", offload)?; + write!(key, "{:?}", polly)?; + write!(key, "{:?}", offload_clang_dir)?; + write!(key, "{:?}", clang)?; + + match build_config { + None => { + write!(key, "None")?; + } + Some(c) => { + let mut build_config = c.iter().collect::>(); + build_config.sort(); + + for (k, v) in build_config { + write!(key, "{}: {}", k, v)?; + } + } + } + + Ok::<_, std::fmt::Error>(key) + }; + + // write! to a String always succeeds unless OOM. + helper().unwrap() + } +} + /// Compares the current `Llvm` options against those in the CI LLVM builder and detects any incompatible options. /// It does this by destructuring the `Llvm` instance to make sure every `Llvm` field is covered and not missing. #[cfg(not(test))] From 9b6ab668bbd8341ef07f7c57397909146e4b09b4 Mon Sep 17 00:00:00 2001 From: xonx <119700621+xonx4l@users.noreply.github.com> Date: Sat, 9 May 2026 10:17:25 +0000 Subject: [PATCH 09/11] port-intrinsic-test --- src/bootstrap/src/core/build_steps/test.rs | 134 ++++++++++++++++++ src/bootstrap/src/core/build_steps/tool.rs | 1 + .../cli_paths/snapshots/x_test_library.snap | 3 + src/bootstrap/src/core/builder/mod.rs | 1 + .../docker/host-x86_64/x86_64-gnu/Dockerfile | 9 +- 5 files changed, 147 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 0dd6cd0d6fc3b..f7f708902c095 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -992,6 +992,140 @@ impl Step for StdarchVerify { } } +/// Runs stdarch's intrinsic-test binary crate to verify that Rust's `core::arch` +/// SIMD intrinsics produce the same results as their C counterparts. +/// +/// First runs the `intrinsic-test` binary, which generates C wrapper programs +/// and a Rust Cargo workspace. Then runs `cargo test` on that workspace +/// which compiles both versions and compares their outputs on random inputs. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct IntrinsicTest { + host: TargetSelection, +} + +impl Step for IntrinsicTest { + type Output = (); + const IS_HOST: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("library/stdarch/crates/intrinsic-test") + } + + fn make_run(run: RunConfig<'_>) { + let target = run.target; + if !target.contains("aarch64-unknown-linux") && !target.contains("x86_64-unknown-linux") { + return; + } + run.builder.ensure(IntrinsicTest { host: target }); + } + + fn run(self, builder: &Builder<'_>) { + let host = self.host; + + let (input_file, skip_file, cflags, sde_runner) = if host.contains("x86_64-unknown-linux") { + let cpuid_def = + builder.src.join("library/stdarch/ci/docker/x86_64-unknown-linux-gnu/cpuid.def"); + let sde_runner = format!( + "/intel-sde/sde64 -cpuid-in {} -rtm-mode full -tsx --", + cpuid_def.display() + ); + ( + builder.src.join("library/stdarch/intrinsics_data/x86-intel.xml"), + [ + builder + .src + .join("library/stdarch/crates/intrinsic-test/missing_x86_common.txt"), + builder.src.join("library/stdarch/crates/intrinsic-test/missing_x86_gcc.txt"), + ], + "-I/usr/include/x86_64-linux-gnu/", + Some(sde_runner), + ) + } else if host.contains("aarch64-unknown-linux") { + ( + builder.src.join("library/stdarch/intrinsics_data/arm_intrinsics.json"), + [ + builder + .src + .join("library/stdarch/crates/intrinsic-test/missing_aarch64_common.txt"), + builder + .src + .join("library/stdarch/crates/intrinsic-test/missing_aarch64_gcc.txt"), + ], + "-I/usr/aarch64-linux-gnu/include/", + None, + ) + } else { + panic!("intrinsic-test only supports aarch64/x86_64 Linux, got {host}"); + }; + + let out_dir = builder.out.join(host).join("intrinsic-test"); + t!(fs::create_dir_all(&out_dir)); + + let crates_link = out_dir.join("crates"); + if !crates_link.exists() { + t!( + helpers::symlink_dir( + &builder.config, + &builder.src.join("library/stdarch/crates"), + &crates_link + ), + format!("failed to symlink stdarch crates into {}", crates_link.display()) + ); + } + + let mut cmd = builder.tool_cmd(Tool::IntrinsicTest); + cmd.current_dir(&out_dir); + cmd.arg(&input_file); + cmd.arg("--target").arg(&*host.triple); + for skip in &skip_file { + cmd.arg("--skip").arg(skip); + } + cmd.arg("--sample-percentage").arg("10"); + cmd.arg("--cc-arg-style").arg("gcc"); + cmd.env("CC", builder.cc(host)); + cmd.env("CFLAGS", cflags); + // intrinsic-test shells out to `cargo` and `rustfmt` make bootstrap's + // managed binaries findable by prepending their dirs to PATH. + let rustfmt_path = builder.config.initial_rustfmt.clone().unwrap_or_else(|| { + eprintln!("intrinsic-test: rustfmt is required but not available on this channel"); + crate::exit!(1); + }); + + let mut path_dirs: Vec = Vec::new(); + if let Some(cargo_dir) = builder.initial_cargo.parent() { + path_dirs.push(cargo_dir.to_path_buf()); + } + if let Some(rustfmt_dir) = rustfmt_path.parent() { + path_dirs.push(rustfmt_dir.to_path_buf()); + } + let old_path = env::var_os("PATH").unwrap_or_default(); + let new_path = env::join_paths(path_dirs.into_iter().chain(env::split_paths(&old_path))) + .expect("could not build PATH for intrinsic-test"); + cmd.env("PATH", new_path); + cmd.run(builder); + + let tested_compiler = builder.compiler(builder.top_stage, host); + builder.std(tested_compiler, host); + let rustc = builder.rustc(tested_compiler); + + let manifest = out_dir.join("rust_programs/Cargo.toml"); + let mut cargo = command(&builder.initial_cargo); + cargo.arg("test"); + cargo.arg("--tests"); + cargo.arg("--manifest-path").arg(&manifest); + cargo.arg("--target").arg(&*host.triple); + cargo.arg("--profile").arg("release"); + cargo.env("CC", builder.cc(host)); + cargo.env("CFLAGS", cflags); + cargo.env("RUSTC", rustc); + cargo.env("RUSTC_BOOTSTRAP", "1"); + if let Some(runner) = sde_runner { + cargo.env("CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER", runner); + } + cargo.run(builder); + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Clippy { compilers: RustcPrivateCompilers, diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index a75d5e4db8998..7b62e31ab4084 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -508,6 +508,7 @@ bootstrap_tool!( FeaturesStatusDump, "src/tools/features-status-dump", "features-status-dump"; OptimizedDist, "src/tools/opt-dist", "opt-dist", submodules = &["src/tools/rustc-perf"]; RunMakeSupport, "src/tools/run-make-support", "run_make_support", artifact_kind = ToolArtifactKind::Library; + IntrinsicTest, "library/stdarch/crates/intrinsic-test", "intrinsic-test"; ); /// These are the submodules that are required for rustbook to work due to diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_library.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_library.snap index f97bb839c1e73..ba1f6b3c940c3 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_library.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_library.snap @@ -21,3 +21,6 @@ expression: test library [Test] test::StdarchVerify targets: [x86_64-unknown-linux-gnu] - Set({test::library/stdarch/crates/stdarch-verify}) +[Test] test::IntrinsicTest + targets: [x86_64-unknown-linux-gnu] + - Set({test::library/stdarch/crates/intrinsic-test}) diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 2e640220efd8e..048fcc5c80145 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -911,6 +911,7 @@ impl<'a> Builder<'a> { test::Clippy, test::CompiletestTest, test::StdarchVerify, + test::IntrinsicTest, test::CrateRunMakeSupport, test::CrateBuildHelper, test::RustdocJSStd, diff --git a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile index 2c9788a0607c3..207dbed681faa 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile @@ -21,6 +21,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libzstd-dev \ && rm -rf /var/lib/apt/lists/* +# Install Intel SDE for AVX-512 emulation +RUN curl -L http://ci-mirrors.rust-lang.org/sde-external-10.8.0-2026-03-15-lin.tar.xz -o /tmp/sde.tar.xz \ + && mkdir -p /intel-sde \ + && tar -xJf /tmp/sde.tar.xz --strip-components=1 -C /intel-sde \ + && rm /tmp/sde.tar.xz + COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh @@ -29,4 +35,5 @@ ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ --enable-profiler \ --enable-compiler-docs \ --set llvm.libzstd=true" -ENV SCRIPT="python3 ../x.py --stage 2 test" +ENV SCRIPT="python3 ../x.py --stage 2 test && \ + python3 ../x.py --stage 2 test library/stdarch/crates/intrinsic-test" \ No newline at end of file From 5b5e4082242f20adbf6ac11f1da9a9b4c18707fb Mon Sep 17 00:00:00 2001 From: Hanna Kruppe Date: Sun, 21 Jun 2026 15:07:54 +0200 Subject: [PATCH 10/11] add test case for miscompilation --- ...comparison.SimplifyComparisonIntegral.diff | 28 +++++++++++++++++++ tests/mir-opt/if_condition_int.rs | 27 ++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 tests/mir-opt/if_condition_int.dont_remove_moved_comparison.SimplifyComparisonIntegral.diff diff --git a/tests/mir-opt/if_condition_int.dont_remove_moved_comparison.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.dont_remove_moved_comparison.SimplifyComparisonIntegral.diff new file mode 100644 index 0000000000000..b3d38516dec0e --- /dev/null +++ b/tests/mir-opt/if_condition_int.dont_remove_moved_comparison.SimplifyComparisonIntegral.diff @@ -0,0 +1,28 @@ +- // MIR for `dont_remove_moved_comparison` before SimplifyComparisonIntegral ++ // MIR for `dont_remove_moved_comparison` after SimplifyComparisonIntegral + + fn dont_remove_moved_comparison(_1: i8) -> i32 { + let mut _0: i32; + let mut _2: bool; + let mut _3: i32; + let mut _4: i32; + + bb0: { +- _2 = Eq(copy _1, const 17_i8); ++ nop; + _3 = copy _2 as i32 (IntToInt); +- switchInt(move _2) -> [1: bb1, otherwise: bb2]; ++ switchInt(copy _1) -> [17: bb1, otherwise: bb2]; + } + + bb1: { + _0 = copy _3; + return; + } + + bb2: { + _0 = Add(copy _3, const 1_i32); + return; + } + } + diff --git a/tests/mir-opt/if_condition_int.rs b/tests/mir-opt/if_condition_int.rs index 5e0961da3ccea..6950faf502005 100644 --- a/tests/mir-opt/if_condition_int.rs +++ b/tests/mir-opt/if_condition_int.rs @@ -103,6 +103,33 @@ fn dont_remove_comparison(a: i8) -> i32 { } } +// EMIT_MIR if_condition_int.dont_remove_moved_comparison.SimplifyComparisonIntegral.diff +#[custom_mir(dialect = "runtime")] +fn dont_remove_moved_comparison(a: i8) -> i32 { + mir! { + let b: bool; + let c: i32; + let d: i32; + { + b = a == 17; + c = b as i32; + match Move(b) { + true => bb1, + _ => bb2, + } + + } + bb1 = { + RET = c; + Return() + } + bb2 = { + RET = c + 1; + Return() + } + } +} + // EMIT_MIR if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff // test that we do not optimize on floats fn dont_opt_floats(a: f32) -> i32 { From a642d9b63c6236074005c10d52df5aef691b4815 Mon Sep 17 00:00:00 2001 From: Hanna Kruppe Date: Sun, 21 Jun 2026 15:22:37 +0200 Subject: [PATCH 11/11] don't try to remove assignments in SimplifyComparisonIntegral --- .../src/simplify_comparison_integral.rs | 46 ++++++++----------- ...comparison.SimplifyComparisonIntegral.diff | 3 +- ...t.opt_char.SimplifyComparisonIntegral.diff | 3 +- ...int.opt_i8.SimplifyComparisonIntegral.diff | 3 +- ...ltiple_ifs.SimplifyComparisonIntegral.diff | 6 +-- ...t_negative.SimplifyComparisonIntegral.diff | 3 +- ...nt.opt_u32.SimplifyComparisonIntegral.diff | 3 +- tests/mir-opt/if_condition_int.rs | 11 ++++- 8 files changed, 35 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs index 74e5fc6f34579..0076e3ed4167c 100644 --- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs +++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs @@ -76,30 +76,24 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral { _ => unreachable!(), } - // delete comparison statement if it the value being switched on was moved, which means - // it can not be used later on - if opt.can_remove_bin_op_stmt { - bb.statements[opt.bin_op_stmt_idx].make_nop(true); - } else { - // if the integer being compared to a const integral is being moved into the - // comparison, e.g `_2 = Eq(move _3, const 'x');` - // we want to avoid making a double move later on in the switchInt on _3. - // So to avoid `switchInt(move _3) -> ['x': bb2, otherwise: bb1];`, - // we convert the move in the comparison statement to a copy. - - // unwrap is safe as we know this statement is an assign - let (_, rhs) = bb.statements[opt.bin_op_stmt_idx].kind.as_assign_mut().unwrap(); - - use Operand::*; - match rhs { - Rvalue::BinaryOp(_, (left @ Move(_), Constant(_))) => { - *left = Copy(opt.to_switch_on); - } - Rvalue::BinaryOp(_, (Constant(_), right @ Move(_))) => { - *right = Copy(opt.to_switch_on); - } - _ => (), + // if the integer being compared to a const integral is being moved into the + // comparison, e.g `_2 = Eq(move _3, const 'x');` + // we want to avoid making a double move later on in the switchInt on _3. + // So to avoid `switchInt(move _3) -> ['x': bb2, otherwise: bb1];`, + // we convert the move in the comparison statement to a copy. + + // unwrap is safe as we know this statement is an assign + let (_, rhs) = bb.statements[opt.bin_op_stmt_idx].kind.as_assign_mut().unwrap(); + + use Operand::*; + match rhs { + Rvalue::BinaryOp(_, (left @ Move(_), Constant(_))) => { + *left = Copy(opt.to_switch_on); + } + Rvalue::BinaryOp(_, (Constant(_), right @ Move(_))) => { + *right = Copy(opt.to_switch_on); } + _ => (), } let terminator = bb.terminator(); @@ -184,7 +178,6 @@ impl<'tcx> OptimizationFinder<'_, 'tcx> { Some(OptimizationInfo { bin_op_stmt_idx: stmt_idx, bb_idx, - can_remove_bin_op_stmt: discr.is_move(), to_switch_on, branch_value_scalar, branch_value_ty, @@ -235,11 +228,8 @@ fn find_branch_value_info<'tcx>( struct OptimizationInfo<'tcx> { /// Basic block to apply the optimization bb_idx: BasicBlock, - /// Statement index of Eq/Ne assignment that can be removed. None if the assignment can not be - /// removed - i.e the statement is used later on + /// Statement index of Eq/Ne assignment bin_op_stmt_idx: usize, - /// Can remove Eq/Ne assignment - can_remove_bin_op_stmt: bool, /// Place that needs to be switched on. This place is of type integral to_switch_on: Place<'tcx>, /// Constant to use in switch target value diff --git a/tests/mir-opt/if_condition_int.dont_remove_moved_comparison.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.dont_remove_moved_comparison.SimplifyComparisonIntegral.diff index b3d38516dec0e..e59e2fde016d2 100644 --- a/tests/mir-opt/if_condition_int.dont_remove_moved_comparison.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/if_condition_int.dont_remove_moved_comparison.SimplifyComparisonIntegral.diff @@ -8,8 +8,7 @@ let mut _4: i32; bb0: { -- _2 = Eq(copy _1, const 17_i8); -+ nop; + _2 = Eq(copy _1, const 17_i8); _3 = copy _2 as i32 (IntToInt); - switchInt(move _2) -> [1: bb1, otherwise: bb2]; + switchInt(copy _1) -> [17: bb1, otherwise: bb2]; diff --git a/tests/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff index 22f6443a6c0f9..58c95e20975ee 100644 --- a/tests/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff @@ -11,9 +11,8 @@ StorageLive(_2); StorageLive(_3); _3 = copy _1; -- _2 = Eq(copy _1, const 'x'); + _2 = Eq(copy _1, const 'x'); - switchInt(move _2) -> [0: bb2, otherwise: bb1]; -+ nop; + switchInt(copy _1) -> [120: bb1, otherwise: bb2]; } diff --git a/tests/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff index d5c48fd04ca60..23dc079de01a0 100644 --- a/tests/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff @@ -11,9 +11,8 @@ StorageLive(_2); StorageLive(_3); _3 = copy _1; -- _2 = Eq(copy _1, const 42_i8); + _2 = Eq(copy _1, const 42_i8); - switchInt(move _2) -> [0: bb2, otherwise: bb1]; -+ nop; + switchInt(copy _1) -> [42: bb1, otherwise: bb2]; } diff --git a/tests/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff index 84d62b8136078..5baf481616186 100644 --- a/tests/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff @@ -13,9 +13,8 @@ StorageLive(_2); StorageLive(_3); _3 = copy _1; -- _2 = Eq(copy _1, const 42_u32); + _2 = Eq(copy _1, const 42_u32); - switchInt(move _2) -> [0: bb2, otherwise: bb1]; -+ nop; + switchInt(copy _1) -> [42: bb1, otherwise: bb2]; } @@ -30,9 +29,8 @@ StorageLive(_4); StorageLive(_5); _5 = copy _1; -- _4 = Ne(copy _1, const 21_u32); + _4 = Ne(copy _1, const 21_u32); - switchInt(move _4) -> [0: bb4, otherwise: bb3]; -+ nop; + switchInt(copy _1) -> [21: bb4, otherwise: bb3]; } diff --git a/tests/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff index a1cbaff796b35..79c3525663c89 100644 --- a/tests/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff @@ -11,9 +11,8 @@ StorageLive(_2); StorageLive(_3); _3 = copy _1; -- _2 = Eq(copy _1, const -42_i32); + _2 = Eq(copy _1, const -42_i32); - switchInt(move _2) -> [0: bb2, otherwise: bb1]; -+ nop; + switchInt(copy _1) -> [4294967254: bb1, otherwise: bb2]; } diff --git a/tests/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff index 8101de8cbf381..3e950f053bc35 100644 --- a/tests/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff @@ -11,9 +11,8 @@ StorageLive(_2); StorageLive(_3); _3 = copy _1; -- _2 = Eq(copy _1, const 42_u32); + _2 = Eq(copy _1, const 42_u32); - switchInt(move _2) -> [0: bb2, otherwise: bb1]; -+ nop; + switchInt(copy _1) -> [42: bb1, otherwise: bb2]; } diff --git a/tests/mir-opt/if_condition_int.rs b/tests/mir-opt/if_condition_int.rs index 6950faf502005..6eed1191ffc57 100644 --- a/tests/mir-opt/if_condition_int.rs +++ b/tests/mir-opt/if_condition_int.rs @@ -85,7 +85,7 @@ fn opt_multiple_ifs(x: u32) -> u32 { } // EMIT_MIR if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff -// test that we optimize, but do not remove the b statement, as that is used later on +// the switchInt can be optimized but the b statement can't be removed as it's used later on fn dont_remove_comparison(a: i8) -> i32 { // CHECK-LABEL: fn dont_remove_comparison( // CHECK: [[b:_.*]] = Eq(copy _1, const 17_i8); @@ -104,8 +104,17 @@ fn dont_remove_comparison(a: i8) -> i32 { } // EMIT_MIR if_condition_int.dont_remove_moved_comparison.SimplifyComparisonIntegral.diff +// like dont_remove_comparison above, but with switchInt(move _N) - regression test for #158206 #[custom_mir(dialect = "runtime")] fn dont_remove_moved_comparison(a: i8) -> i32 { + // CHECK-LABEL: fn dont_remove_moved_comparison( + // CHECK: [[b:_.*]] = Eq(copy _1, const 17_i8); + // CHECK: [[cast:_.*]] = copy [[b]] as i32 (IntToInt); + // CHECK: switchInt(copy _1) -> [17: [[BB1:bb.*]], otherwise: [[BB2:bb.*]]]; + // CHECK: [[BB1]]: + // CHECK: _0 = copy [[cast]]; + // CHECK: [[BB2]]: + // CHECK: _0 = Add(copy [[cast]], const 1_i32); mir! { let b: bool; let c: i32;