From f74c4fe2781bf33db2d542383970ae606e648f81 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Wed, 6 May 2026 17:42:46 +0300 Subject: [PATCH 01/23] nix: remove some unneeded variables --- src/tools/nix-dev-shell/shell.nix | 4 ++-- src/tools/nix-dev-shell/x/default.nix | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/tools/nix-dev-shell/shell.nix b/src/tools/nix-dev-shell/shell.nix index 6ca8a7c4652d3..199b63e645230 100644 --- a/src/tools/nix-dev-shell/shell.nix +++ b/src/tools/nix-dev-shell/shell.nix @@ -2,7 +2,7 @@ pkgs ? import { }, }: let - inherit (pkgs.lib) lists attrsets; + inherit (pkgs.lib) lists attrsets makeLibraryPath; x = pkgs.callPackage ./x { }; inherit (x.passthru) cacert env; @@ -25,6 +25,6 @@ pkgs.mkShell { RUSTC_ICE = 0; SSL_CERT_FILE = cacert; # cargo seems to dlopen libcurl, so we need it in the ld library path - LD_LIBRARY_PATH = "${pkgs.lib.makeLibraryPath [pkgs.stdenv.cc.cc.lib pkgs.curl]}"; + LD_LIBRARY_PATH = "${makeLibraryPath [pkgs.stdenv.cc.cc.lib pkgs.curl]}"; }; } diff --git a/src/tools/nix-dev-shell/x/default.nix b/src/tools/nix-dev-shell/x/default.nix index 9573ddd2825d6..915158080e421 100644 --- a/src/tools/nix-dev-shell/x/default.nix +++ b/src/tools/nix-dev-shell/x/default.nix @@ -1,5 +1,4 @@ { - pkgs, lib, stdenv, rustc, @@ -16,7 +15,6 @@ # LLVM Deps ninja, cmake, - glibc, }: stdenv.mkDerivation (self: { strictDeps = true; From 586d87a73e330d8b34b3dd9cacfe30c85d010cfc Mon Sep 17 00:00:00 2001 From: lms0806 Date: Thu, 14 May 2026 15:03:27 +0900 Subject: [PATCH 02/23] chore : Resolving Windows environment test failures --- library/std/src/fs/tests.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 25a5b767699fe..14f8c7e202df0 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -2334,6 +2334,9 @@ fn test_fs_set_times_follows_symlink() { use crate::os::windows::fs::FileTimesExt; let tmp = tmpdir(); + if !got_symlink_permission(&tmp) { + return; + } // Create a target file let target = tmp.join("target"); @@ -2432,6 +2435,9 @@ fn test_fs_set_times_nofollow() { use crate::os::windows::fs::FileTimesExt; let tmp = tmpdir(); + if !got_symlink_permission(&tmp) { + return; + } // Create a target file and a symlink to it let target = tmp.join("target"); From b8813df6cbbf5d3c095c09fc90f6c2428582171f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 25 May 2026 16:58:57 +0200 Subject: [PATCH 03/23] Use #[panic_handler] rather than #[lang = "panic_impl"] As preparation for turning #[panic_handler] from a weak lang item into an EII. --- tests/ui/error-codes/E0152-duplicate-lang-items.rs | 6 +++--- tests/ui/error-codes/E0152-duplicate-lang-items.stderr | 4 ++-- tests/ui/macros/macro-comma-behavior.rs | 2 +- tests/ui/panic-handler/panic-handler-duplicate.rs | 2 +- .../ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/ui/error-codes/E0152-duplicate-lang-items.rs b/tests/ui/error-codes/E0152-duplicate-lang-items.rs index 4b243205dc481..17f235c615997 100644 --- a/tests/ui/error-codes/E0152-duplicate-lang-items.rs +++ b/tests/ui/error-codes/E0152-duplicate-lang-items.rs @@ -12,9 +12,9 @@ extern crate core; use core::panic::PanicInfo; -#[lang = "panic_impl"] -fn panic_impl(info: &PanicInfo) -> ! { - //~^ ERROR: found duplicate lang item `panic_impl` +#[lang = "eh_personality"] +fn personality() { + //~^ ERROR: found duplicate lang item `eh_personality` //~| NOTE first defined in crate `std` loop {} } diff --git a/tests/ui/error-codes/E0152-duplicate-lang-items.stderr b/tests/ui/error-codes/E0152-duplicate-lang-items.stderr index 55d5206b42ce9..3e6cbd2d1a560 100644 --- a/tests/ui/error-codes/E0152-duplicate-lang-items.stderr +++ b/tests/ui/error-codes/E0152-duplicate-lang-items.stderr @@ -1,7 +1,7 @@ -error[E0152]: found duplicate lang item `panic_impl` +error[E0152]: found duplicate lang item `eh_personality` --> $DIR/E0152-duplicate-lang-items.rs:16:1 | -LL | / fn panic_impl(info: &PanicInfo) -> ! { +LL | / fn personality() { LL | | LL | | LL | | loop {} diff --git a/tests/ui/macros/macro-comma-behavior.rs b/tests/ui/macros/macro-comma-behavior.rs index f00d4d3e85842..ea75fdd6842e1 100644 --- a/tests/ui/macros/macro-comma-behavior.rs +++ b/tests/ui/macros/macro-comma-behavior.rs @@ -10,7 +10,7 @@ #[cfg(core)] use core::fmt; #[cfg(core)] #[lang = "eh_personality"] fn eh_personality() {} #[cfg(core)] #[lang = "eh_catch_typeinfo"] static EH_CATCH_TYPEINFO: u8 = 0; -#[cfg(core)] #[lang = "panic_impl"] fn panic_impl(panic: &core::panic::PanicInfo) -> ! { loop {} } +#[cfg(core)] #[panic_handler] fn panic_impl(panic: &core::panic::PanicInfo) -> ! { loop {} } // (see documentation of the similarly-named test in run-pass) fn to_format_or_not_to_format() { diff --git a/tests/ui/panic-handler/panic-handler-duplicate.rs b/tests/ui/panic-handler/panic-handler-duplicate.rs index c0a7d6aa6d723..96a11157b5491 100644 --- a/tests/ui/panic-handler/panic-handler-duplicate.rs +++ b/tests/ui/panic-handler/panic-handler-duplicate.rs @@ -11,7 +11,7 @@ fn panic(info: &PanicInfo) -> ! { loop {} } -#[lang = "panic_impl"] +#[panic_handler] fn panic2(info: &PanicInfo) -> ! { //~ ERROR found duplicate lang item `panic_impl` loop {} } diff --git a/tests/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs b/tests/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs index 938f6bcb906b6..44137b85748fa 100644 --- a/tests/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs +++ b/tests/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs @@ -7,7 +7,7 @@ use core::panic::PanicInfo; -#[lang = "panic_impl"] +#[panic_handler] fn panic_impl(info: &PanicInfo) -> ! { loop {} } #[lang = "eh_personality"] fn eh_personality() {} From fba2ec9a7c6edaf3c05672b875c7f05521413f5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=9D=E5=80=89=E6=B0=B4=E5=B8=8C?= Date: Sat, 30 May 2026 16:30:46 +0800 Subject: [PATCH 04/23] Add #[unsafe_eii] to unsafe EII UI tests --- tests/ui/eii/unsafe_impl_err.rs | 11 +++++++++++ tests/ui/eii/unsafe_impl_err.stderr | 15 +++++++++++++-- tests/ui/eii/unsafe_impl_ok.rs | 12 +++++++++++- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/tests/ui/eii/unsafe_impl_err.rs b/tests/ui/eii/unsafe_impl_err.rs index a6d24c47ae213..c02f2143d73bd 100644 --- a/tests/ui/eii/unsafe_impl_err.rs +++ b/tests/ui/eii/unsafe_impl_err.rs @@ -5,6 +5,7 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] +// Uses manual desugaring of EII internals. #[eii_declaration(bar, "unsafe")] #[rustc_builtin_macro(eii_shared_macro)] macro foo() {} @@ -18,6 +19,16 @@ fn other(x: u64) -> u64 { x } +// Uses the user-facing unsafe_eii wrapper. +#[unsafe_eii(baz)] +fn qux(x: u64) -> u64; + +#[baz] //~ ERROR `#[baz]` is unsafe to implement +fn another(x: u64) -> u64 { + x +} + fn main() { bar(0); + qux(0); } diff --git a/tests/ui/eii/unsafe_impl_err.stderr b/tests/ui/eii/unsafe_impl_err.stderr index eb917a65bb520..0eb3acda93991 100644 --- a/tests/ui/eii/unsafe_impl_err.stderr +++ b/tests/ui/eii/unsafe_impl_err.stderr @@ -1,5 +1,5 @@ error: `#[foo]` is unsafe to implement - --> $DIR/unsafe_impl_err.rs:16:1 + --> $DIR/unsafe_impl_err.rs:17:1 | LL | #[foo] | ^^^^^^ @@ -9,5 +9,16 @@ help: wrap the attribute in `unsafe(...)` LL | #[unsafe(foo)] | +++++++ + -error: aborting due to 1 previous error +error: `#[baz]` is unsafe to implement + --> $DIR/unsafe_impl_err.rs:26:1 + | +LL | #[baz] + | ^^^^^^ + | +help: wrap the attribute in `unsafe(...)` + | +LL | #[unsafe(baz)] + | +++++++ + + +error: aborting due to 2 previous errors diff --git a/tests/ui/eii/unsafe_impl_ok.rs b/tests/ui/eii/unsafe_impl_ok.rs index 1af6d63eb7cff..f7667afaf1956 100644 --- a/tests/ui/eii/unsafe_impl_ok.rs +++ b/tests/ui/eii/unsafe_impl_ok.rs @@ -1,12 +1,12 @@ //@ compile-flags: --crate-type rlib //@ check-pass -// Uses manual desugaring of EII internals: // Tests whether it's okay to implement an unsafe EII with an unsafe implementation. #![feature(extern_item_impls)] #![feature(decl_macro)] #![feature(rustc_attrs)] #![feature(eii_internals)] +// Uses manual desugaring of EII internals. #[eii_declaration(bar, "unsafe")] #[rustc_builtin_macro(eii_shared_macro)] macro foo() {} @@ -20,6 +20,16 @@ fn other(x: u64) -> u64 { x } +// Uses the user-facing unsafe_eii wrapper. +#[unsafe_eii(baz)] +fn qux(x: u64) -> u64; + +#[unsafe(baz)] +fn another(x: u64) -> u64 { + x +} + fn main() { bar(0); + qux(0); } From d2abca46db830f091772fe2533b4b37db208cb4b Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 10 Apr 2026 16:23:20 +0200 Subject: [PATCH 05/23] Remove `Clone` from parser types --- compiler/rustc_attr_parsing/src/parser.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 15a9eb91a143d..2f43dd22b1ed7 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -5,7 +5,7 @@ use std::borrow::Borrow; use std::fmt::{Debug, Display}; - +use std::sync::atomic::AtomicBool; use rustc_ast::token::{self, Delimiter, MetaVarKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{ @@ -87,7 +87,7 @@ impl> Display for PathParser

{ } } -#[derive(Clone, Debug)] +#[derive(Debug)] #[must_use] pub enum ArgParser { NoArgs, @@ -215,7 +215,7 @@ impl ArgParser { /// This enum represents that. /// /// Choose which one you want using the provided methods. -#[derive(Debug, Clone)] +#[derive(Debug)] pub enum MetaItemOrLitParser { MetaItemParser(MetaItemParser), Lit(MetaItemLit), @@ -270,7 +270,6 @@ impl MetaItemOrLitParser { /// `= value` part /// /// The syntax of MetaItems can be found at -#[derive(Clone)] pub struct MetaItemParser { path: OwnedPathParser, args: ArgParser, @@ -670,7 +669,7 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { } } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct MetaItemListParser { sub_parsers: ThinVec, pub span: Span, From 79e85e6e54ec16f507d5a121acdaa0cbccf701d1 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 10 Apr 2026 16:27:18 +0200 Subject: [PATCH 06/23] Add debug assertion to check usage of arguments of `MetaItemParser` --- .../src/attributes/diagnostic/on_const.rs | 1 + .../src/attributes/diagnostic/on_move.rs | 1 + .../src/attributes/diagnostic/on_unknown.rs | 1 + .../rustc_attr_parsing/src/attributes/doc.rs | 2 + .../src/attributes/dummy.rs | 3 +- compiler/rustc_attr_parsing/src/context.rs | 9 +++ compiler/rustc_attr_parsing/src/interface.rs | 39 +++++++++++- compiler/rustc_attr_parsing/src/parser.rs | 61 ++++++++++++++++++- 8 files changed, 113 insertions(+), 4 deletions(-) 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 e783e49ef1e83..4379563873f4d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs @@ -17,6 +17,7 @@ impl AttributeParser for OnConstParser { |this, cx, args| { if !cx.features().diagnostic_on_const() { // `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs + args.ignore_args(); return; } 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 b3c6c93a480ee..f08d983d47efc 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs @@ -20,6 +20,7 @@ impl OnMoveParser { fn parse<'sess>(&mut self, cx: &mut AcceptContext<'_, 'sess>, args: &ArgParser, mode: Mode) { if !cx.features().diagnostic_on_move() { // `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs + args.ignore_args(); return; } 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 4c327804dd5b9..43d2ead682852 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs @@ -18,6 +18,7 @@ impl OnUnknownParser { && !features.diagnostic_on_unknown() { // `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs + args.ignore_args(); return; } let span = cx.attr_span; diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 535f67f67a263..f31af01e0e77e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -190,6 +190,8 @@ impl DocParser { // FIXME: convert list into a Vec of `AttributeKind` because current code is awful. for attr in list.mixed() { + // Arguments of `attr` are checked via the span, so can be safely ignored + attr.ignore_args(); self.attribute.test_attrs.push(attr.span()); } } diff --git a/compiler/rustc_attr_parsing/src/attributes/dummy.rs b/compiler/rustc_attr_parsing/src/attributes/dummy.rs index 622f7e1ceba49..ebf72722c9012 100644 --- a/compiler/rustc_attr_parsing/src/attributes/dummy.rs +++ b/compiler/rustc_attr_parsing/src/attributes/dummy.rs @@ -14,7 +14,8 @@ impl SingleAttributeParser for RustcDummyParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); const TEMPLATE: AttributeTemplate = template!(Word); // Anything, really - fn convert(_: &mut AcceptContext<'_, '_>, _: &ArgParser) -> Option { + fn convert(_: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { + args.ignore_args(); Some(AttributeKind::RustcDummy) } } diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 750fe10a483fc..8da222e58496a 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -4,6 +4,8 @@ use std::collections::btree_map::Entry; use std::mem; use std::ops::{Deref, DerefMut}; use std::sync::LazyLock; +#[cfg(debug_assertions)] +use std::sync::atomic::{AtomicBool, Ordering}; use rustc_ast::{AttrStyle, MetaItemLit, Safety}; use rustc_data_structures::sync::{DynSend, DynSync}; @@ -405,6 +407,8 @@ impl<'f, 'sess: 'f> SharedContext<'f, 'sess> { kind: EmitAttribute, span: impl Into, ) { + #[cfg(debug_assertions)] + self.has_lint_been_emitted.store(true, Ordering::Relaxed); if !matches!( self.should_emit, ShouldEmit::ErrorsAndLints { .. } | ShouldEmit::EarlyFatal { also_emit_lints: true } @@ -744,6 +748,11 @@ pub struct SharedContext<'p, 'sess> { pub(crate) target: rustc_hir::Target, pub(crate) emit_lint: &'p mut dyn FnMut(LintId, MultiSpan, EmitAttribute), + + /// This atomic bool keeps track of whether any lint has been emitted. + /// This is used for the arguments-used check. + #[cfg(debug_assertions)] + pub(crate) has_lint_been_emitted: AtomicBool, } /// Context given to every attribute parser during finalization. diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index ffe0451f29aa9..4fbf7b7644033 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -1,4 +1,6 @@ use std::convert::identity; +#[cfg(debug_assertions)] +use std::sync::atomic::{AtomicBool, Ordering}; use rustc_ast as ast; use rustc_ast::token::DocFragmentKind; @@ -228,6 +230,8 @@ impl<'sess> AttributeParser<'sess> { target_span, target, emit_lint: &mut emit_lint, + #[cfg(debug_assertions)] + has_lint_been_emitted: AtomicBool::new(false), }, attr_span, inner_span, @@ -394,6 +398,8 @@ impl<'sess> AttributeParser<'sess> { target_span, target, emit_lint: &mut emit_lint, + #[cfg(debug_assertions)] + has_lint_been_emitted: AtomicBool::new(false), }, attr_span, inner_span: lower_span(n.item.span()), @@ -408,6 +414,10 @@ impl<'sess> AttributeParser<'sess> { finalizers.push(accept.finalizer); Self::check_target(&accept.allowed_targets, &mut cx); + #[cfg(debug_assertions)] + if !cx.shared.has_lint_been_emitted.load(Ordering::Relaxed) { + cx.shared.cx.check_args_used(&attr, &args) + } } else { let attr = AttrItem { path: attr_path.clone(), @@ -441,7 +451,14 @@ impl<'sess> AttributeParser<'sess> { early_parsed_state.finalize_early_parsed_attributes(&mut attributes); for f in &finalizers { if let Some(attr) = f(&mut FinalizeContext { - shared: SharedContext { cx: self, target_span, target, emit_lint: &mut emit_lint }, + shared: SharedContext { + cx: self, + target_span, + target, + emit_lint: &mut emit_lint, + #[cfg(debug_assertions)] + has_lint_been_emitted: AtomicBool::new(false), + }, all_attrs: &attr_paths, }) { attributes.push(Attribute::Parsed(attr)); @@ -455,6 +472,26 @@ impl<'sess> AttributeParser<'sess> { attributes } + #[cfg(debug_assertions)] + /// Checks whether all `ArgParser`s were observed by an attribute parser at least once + /// This check exists because otherwise it is too easy to accidentally ignore the arguments of an attribute + fn check_args_used(&self, attr: &ast::Attribute, args: &ArgParser) { + if let ArgParser::List(items) = args { + for item in items.mixed() { + if let crate::parser::MetaItemOrLitParser::MetaItemParser(item) = item { + if !item.are_args_checked() { + self.dcx().span_delayed_bug( + item.span(), + "attribute args were not properly checked", + ); + return; + } + self.check_args_used(attr, item.args()); + } + } + } + } + /// Returns whether there is a parser for an attribute with this name pub fn is_parsed_attribute(path: &[Symbol]) -> bool { /// The list of attributes that are parsed attributes, diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 2f43dd22b1ed7..820400813f910 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -5,7 +5,9 @@ use std::borrow::Borrow; use std::fmt::{Debug, Display}; -use std::sync::atomic::AtomicBool; +#[cfg(debug_assertions)] +use std::sync::atomic::{AtomicBool, Ordering}; + use rustc_ast::token::{self, Delimiter, MetaVarKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{ @@ -209,6 +211,19 @@ impl ArgParser { Self::NameValue(args) => Err(args.args_span()), } } + + /// Explicitly ignore the arguments, disarming the arguments-used check + pub fn ignore_args(&self) { + #[cfg(debug_assertions)] + match self { + ArgParser::List(list) => { + for item in list.mixed() { + item.ignore_args(); + } + } + _ => {} + } + } } /// Inside lists, values could be either literals, or more deeply nested meta items. @@ -253,6 +268,26 @@ impl MetaItemOrLitParser { MetaItemOrLitParser::Lit(_) => None, } } + + /// Returns some if this `MetaItemOrLitParser` is a `MetaItem` with no arguments + pub fn meta_item_no_args(&self) -> Option<&MetaItemParser> { + let meta_item = self.meta_item()?; + match meta_item.args().as_no_args() { + Ok(_) => Some(meta_item), + Err(_) => None, + } + } + + /// Explicitly ignore the arguments, disarming the arguments-used check + pub fn ignore_args(&self) { + #[cfg(debug_assertions)] + match self { + MetaItemOrLitParser::MetaItemParser(meta_item) => { + meta_item.ignore_args(); + } + MetaItemOrLitParser::Lit(_) => {} + } + } } // FIXME(scrabsha): once #155696 is merged, update this and mention the higher-level APIs. @@ -273,6 +308,11 @@ impl MetaItemOrLitParser { pub struct MetaItemParser { path: OwnedPathParser, args: ArgParser, + + /// Whether the `args` of this meta item have been looked at. + /// This is tracked because if the arguments of a `MetaItemParser` are ignored, this is probably a mistake + #[cfg(debug_assertions)] + args_checked: AtomicBool, } impl Debug for MetaItemParser { @@ -309,6 +349,8 @@ impl MetaItemParser { /// Gets just the args parser, without caring about the path. pub fn args(&self) -> &ArgParser { + #[cfg(debug_assertions)] + self.args_checked.store(true, Ordering::Relaxed); &self.args } @@ -321,6 +363,16 @@ impl MetaItemParser { pub fn word_is(&self, sym: Symbol) -> Option<&ArgParser> { self.path().word_is(sym).then(|| self.args()) } + + /// Explicitly ignore the arguments, disarming the arguments-used check + pub fn ignore_args(&self) { + self.args().ignore_args(); + } + + #[cfg(debug_assertions)] + pub fn are_args_checked(&self) -> bool { + self.args_checked.load(Ordering::Relaxed) + } } #[derive(Clone)] @@ -544,7 +596,12 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { ArgParser::NoArgs }; - Ok(MetaItemParser { path: PathParser(path), args }) + Ok(MetaItemParser { + path: PathParser(path), + args, + #[cfg(debug_assertions)] + args_checked: AtomicBool::new(false), + }) } fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser> { From b3d4af3c613e89a737a37b20ac821f9eed8eae93 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 12 Apr 2026 12:33:49 +0200 Subject: [PATCH 07/23] Properly check arguments of `#[inline]` --- .../src/attributes/inline.rs | 2 +- tests/ui/attributes/args-checked.rs | 7 +++ tests/ui/attributes/args-checked.stderr | 45 +++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 tests/ui/attributes/args-checked.rs create mode 100644 tests/ui/attributes/args-checked.stderr diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index aee0537771fd4..9363ae2bf286f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -39,7 +39,7 @@ impl SingleAttributeParser for InlineParser { ArgParser::List(list) => { let l = cx.expect_single(list)?; - match l.meta_item().and_then(|i| i.path().word_sym()) { + match l.meta_item_no_args().and_then(|i| i.path().word_sym()) { Some(sym::always) => { Some(AttributeKind::Inline(InlineAttr::Always, cx.attr_span)) } diff --git a/tests/ui/attributes/args-checked.rs b/tests/ui/attributes/args-checked.rs new file mode 100644 index 0000000000000..8a512a7f2a849 --- /dev/null +++ b/tests/ui/attributes/args-checked.rs @@ -0,0 +1,7 @@ +#[inline(always = 5)] +//~^ ERROR malformed +#[inline(always(x, y, z))] +//~^ ERROR malformed +fn main() { + +} \ No newline at end of file diff --git a/tests/ui/attributes/args-checked.stderr b/tests/ui/attributes/args-checked.stderr new file mode 100644 index 0000000000000..362a03ac68f5d --- /dev/null +++ b/tests/ui/attributes/args-checked.stderr @@ -0,0 +1,45 @@ +error[E0539]: malformed `inline` attribute input + --> $DIR/args-checked.rs:1:1 + | +LL | #[inline(always = 5)] + | ^^^^^^^^^----------^^ + | | + | valid arguments are `always` or `never` + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[inline(always = 5)] +LL + #[inline(always)] + | +LL - #[inline(always = 5)] +LL + #[inline(never)] + | +LL - #[inline(always = 5)] +LL + #[inline] + | + +error[E0539]: malformed `inline` attribute input + --> $DIR/args-checked.rs:3:1 + | +LL | #[inline(always(x, y, z))] + | ^^^^^^^^^---------------^^ + | | + | valid arguments are `always` or `never` + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[inline(always(x, y, z))] +LL + #[inline(always)] + | +LL - #[inline(always(x, y, z))] +LL + #[inline(never)] + | +LL - #[inline(always(x, y, z))] +LL + #[inline] + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0539`. From bf2db507d7e9734b77ec0225b95ab614d0a4fcca Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 12 Apr 2026 12:35:05 +0200 Subject: [PATCH 08/23] Properly check arguments of `#[instruction_set]` --- .../src/attributes/instruction_set.rs | 2 +- tests/ui/attributes/args-checked.rs | 4 +++ tests/ui/attributes/args-checked.stderr | 32 ++++++++++++++++++- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs b/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs index 6f239a8f5761d..a42a77d95c5c0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs +++ b/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs @@ -21,7 +21,7 @@ impl SingleAttributeParser for InstructionSetParser { const POSSIBLE_ARM_SYMBOLS: &[Symbol] = &[sym::a32, sym::t32]; let maybe_meta_item = cx.expect_single_element_list(args, cx.attr_span)?; - let Some(meta_item) = maybe_meta_item.meta_item() else { + let Some(meta_item) = maybe_meta_item.meta_item_no_args() else { cx.adcx().expected_specific_argument(maybe_meta_item.span(), POSSIBLE_SYMBOLS); return None; }; diff --git a/tests/ui/attributes/args-checked.rs b/tests/ui/attributes/args-checked.rs index 8a512a7f2a849..0f4d933e7be4e 100644 --- a/tests/ui/attributes/args-checked.rs +++ b/tests/ui/attributes/args-checked.rs @@ -2,6 +2,10 @@ //~^ ERROR malformed #[inline(always(x, y, z))] //~^ ERROR malformed +#[instruction_set(arm::a32 = 5)] +//~^ ERROR malformed +#[instruction_set(arm::a32(x, y, z))] +//~^ ERROR malformed fn main() { } \ No newline at end of file diff --git a/tests/ui/attributes/args-checked.stderr b/tests/ui/attributes/args-checked.stderr index 362a03ac68f5d..cdc08bc4b45f0 100644 --- a/tests/ui/attributes/args-checked.stderr +++ b/tests/ui/attributes/args-checked.stderr @@ -40,6 +40,36 @@ LL - #[inline(always(x, y, z))] LL + #[inline] | -error: aborting due to 2 previous errors +error[E0539]: malformed `instruction_set` attribute input + --> $DIR/args-checked.rs:5:1 + | +LL | #[instruction_set(arm::a32 = 5)] + | ^^^^^^^^^^^^^^^^^^------------^^ + | | + | valid arguments are `arm::a32` or `arm::t32` + | + = note: for more information, visit +help: must be of the form + | +LL - #[instruction_set(arm::a32 = 5)] +LL + #[instruction_set(set)] + | + +error[E0539]: malformed `instruction_set` attribute input + --> $DIR/args-checked.rs:7:1 + | +LL | #[instruction_set(arm::a32(x, y, z))] + | ^^^^^^^^^^^^^^^^^^-----------------^^ + | | + | valid arguments are `arm::a32` or `arm::t32` + | + = note: for more information, visit +help: must be of the form + | +LL - #[instruction_set(arm::a32(x, y, z))] +LL + #[instruction_set(set)] + | + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0539`. From f3983c71ced4ed82bfa6fa371b1b98e2c74fb3c0 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 12 Apr 2026 12:36:39 +0200 Subject: [PATCH 09/23] Properly check arguments of `#[macro_export]` --- .../src/attributes/macro_attrs.rs | 2 +- tests/ui/attributes/args-checked.rs | 10 +++++ tests/ui/attributes/args-checked.stderr | 43 ++++++++++++++++++- 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index 067590d23fc8d..ff0ab2747962f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -145,7 +145,7 @@ impl SingleAttributeParser for MacroExportParser { cx.adcx().warn_ill_formed_attribute_input(INVALID_MACRO_EXPORT_ARGUMENTS); return None; }; - match l.meta_item().and_then(|i| i.path().word_sym()) { + match l.meta_item_no_args().and_then(|i| i.path().word_sym()) { Some(sym::local_inner_macros) => true, _ => { cx.adcx().warn_ill_formed_attribute_input(INVALID_MACRO_EXPORT_ARGUMENTS); diff --git a/tests/ui/attributes/args-checked.rs b/tests/ui/attributes/args-checked.rs index 0f4d933e7be4e..c5abfd68ed66c 100644 --- a/tests/ui/attributes/args-checked.rs +++ b/tests/ui/attributes/args-checked.rs @@ -8,4 +8,14 @@ //~^ ERROR malformed fn main() { +} + +#[macro_export(local_inner_macros = 5)] +//~^ ERROR valid forms for the attribute are +//~| WARN previously accepted +#[macro_export(local_inner_macros(x, y, z))] +//~^ ERROR valid forms for the attribute are +//~| WARN previously accepted +macro_rules! m { + () => {}; } \ No newline at end of file diff --git a/tests/ui/attributes/args-checked.stderr b/tests/ui/attributes/args-checked.stderr index cdc08bc4b45f0..2d3cf21e201ea 100644 --- a/tests/ui/attributes/args-checked.stderr +++ b/tests/ui/attributes/args-checked.stderr @@ -70,6 +70,47 @@ LL - #[instruction_set(arm::a32(x, y, z))] LL + #[instruction_set(set)] | -error: aborting due to 4 previous errors +error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/args-checked.rs:13:1 + | +LL | #[macro_export(local_inner_macros = 5)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + = note: `#[deny(invalid_macro_export_arguments)]` (part of `#[deny(future_incompatible)]`) on by default + +error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/args-checked.rs:16:1 + | +LL | #[macro_export(local_inner_macros(x, y, z))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0539`. +Future incompatibility report: Future breakage diagnostic: +error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/args-checked.rs:13:1 + | +LL | #[macro_export(local_inner_macros = 5)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + = note: `#[deny(invalid_macro_export_arguments)]` (part of `#[deny(future_incompatible)]`) on by default + +Future breakage diagnostic: +error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/args-checked.rs:16:1 + | +LL | #[macro_export(local_inner_macros(x, y, z))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + = note: `#[deny(invalid_macro_export_arguments)]` (part of `#[deny(future_incompatible)]`) on by default + From f35ea0eb8e04936b39f9e9d46cc4a33ab78006ab Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 12 Apr 2026 12:39:09 +0200 Subject: [PATCH 10/23] Properly check arguments of `#[rustc_allow_const_fn_unstable]` --- .../src/attributes/allow_unstable.rs | 2 +- tests/ui/attributes/args-checked.rs | 10 ++++++- tests/ui/attributes/args-checked.stderr | 30 +++++++++++++------ 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index e72533fb3c890..05e1557f58b60 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -91,7 +91,7 @@ fn parse_unstable( for param in list.mixed() { let param_span = param.span(); - if let Some(ident) = param.meta_item().and_then(|i| i.path().word()) { + if let Some(ident) = param.meta_item_no_args().and_then(|i| i.path().word()) { res.push(ident.name); } else { cx.emit_err(session_diagnostics::ExpectsFeatures { diff --git a/tests/ui/attributes/args-checked.rs b/tests/ui/attributes/args-checked.rs index c5abfd68ed66c..462ca307b58a7 100644 --- a/tests/ui/attributes/args-checked.rs +++ b/tests/ui/attributes/args-checked.rs @@ -1,3 +1,5 @@ +#![feature(rustc_attrs)] + #[inline(always = 5)] //~^ ERROR malformed #[inline(always(x, y, z))] @@ -18,4 +20,10 @@ fn main() { //~| WARN previously accepted macro_rules! m { () => {}; -} \ No newline at end of file +} + +#[rustc_allow_const_fn_unstable(x = 5)] +//~^ ERROR `rustc_allow_const_fn_unstable` expects feature names +#[rustc_allow_const_fn_unstable(x(x, y, z))] +//~^ ERROR `rustc_allow_const_fn_unstable` expects feature names +const fn g() {} \ No newline at end of file diff --git a/tests/ui/attributes/args-checked.stderr b/tests/ui/attributes/args-checked.stderr index 2d3cf21e201ea..e523d3c3b5415 100644 --- a/tests/ui/attributes/args-checked.stderr +++ b/tests/ui/attributes/args-checked.stderr @@ -1,5 +1,5 @@ error[E0539]: malformed `inline` attribute input - --> $DIR/args-checked.rs:1:1 + --> $DIR/args-checked.rs:3:1 | LL | #[inline(always = 5)] | ^^^^^^^^^----------^^ @@ -20,7 +20,7 @@ LL + #[inline] | error[E0539]: malformed `inline` attribute input - --> $DIR/args-checked.rs:3:1 + --> $DIR/args-checked.rs:5:1 | LL | #[inline(always(x, y, z))] | ^^^^^^^^^---------------^^ @@ -41,7 +41,7 @@ LL + #[inline] | error[E0539]: malformed `instruction_set` attribute input - --> $DIR/args-checked.rs:5:1 + --> $DIR/args-checked.rs:7:1 | LL | #[instruction_set(arm::a32 = 5)] | ^^^^^^^^^^^^^^^^^^------------^^ @@ -56,7 +56,7 @@ LL + #[instruction_set(set)] | error[E0539]: malformed `instruction_set` attribute input - --> $DIR/args-checked.rs:7:1 + --> $DIR/args-checked.rs:9:1 | LL | #[instruction_set(arm::a32(x, y, z))] | ^^^^^^^^^^^^^^^^^^-----------------^^ @@ -70,8 +70,20 @@ LL - #[instruction_set(arm::a32(x, y, z))] LL + #[instruction_set(set)] | +error: `rustc_allow_const_fn_unstable` expects feature names + --> $DIR/args-checked.rs:25:33 + | +LL | #[rustc_allow_const_fn_unstable(x = 5)] + | ^^^^^ + +error: `rustc_allow_const_fn_unstable` expects feature names + --> $DIR/args-checked.rs:27:33 + | +LL | #[rustc_allow_const_fn_unstable(x(x, y, z))] + | ^^^^^^^^^^ + error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` - --> $DIR/args-checked.rs:13:1 + --> $DIR/args-checked.rs:15:1 | LL | #[macro_export(local_inner_macros = 5)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -81,7 +93,7 @@ LL | #[macro_export(local_inner_macros = 5)] = note: `#[deny(invalid_macro_export_arguments)]` (part of `#[deny(future_incompatible)]`) on by default error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` - --> $DIR/args-checked.rs:16:1 + --> $DIR/args-checked.rs:18:1 | LL | #[macro_export(local_inner_macros(x, y, z))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -89,12 +101,12 @@ LL | #[macro_export(local_inner_macros(x, y, z))] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 -error: aborting due to 6 previous errors +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0539`. Future incompatibility report: Future breakage diagnostic: error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` - --> $DIR/args-checked.rs:13:1 + --> $DIR/args-checked.rs:15:1 | LL | #[macro_export(local_inner_macros = 5)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -105,7 +117,7 @@ LL | #[macro_export(local_inner_macros = 5)] Future breakage diagnostic: error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` - --> $DIR/args-checked.rs:16:1 + --> $DIR/args-checked.rs:18:1 | LL | #[macro_export(local_inner_macros(x, y, z))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 5c90b79490a4e60299bb5383e852ca9517c77076 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 12 Apr 2026 12:40:19 +0200 Subject: [PATCH 11/23] Properly check arguments of `#[optimize]` --- .../src/attributes/codegen_attrs.rs | 2 +- tests/ui/attributes/args-checked.rs | 7 ++ tests/ui/attributes/args-checked.stderr | 74 ++++++++++++++++--- 3 files changed, 71 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 41abb4806567f..002c55e4372b5 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -26,7 +26,7 @@ impl SingleAttributeParser for OptimizeParser { fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { let single = cx.expect_single_element_list(args, cx.attr_span)?; - let res = match single.meta_item().and_then(|i| i.path().word().map(|i| i.name)) { + let res = match single.meta_item_no_args().and_then(|i| i.path().word().map(|i| i.name)) { Some(sym::size) => OptimizeAttr::Size, Some(sym::speed) => OptimizeAttr::Speed, Some(sym::none) => OptimizeAttr::DoNotOptimize, diff --git a/tests/ui/attributes/args-checked.rs b/tests/ui/attributes/args-checked.rs index 462ca307b58a7..b727edc8e9192 100644 --- a/tests/ui/attributes/args-checked.rs +++ b/tests/ui/attributes/args-checked.rs @@ -1,4 +1,6 @@ #![feature(rustc_attrs)] +#![feature(optimize_attribute)] +#![allow(unused_attributes)] #[inline(always = 5)] //~^ ERROR malformed @@ -8,6 +10,11 @@ //~^ ERROR malformed #[instruction_set(arm::a32(x, y, z))] //~^ ERROR malformed +#[optimize(size = 5)] +//~^ ERROR malformed +#[optimize(size(x, y, z))] +//~^ ERROR malformed +//~| ERROR multiple `optimize` attributes fn main() { } diff --git a/tests/ui/attributes/args-checked.stderr b/tests/ui/attributes/args-checked.stderr index e523d3c3b5415..a0c57bc1d3783 100644 --- a/tests/ui/attributes/args-checked.stderr +++ b/tests/ui/attributes/args-checked.stderr @@ -1,5 +1,5 @@ error[E0539]: malformed `inline` attribute input - --> $DIR/args-checked.rs:3:1 + --> $DIR/args-checked.rs:5:1 | LL | #[inline(always = 5)] | ^^^^^^^^^----------^^ @@ -20,7 +20,7 @@ LL + #[inline] | error[E0539]: malformed `inline` attribute input - --> $DIR/args-checked.rs:5:1 + --> $DIR/args-checked.rs:7:1 | LL | #[inline(always(x, y, z))] | ^^^^^^^^^---------------^^ @@ -41,7 +41,7 @@ LL + #[inline] | error[E0539]: malformed `instruction_set` attribute input - --> $DIR/args-checked.rs:7:1 + --> $DIR/args-checked.rs:9:1 | LL | #[instruction_set(arm::a32 = 5)] | ^^^^^^^^^^^^^^^^^^------------^^ @@ -56,7 +56,7 @@ LL + #[instruction_set(set)] | error[E0539]: malformed `instruction_set` attribute input - --> $DIR/args-checked.rs:9:1 + --> $DIR/args-checked.rs:11:1 | LL | #[instruction_set(arm::a32(x, y, z))] | ^^^^^^^^^^^^^^^^^^-----------------^^ @@ -70,20 +70,72 @@ LL - #[instruction_set(arm::a32(x, y, z))] LL + #[instruction_set(set)] | +error[E0539]: malformed `optimize` attribute input + --> $DIR/args-checked.rs:13:1 + | +LL | #[optimize(size = 5)] + | ^^^^^^^^^^^--------^^ + | | + | valid arguments are `size`, `speed` or `none` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[optimize(size = 5)] +LL + #[optimize(none)] + | +LL - #[optimize(size = 5)] +LL + #[optimize(size)] + | +LL - #[optimize(size = 5)] +LL + #[optimize(speed)] + | + +error[E0539]: malformed `optimize` attribute input + --> $DIR/args-checked.rs:15:1 + | +LL | #[optimize(size(x, y, z))] + | ^^^^^^^^^^^-------------^^ + | | + | valid arguments are `size`, `speed` or `none` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[optimize(size(x, y, z))] +LL + #[optimize(none)] + | +LL - #[optimize(size(x, y, z))] +LL + #[optimize(size)] + | +LL - #[optimize(size(x, y, z))] +LL + #[optimize(speed)] + | + +error: multiple `optimize` attributes + --> $DIR/args-checked.rs:15:1 + | +LL | #[optimize(size(x, y, z))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/args-checked.rs:13:1 + | +LL | #[optimize(size = 5)] + | ^^^^^^^^^^^^^^^^^^^^^ + error: `rustc_allow_const_fn_unstable` expects feature names - --> $DIR/args-checked.rs:25:33 + --> $DIR/args-checked.rs:32:33 | LL | #[rustc_allow_const_fn_unstable(x = 5)] | ^^^^^ error: `rustc_allow_const_fn_unstable` expects feature names - --> $DIR/args-checked.rs:27:33 + --> $DIR/args-checked.rs:34:33 | LL | #[rustc_allow_const_fn_unstable(x(x, y, z))] | ^^^^^^^^^^ error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` - --> $DIR/args-checked.rs:15:1 + --> $DIR/args-checked.rs:22:1 | LL | #[macro_export(local_inner_macros = 5)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -93,7 +145,7 @@ LL | #[macro_export(local_inner_macros = 5)] = note: `#[deny(invalid_macro_export_arguments)]` (part of `#[deny(future_incompatible)]`) on by default error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` - --> $DIR/args-checked.rs:18:1 + --> $DIR/args-checked.rs:25:1 | LL | #[macro_export(local_inner_macros(x, y, z))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -101,12 +153,12 @@ LL | #[macro_export(local_inner_macros(x, y, z))] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 -error: aborting due to 8 previous errors +error: aborting due to 11 previous errors For more information about this error, try `rustc --explain E0539`. Future incompatibility report: Future breakage diagnostic: error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` - --> $DIR/args-checked.rs:15:1 + --> $DIR/args-checked.rs:22:1 | LL | #[macro_export(local_inner_macros = 5)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -117,7 +169,7 @@ LL | #[macro_export(local_inner_macros = 5)] Future breakage diagnostic: error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` - --> $DIR/args-checked.rs:18:1 + --> $DIR/args-checked.rs:25:1 | LL | #[macro_export(local_inner_macros(x, y, z))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 10c6c99d307c7910902f0c0ca1f26847527e15f0 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 12 Apr 2026 12:41:06 +0200 Subject: [PATCH 12/23] Properly check arguments of `#[coverage]` --- .../src/attributes/codegen_attrs.rs | 2 +- tests/ui/attributes/args-checked.rs | 5 ++ tests/ui/attributes/args-checked.stderr | 64 ++++++++++++++----- 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 002c55e4372b5..9c4266f3c9d22 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -80,7 +80,7 @@ impl SingleAttributeParser for CoverageParser { let mut fail_incorrect_argument = |span| cx.adcx().expected_specific_argument(span, &[sym::on, sym::off]); - let Some(arg) = arg.meta_item() else { + let Some(arg) = arg.meta_item_no_args() else { fail_incorrect_argument(arg.span()); return None; }; diff --git a/tests/ui/attributes/args-checked.rs b/tests/ui/attributes/args-checked.rs index b727edc8e9192..49cf2bdbd03e0 100644 --- a/tests/ui/attributes/args-checked.rs +++ b/tests/ui/attributes/args-checked.rs @@ -1,5 +1,6 @@ #![feature(rustc_attrs)] #![feature(optimize_attribute)] +#![feature(coverage_attribute)] #![allow(unused_attributes)] #[inline(always = 5)] @@ -15,6 +16,10 @@ #[optimize(size(x, y, z))] //~^ ERROR malformed //~| ERROR multiple `optimize` attributes +#[coverage(off = 5)] +//~^ ERROR malformed +#[coverage(off(x, y, z))] +//~^ ERROR malformed fn main() { } diff --git a/tests/ui/attributes/args-checked.stderr b/tests/ui/attributes/args-checked.stderr index a0c57bc1d3783..8d9359dd25e8b 100644 --- a/tests/ui/attributes/args-checked.stderr +++ b/tests/ui/attributes/args-checked.stderr @@ -1,5 +1,5 @@ error[E0539]: malformed `inline` attribute input - --> $DIR/args-checked.rs:5:1 + --> $DIR/args-checked.rs:6:1 | LL | #[inline(always = 5)] | ^^^^^^^^^----------^^ @@ -20,7 +20,7 @@ LL + #[inline] | error[E0539]: malformed `inline` attribute input - --> $DIR/args-checked.rs:7:1 + --> $DIR/args-checked.rs:8:1 | LL | #[inline(always(x, y, z))] | ^^^^^^^^^---------------^^ @@ -41,7 +41,7 @@ LL + #[inline] | error[E0539]: malformed `instruction_set` attribute input - --> $DIR/args-checked.rs:9:1 + --> $DIR/args-checked.rs:10:1 | LL | #[instruction_set(arm::a32 = 5)] | ^^^^^^^^^^^^^^^^^^------------^^ @@ -56,7 +56,7 @@ LL + #[instruction_set(set)] | error[E0539]: malformed `instruction_set` attribute input - --> $DIR/args-checked.rs:11:1 + --> $DIR/args-checked.rs:12:1 | LL | #[instruction_set(arm::a32(x, y, z))] | ^^^^^^^^^^^^^^^^^^-----------------^^ @@ -71,7 +71,7 @@ LL + #[instruction_set(set)] | error[E0539]: malformed `optimize` attribute input - --> $DIR/args-checked.rs:13:1 + --> $DIR/args-checked.rs:14:1 | LL | #[optimize(size = 5)] | ^^^^^^^^^^^--------^^ @@ -91,7 +91,7 @@ LL + #[optimize(speed)] | error[E0539]: malformed `optimize` attribute input - --> $DIR/args-checked.rs:15:1 + --> $DIR/args-checked.rs:16:1 | LL | #[optimize(size(x, y, z))] | ^^^^^^^^^^^-------------^^ @@ -111,31 +111,65 @@ LL + #[optimize(speed)] | error: multiple `optimize` attributes - --> $DIR/args-checked.rs:15:1 + --> $DIR/args-checked.rs:16:1 | LL | #[optimize(size(x, y, z))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/args-checked.rs:13:1 + --> $DIR/args-checked.rs:14:1 | LL | #[optimize(size = 5)] | ^^^^^^^^^^^^^^^^^^^^^ +error[E0539]: malformed `coverage` attribute input + --> $DIR/args-checked.rs:19:1 + | +LL | #[coverage(off = 5)] + | ^^^^^^^^^^^-------^^ + | | + | valid arguments are `on` or `off` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[coverage(off = 5)] +LL + #[coverage(off)] + | +LL - #[coverage(off = 5)] +LL + #[coverage(on)] + | + +error[E0539]: malformed `coverage` attribute input + --> $DIR/args-checked.rs:21:1 + | +LL | #[coverage(off(x, y, z))] + | ^^^^^^^^^^^------------^^ + | | + | valid arguments are `on` or `off` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[coverage(off(x, y, z))] +LL + #[coverage(off)] + | +LL - #[coverage(off(x, y, z))] +LL + #[coverage(on)] + | + error: `rustc_allow_const_fn_unstable` expects feature names - --> $DIR/args-checked.rs:32:33 + --> $DIR/args-checked.rs:37:33 | LL | #[rustc_allow_const_fn_unstable(x = 5)] | ^^^^^ error: `rustc_allow_const_fn_unstable` expects feature names - --> $DIR/args-checked.rs:34:33 + --> $DIR/args-checked.rs:39:33 | LL | #[rustc_allow_const_fn_unstable(x(x, y, z))] | ^^^^^^^^^^ error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` - --> $DIR/args-checked.rs:22:1 + --> $DIR/args-checked.rs:27:1 | LL | #[macro_export(local_inner_macros = 5)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +179,7 @@ LL | #[macro_export(local_inner_macros = 5)] = note: `#[deny(invalid_macro_export_arguments)]` (part of `#[deny(future_incompatible)]`) on by default error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` - --> $DIR/args-checked.rs:25:1 + --> $DIR/args-checked.rs:30:1 | LL | #[macro_export(local_inner_macros(x, y, z))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -153,12 +187,12 @@ LL | #[macro_export(local_inner_macros(x, y, z))] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 -error: aborting due to 11 previous errors +error: aborting due to 13 previous errors For more information about this error, try `rustc --explain E0539`. Future incompatibility report: Future breakage diagnostic: error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` - --> $DIR/args-checked.rs:22:1 + --> $DIR/args-checked.rs:27:1 | LL | #[macro_export(local_inner_macros = 5)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +203,7 @@ LL | #[macro_export(local_inner_macros = 5)] Future breakage diagnostic: error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` - --> $DIR/args-checked.rs:25:1 + --> $DIR/args-checked.rs:30:1 | LL | #[macro_export(local_inner_macros(x, y, z))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 4081ff49d0c10a643b0820ddf00d5088fcbf966e Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Wed, 29 Apr 2026 20:11:50 +0200 Subject: [PATCH 13/23] Properly check arguments of `#[used]` --- .../src/attributes/codegen_attrs.rs | 2 +- tests/ui/attributes/args-checked.rs | 8 +++- tests/ui/attributes/args-checked.stderr | 42 ++++++++++++++++++- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 9c4266f3c9d22..94cc2cf76d6c7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -373,7 +373,7 @@ impl AttributeParser for UsedParser { return; }; - match l.meta_item().and_then(|i| i.path().word_sym()) { + match l.meta_item_no_args().and_then(|i| i.path().word_sym()) { Some(sym::compiler) => { if !cx.features().used_with_arg() { feature_err( diff --git a/tests/ui/attributes/args-checked.rs b/tests/ui/attributes/args-checked.rs index 49cf2bdbd03e0..5a1eb34207c5e 100644 --- a/tests/ui/attributes/args-checked.rs +++ b/tests/ui/attributes/args-checked.rs @@ -38,4 +38,10 @@ macro_rules! m { //~^ ERROR `rustc_allow_const_fn_unstable` expects feature names #[rustc_allow_const_fn_unstable(x(x, y, z))] //~^ ERROR `rustc_allow_const_fn_unstable` expects feature names -const fn g() {} \ No newline at end of file +const fn g() {} + +#[used(always = 5)] +//~^ ERROR malformed +#[used(always(x, y, z))] +//~^ ERROR malformed +static H: u64 = 5; \ No newline at end of file diff --git a/tests/ui/attributes/args-checked.stderr b/tests/ui/attributes/args-checked.stderr index 8d9359dd25e8b..2bc167358396c 100644 --- a/tests/ui/attributes/args-checked.stderr +++ b/tests/ui/attributes/args-checked.stderr @@ -168,6 +168,46 @@ error: `rustc_allow_const_fn_unstable` expects feature names LL | #[rustc_allow_const_fn_unstable(x(x, y, z))] | ^^^^^^^^^^ +error[E0539]: malformed `used` attribute input + --> $DIR/args-checked.rs:43:1 + | +LL | #[used(always = 5)] + | ^^^^^^^----------^^ + | | + | valid arguments are `compiler` or `linker` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[used(always = 5)] +LL + #[used(compiler)] + | +LL - #[used(always = 5)] +LL + #[used(linker)] + | +LL - #[used(always = 5)] +LL + #[used] + | + +error[E0539]: malformed `used` attribute input + --> $DIR/args-checked.rs:45:1 + | +LL | #[used(always(x, y, z))] + | ^^^^^^^---------------^^ + | | + | valid arguments are `compiler` or `linker` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[used(always(x, y, z))] +LL + #[used(compiler)] + | +LL - #[used(always(x, y, z))] +LL + #[used(linker)] + | +LL - #[used(always(x, y, z))] +LL + #[used] + | + error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` --> $DIR/args-checked.rs:27:1 | @@ -187,7 +227,7 @@ LL | #[macro_export(local_inner_macros(x, y, z))] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 -error: aborting due to 13 previous errors +error: aborting due to 15 previous errors For more information about this error, try `rustc --explain E0539`. Future incompatibility report: Future breakage diagnostic: From 6c7f6013e013b9fd978d2f67ed5d75cdf6a11e15 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 12 Apr 2026 12:44:39 +0200 Subject: [PATCH 14/23] Properly check arguments of `#[rustc_must_implement_one_of]` --- .../src/attributes/rustc_internal.rs | 2 +- tests/ui/attributes/args-checked.rs | 10 ++++++- tests/ui/attributes/args-checked.stderr | 30 ++++++++++++++++++- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 8a648550ae8c6..f124a737e3917 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -43,7 +43,7 @@ impl SingleAttributeParser for RustcMustImplementOneOfParser { let mut errored = false; for argument in inputs { - let Some(meta) = argument.meta_item() else { + let Some(meta) = argument.meta_item_no_args() else { cx.adcx().expected_identifier(argument.span()); return None; }; diff --git a/tests/ui/attributes/args-checked.rs b/tests/ui/attributes/args-checked.rs index 5a1eb34207c5e..bf2624692a1b1 100644 --- a/tests/ui/attributes/args-checked.rs +++ b/tests/ui/attributes/args-checked.rs @@ -44,4 +44,12 @@ const fn g() {} //~^ ERROR malformed #[used(always(x, y, z))] //~^ ERROR malformed -static H: u64 = 5; \ No newline at end of file +static H: u64 = 5; + +#[rustc_must_implement_one_of(eq = 5, neq)] +//~^ ERROR malformed +#[rustc_must_implement_one_of(eq(x, y, z), neq)] +//~^ ERROR malformed +trait T { + +} \ No newline at end of file diff --git a/tests/ui/attributes/args-checked.stderr b/tests/ui/attributes/args-checked.stderr index 2bc167358396c..4e31329cf7d62 100644 --- a/tests/ui/attributes/args-checked.stderr +++ b/tests/ui/attributes/args-checked.stderr @@ -208,6 +208,34 @@ LL - #[used(always(x, y, z))] LL + #[used] | +error[E0565]: malformed `rustc_must_implement_one_of` attribute input + --> $DIR/args-checked.rs:49:1 + | +LL | #[rustc_must_implement_one_of(eq = 5, neq)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------^^^^^^^ + | | + | expected a valid identifier here + | +help: must be of the form + | +LL - #[rustc_must_implement_one_of(eq = 5, neq)] +LL + #[rustc_must_implement_one_of(function1, function2, ...)] + | + +error[E0565]: malformed `rustc_must_implement_one_of` attribute input + --> $DIR/args-checked.rs:51:1 + | +LL | #[rustc_must_implement_one_of(eq(x, y, z), neq)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^^^^ + | | + | expected a valid identifier here + | +help: must be of the form + | +LL - #[rustc_must_implement_one_of(eq(x, y, z), neq)] +LL + #[rustc_must_implement_one_of(function1, function2, ...)] + | + error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` --> $DIR/args-checked.rs:27:1 | @@ -227,7 +255,7 @@ LL | #[macro_export(local_inner_macros(x, y, z))] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 -error: aborting due to 15 previous errors +error: aborting due to 17 previous errors For more information about this error, try `rustc --explain E0539`. Future incompatibility report: Future breakage diagnostic: From 2b72962aa494d35899097a97702fc7b5a51c2ec1 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 12 Apr 2026 12:45:39 +0200 Subject: [PATCH 15/23] Properly check arguments of `#[rustc_dump_layout]` --- .../src/attributes/rustc_dump.rs | 2 +- tests/ui/attributes/args-checked.rs | 8 +++++++ tests/ui/attributes/args-checked.stderr | 21 +++++++++++++++++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs index 8d507065dbdb6..4adbcbbdf6587 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -98,7 +98,7 @@ impl CombineAttributeParser for RustcDumpLayoutParser { let mut result = Vec::new(); for item in items.mixed() { - let Some(arg) = item.meta_item() else { + let Some(arg) = item.meta_item_no_args() else { cx.adcx().expected_not_literal(item.span()); continue; }; diff --git a/tests/ui/attributes/args-checked.rs b/tests/ui/attributes/args-checked.rs index bf2624692a1b1..e3a9a0b21b993 100644 --- a/tests/ui/attributes/args-checked.rs +++ b/tests/ui/attributes/args-checked.rs @@ -52,4 +52,12 @@ static H: u64 = 5; //~^ ERROR malformed trait T { +} + +#[rustc_dump_layout(debug = 5)] +//~^ ERROR malformed +#[rustc_dump_layout(debug(x, y, z))] +//~^ ERROR malformed +enum E { + } \ No newline at end of file diff --git a/tests/ui/attributes/args-checked.stderr b/tests/ui/attributes/args-checked.stderr index 4e31329cf7d62..fdaf49d25f83d 100644 --- a/tests/ui/attributes/args-checked.stderr +++ b/tests/ui/attributes/args-checked.stderr @@ -236,6 +236,22 @@ LL - #[rustc_must_implement_one_of(eq(x, y, z), neq)] LL + #[rustc_must_implement_one_of(function1, function2, ...)] | +error[E0565]: malformed `rustc_dump_layout` attribute input + --> $DIR/args-checked.rs:57:1 + | +LL | #[rustc_dump_layout(debug = 5)] + | ^^^^^^^^^^^^^^^^^^^^---------^^ + | | + | didn't expect a literal here + +error[E0565]: malformed `rustc_dump_layout` attribute input + --> $DIR/args-checked.rs:59:1 + | +LL | #[rustc_dump_layout(debug(x, y, z))] + | ^^^^^^^^^^^^^^^^^^^^--------------^^ + | | + | didn't expect a literal here + error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` --> $DIR/args-checked.rs:27:1 | @@ -255,9 +271,10 @@ LL | #[macro_export(local_inner_macros(x, y, z))] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 -error: aborting due to 17 previous errors +error: aborting due to 19 previous errors -For more information about this error, try `rustc --explain E0539`. +Some errors have detailed explanations: E0539, E0565. +For more information about an error, try `rustc --explain E0539`. Future incompatibility report: Future breakage diagnostic: error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` --> $DIR/args-checked.rs:27:1 From 29b5a168e06bd338fe2003d07a6e2932d7975e81 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 12 Apr 2026 12:47:59 +0200 Subject: [PATCH 16/23] Properly check arguments of query dep graph attrs --- compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index f124a737e3917..3192f9c767fc1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -820,7 +820,7 @@ impl SingleAttributeParser for RustcIfThisChangedParser { ArgParser::NoArgs => Some(AttributeKind::RustcIfThisChanged(cx.attr_span, None)), ArgParser::List(list) => { let item = cx.expect_single(list)?; - let Some(ident) = item.meta_item().and_then(|item| item.ident()) else { + let Some(ident) = item.meta_item_no_args().and_then(|item| item.ident()) else { cx.adcx().expected_identifier(item.span()); return None; }; @@ -878,7 +878,7 @@ impl CombineAttributeParser for RustcThenThisWouldNeedParser { cx.emit_err(AttributeRequiresOpt { span: cx.attr_span, opt: "-Z query-dep-graph" }); } let item = cx.expect_single_element_list(args, cx.attr_span)?; - let Some(ident) = item.meta_item().and_then(|item| item.ident()) else { + let Some(ident) = item.meta_item_no_args().and_then(|item| item.ident()) else { cx.adcx().expected_identifier(item.span()); return None; }; From 5bee968f527c319956288703baab935c8839bef6 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 12 Apr 2026 12:48:46 +0200 Subject: [PATCH 17/23] Properly check arguments of `#[rustc_abi]` --- .../src/attributes/test_attrs.rs | 2 +- tests/ui/attributes/args-checked.rs | 4 ++ tests/ui/attributes/args-checked.stderr | 60 +++++++++++++++---- 3 files changed, 52 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index 7ffeb3d2194a3..022fe3e5f75ee 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -123,7 +123,7 @@ impl SingleAttributeParser for RustcAbiParser { let mut fail_incorrect_argument = |span| cx.adcx().expected_specific_argument(span, &[sym::assert_eq, sym::debug]); - let Some(arg) = arg.meta_item() else { + let Some(arg) = arg.meta_item_no_args() else { fail_incorrect_argument(args.span); return None; }; diff --git a/tests/ui/attributes/args-checked.rs b/tests/ui/attributes/args-checked.rs index e3a9a0b21b993..76cf87e1e6f2d 100644 --- a/tests/ui/attributes/args-checked.rs +++ b/tests/ui/attributes/args-checked.rs @@ -20,6 +20,10 @@ //~^ ERROR malformed #[coverage(off(x, y, z))] //~^ ERROR malformed +#[rustc_abi(debug = 5)] +//~^ ERROR malformed +#[rustc_abi(debug(x, y, z))] +//~^ ERROR malformed fn main() { } diff --git a/tests/ui/attributes/args-checked.stderr b/tests/ui/attributes/args-checked.stderr index fdaf49d25f83d..21c68f24baf5a 100644 --- a/tests/ui/attributes/args-checked.stderr +++ b/tests/ui/attributes/args-checked.stderr @@ -156,20 +156,54 @@ LL - #[coverage(off(x, y, z))] LL + #[coverage(on)] | +error[E0539]: malformed `rustc_abi` attribute input + --> $DIR/args-checked.rs:23:1 + | +LL | #[rustc_abi(debug = 5)] + | ^^^^^^^^^^^-----------^ + | | + | valid arguments are `assert_eq` or `debug` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[rustc_abi(debug = 5)] +LL + #[rustc_abi(assert_eq)] + | +LL - #[rustc_abi(debug = 5)] +LL + #[rustc_abi(debug)] + | + +error[E0539]: malformed `rustc_abi` attribute input + --> $DIR/args-checked.rs:25:1 + | +LL | #[rustc_abi(debug(x, y, z))] + | ^^^^^^^^^^^----------------^ + | | + | valid arguments are `assert_eq` or `debug` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[rustc_abi(debug(x, y, z))] +LL + #[rustc_abi(assert_eq)] + | +LL - #[rustc_abi(debug(x, y, z))] +LL + #[rustc_abi(debug)] + | + error: `rustc_allow_const_fn_unstable` expects feature names - --> $DIR/args-checked.rs:37:33 + --> $DIR/args-checked.rs:41:33 | LL | #[rustc_allow_const_fn_unstable(x = 5)] | ^^^^^ error: `rustc_allow_const_fn_unstable` expects feature names - --> $DIR/args-checked.rs:39:33 + --> $DIR/args-checked.rs:43:33 | LL | #[rustc_allow_const_fn_unstable(x(x, y, z))] | ^^^^^^^^^^ error[E0539]: malformed `used` attribute input - --> $DIR/args-checked.rs:43:1 + --> $DIR/args-checked.rs:47:1 | LL | #[used(always = 5)] | ^^^^^^^----------^^ @@ -189,7 +223,7 @@ LL + #[used] | error[E0539]: malformed `used` attribute input - --> $DIR/args-checked.rs:45:1 + --> $DIR/args-checked.rs:49:1 | LL | #[used(always(x, y, z))] | ^^^^^^^---------------^^ @@ -209,7 +243,7 @@ LL + #[used] | error[E0565]: malformed `rustc_must_implement_one_of` attribute input - --> $DIR/args-checked.rs:49:1 + --> $DIR/args-checked.rs:53:1 | LL | #[rustc_must_implement_one_of(eq = 5, neq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------^^^^^^^ @@ -223,7 +257,7 @@ LL + #[rustc_must_implement_one_of(function1, function2, ...)] | error[E0565]: malformed `rustc_must_implement_one_of` attribute input - --> $DIR/args-checked.rs:51:1 + --> $DIR/args-checked.rs:55:1 | LL | #[rustc_must_implement_one_of(eq(x, y, z), neq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^^^^ @@ -237,7 +271,7 @@ LL + #[rustc_must_implement_one_of(function1, function2, ...)] | error[E0565]: malformed `rustc_dump_layout` attribute input - --> $DIR/args-checked.rs:57:1 + --> $DIR/args-checked.rs:61:1 | LL | #[rustc_dump_layout(debug = 5)] | ^^^^^^^^^^^^^^^^^^^^---------^^ @@ -245,7 +279,7 @@ LL | #[rustc_dump_layout(debug = 5)] | didn't expect a literal here error[E0565]: malformed `rustc_dump_layout` attribute input - --> $DIR/args-checked.rs:59:1 + --> $DIR/args-checked.rs:63:1 | LL | #[rustc_dump_layout(debug(x, y, z))] | ^^^^^^^^^^^^^^^^^^^^--------------^^ @@ -253,7 +287,7 @@ LL | #[rustc_dump_layout(debug(x, y, z))] | didn't expect a literal here error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` - --> $DIR/args-checked.rs:27:1 + --> $DIR/args-checked.rs:31:1 | LL | #[macro_export(local_inner_macros = 5)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -263,7 +297,7 @@ LL | #[macro_export(local_inner_macros = 5)] = note: `#[deny(invalid_macro_export_arguments)]` (part of `#[deny(future_incompatible)]`) on by default error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` - --> $DIR/args-checked.rs:30:1 + --> $DIR/args-checked.rs:34:1 | LL | #[macro_export(local_inner_macros(x, y, z))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -271,13 +305,13 @@ LL | #[macro_export(local_inner_macros(x, y, z))] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 -error: aborting due to 19 previous errors +error: aborting due to 21 previous errors Some errors have detailed explanations: E0539, E0565. For more information about an error, try `rustc --explain E0539`. Future incompatibility report: Future breakage diagnostic: error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` - --> $DIR/args-checked.rs:27:1 + --> $DIR/args-checked.rs:31:1 | LL | #[macro_export(local_inner_macros = 5)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -288,7 +322,7 @@ LL | #[macro_export(local_inner_macros = 5)] Future breakage diagnostic: error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` - --> $DIR/args-checked.rs:30:1 + --> $DIR/args-checked.rs:34:1 | LL | #[macro_export(local_inner_macros(x, y, z))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 3fcbca4707c0a679eb1d1b68acf6c8119af45fdc Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 12 Apr 2026 12:49:44 +0200 Subject: [PATCH 18/23] Properly check arguments of `#[test_runner]` --- .../src/attributes/test_attrs.rs | 2 +- tests/ui/attributes/args-checked.rs | 8 +- tests/ui/attributes/args-checked.stderr | 78 +++++++++++++------ 3 files changed, 61 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index 022fe3e5f75ee..eeee6eff00931 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -173,7 +173,7 @@ impl SingleAttributeParser for TestRunnerParser { fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { let single = cx.expect_single_element_list(args, cx.attr_span)?; - let Some(meta) = single.meta_item() else { + let Some(meta) = single.meta_item_no_args() else { cx.adcx().expected_not_literal(single.span()); return None; }; diff --git a/tests/ui/attributes/args-checked.rs b/tests/ui/attributes/args-checked.rs index 76cf87e1e6f2d..18369acfea034 100644 --- a/tests/ui/attributes/args-checked.rs +++ b/tests/ui/attributes/args-checked.rs @@ -1,8 +1,14 @@ #![feature(rustc_attrs)] #![feature(optimize_attribute)] #![feature(coverage_attribute)] +#![feature(custom_test_frameworks)] #![allow(unused_attributes)] +#![test_runner(x = 5)] +//~^ ERROR malformed +#![test_runner(x(x,y,z))] +//~^ ERROR malformed + #[inline(always = 5)] //~^ ERROR malformed #[inline(always(x, y, z))] @@ -64,4 +70,4 @@ trait T { //~^ ERROR malformed enum E { -} \ No newline at end of file +} diff --git a/tests/ui/attributes/args-checked.stderr b/tests/ui/attributes/args-checked.stderr index 21c68f24baf5a..277dd672fef22 100644 --- a/tests/ui/attributes/args-checked.stderr +++ b/tests/ui/attributes/args-checked.stderr @@ -1,5 +1,33 @@ +error[E0565]: malformed `test_runner` attribute input + --> $DIR/args-checked.rs:7:1 + | +LL | #![test_runner(x = 5)] + | ^^^^^^^^^^^^^^^-----^^ + | | + | didn't expect a literal here + | +help: must be of the form + | +LL - #![test_runner(x = 5)] +LL + #![test_runner(path)] + | + +error[E0565]: malformed `test_runner` attribute input + --> $DIR/args-checked.rs:9:1 + | +LL | #![test_runner(x(x,y,z))] + | ^^^^^^^^^^^^^^^--------^^ + | | + | didn't expect a literal here + | +help: must be of the form + | +LL - #![test_runner(x(x,y,z))] +LL + #![test_runner(path)] + | + error[E0539]: malformed `inline` attribute input - --> $DIR/args-checked.rs:6:1 + --> $DIR/args-checked.rs:12:1 | LL | #[inline(always = 5)] | ^^^^^^^^^----------^^ @@ -20,7 +48,7 @@ LL + #[inline] | error[E0539]: malformed `inline` attribute input - --> $DIR/args-checked.rs:8:1 + --> $DIR/args-checked.rs:14:1 | LL | #[inline(always(x, y, z))] | ^^^^^^^^^---------------^^ @@ -41,7 +69,7 @@ LL + #[inline] | error[E0539]: malformed `instruction_set` attribute input - --> $DIR/args-checked.rs:10:1 + --> $DIR/args-checked.rs:16:1 | LL | #[instruction_set(arm::a32 = 5)] | ^^^^^^^^^^^^^^^^^^------------^^ @@ -56,7 +84,7 @@ LL + #[instruction_set(set)] | error[E0539]: malformed `instruction_set` attribute input - --> $DIR/args-checked.rs:12:1 + --> $DIR/args-checked.rs:18:1 | LL | #[instruction_set(arm::a32(x, y, z))] | ^^^^^^^^^^^^^^^^^^-----------------^^ @@ -71,7 +99,7 @@ LL + #[instruction_set(set)] | error[E0539]: malformed `optimize` attribute input - --> $DIR/args-checked.rs:14:1 + --> $DIR/args-checked.rs:20:1 | LL | #[optimize(size = 5)] | ^^^^^^^^^^^--------^^ @@ -91,7 +119,7 @@ LL + #[optimize(speed)] | error[E0539]: malformed `optimize` attribute input - --> $DIR/args-checked.rs:16:1 + --> $DIR/args-checked.rs:22:1 | LL | #[optimize(size(x, y, z))] | ^^^^^^^^^^^-------------^^ @@ -111,19 +139,19 @@ LL + #[optimize(speed)] | error: multiple `optimize` attributes - --> $DIR/args-checked.rs:16:1 + --> $DIR/args-checked.rs:22:1 | LL | #[optimize(size(x, y, z))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/args-checked.rs:14:1 + --> $DIR/args-checked.rs:20:1 | LL | #[optimize(size = 5)] | ^^^^^^^^^^^^^^^^^^^^^ error[E0539]: malformed `coverage` attribute input - --> $DIR/args-checked.rs:19:1 + --> $DIR/args-checked.rs:25:1 | LL | #[coverage(off = 5)] | ^^^^^^^^^^^-------^^ @@ -140,7 +168,7 @@ LL + #[coverage(on)] | error[E0539]: malformed `coverage` attribute input - --> $DIR/args-checked.rs:21:1 + --> $DIR/args-checked.rs:27:1 | LL | #[coverage(off(x, y, z))] | ^^^^^^^^^^^------------^^ @@ -157,7 +185,7 @@ LL + #[coverage(on)] | error[E0539]: malformed `rustc_abi` attribute input - --> $DIR/args-checked.rs:23:1 + --> $DIR/args-checked.rs:29:1 | LL | #[rustc_abi(debug = 5)] | ^^^^^^^^^^^-----------^ @@ -174,7 +202,7 @@ LL + #[rustc_abi(debug)] | error[E0539]: malformed `rustc_abi` attribute input - --> $DIR/args-checked.rs:25:1 + --> $DIR/args-checked.rs:31:1 | LL | #[rustc_abi(debug(x, y, z))] | ^^^^^^^^^^^----------------^ @@ -191,19 +219,19 @@ LL + #[rustc_abi(debug)] | error: `rustc_allow_const_fn_unstable` expects feature names - --> $DIR/args-checked.rs:41:33 + --> $DIR/args-checked.rs:47:33 | LL | #[rustc_allow_const_fn_unstable(x = 5)] | ^^^^^ error: `rustc_allow_const_fn_unstable` expects feature names - --> $DIR/args-checked.rs:43:33 + --> $DIR/args-checked.rs:49:33 | LL | #[rustc_allow_const_fn_unstable(x(x, y, z))] | ^^^^^^^^^^ error[E0539]: malformed `used` attribute input - --> $DIR/args-checked.rs:47:1 + --> $DIR/args-checked.rs:53:1 | LL | #[used(always = 5)] | ^^^^^^^----------^^ @@ -223,7 +251,7 @@ LL + #[used] | error[E0539]: malformed `used` attribute input - --> $DIR/args-checked.rs:49:1 + --> $DIR/args-checked.rs:55:1 | LL | #[used(always(x, y, z))] | ^^^^^^^---------------^^ @@ -243,7 +271,7 @@ LL + #[used] | error[E0565]: malformed `rustc_must_implement_one_of` attribute input - --> $DIR/args-checked.rs:53:1 + --> $DIR/args-checked.rs:59:1 | LL | #[rustc_must_implement_one_of(eq = 5, neq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------^^^^^^^ @@ -257,7 +285,7 @@ LL + #[rustc_must_implement_one_of(function1, function2, ...)] | error[E0565]: malformed `rustc_must_implement_one_of` attribute input - --> $DIR/args-checked.rs:55:1 + --> $DIR/args-checked.rs:61:1 | LL | #[rustc_must_implement_one_of(eq(x, y, z), neq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^^^^ @@ -271,7 +299,7 @@ LL + #[rustc_must_implement_one_of(function1, function2, ...)] | error[E0565]: malformed `rustc_dump_layout` attribute input - --> $DIR/args-checked.rs:61:1 + --> $DIR/args-checked.rs:67:1 | LL | #[rustc_dump_layout(debug = 5)] | ^^^^^^^^^^^^^^^^^^^^---------^^ @@ -279,7 +307,7 @@ LL | #[rustc_dump_layout(debug = 5)] | didn't expect a literal here error[E0565]: malformed `rustc_dump_layout` attribute input - --> $DIR/args-checked.rs:63:1 + --> $DIR/args-checked.rs:69:1 | LL | #[rustc_dump_layout(debug(x, y, z))] | ^^^^^^^^^^^^^^^^^^^^--------------^^ @@ -287,7 +315,7 @@ LL | #[rustc_dump_layout(debug(x, y, z))] | didn't expect a literal here error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` - --> $DIR/args-checked.rs:31:1 + --> $DIR/args-checked.rs:37:1 | LL | #[macro_export(local_inner_macros = 5)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -297,7 +325,7 @@ LL | #[macro_export(local_inner_macros = 5)] = note: `#[deny(invalid_macro_export_arguments)]` (part of `#[deny(future_incompatible)]`) on by default error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` - --> $DIR/args-checked.rs:34:1 + --> $DIR/args-checked.rs:40:1 | LL | #[macro_export(local_inner_macros(x, y, z))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -305,13 +333,13 @@ LL | #[macro_export(local_inner_macros(x, y, z))] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 -error: aborting due to 21 previous errors +error: aborting due to 23 previous errors Some errors have detailed explanations: E0539, E0565. For more information about an error, try `rustc --explain E0539`. Future incompatibility report: Future breakage diagnostic: error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` - --> $DIR/args-checked.rs:31:1 + --> $DIR/args-checked.rs:37:1 | LL | #[macro_export(local_inner_macros = 5)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -322,7 +350,7 @@ LL | #[macro_export(local_inner_macros = 5)] Future breakage diagnostic: error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` - --> $DIR/args-checked.rs:34:1 + --> $DIR/args-checked.rs:40:1 | LL | #[macro_export(local_inner_macros(x, y, z))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From dfc475d018c780475ea962f15d86cfa05a50a148 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 31 May 2026 13:19:56 -0700 Subject: [PATCH 19/23] cg_ssa: a bit less `immediate_or_packed_pair` This is one of the things that made cg_clif not use cg_ssa, IIRC, so let's take the opportunities to avoid it where we can. --- compiler/rustc_codegen_ssa/src/mir/block.rs | 3 ++- compiler/rustc_codegen_ssa/src/mir/mod.rs | 9 ++++++--- compiler/rustc_codegen_ssa/src/mir/operand.rs | 6 ++++++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index b6b95c5f12aae..0eaad18430c2b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1737,7 +1737,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { op.store_with_annotation(bx, scratch); (scratch.val.llval, scratch.val.align, true) } - _ => (op.immediate_or_packed_pair(bx), arg.layout.align.abi, false), + PassMode::Direct(_) => (op.immediate(), arg.layout.align.abi, false), + PassMode::Ignore | PassMode::Pair(..) => unreachable!("handled above"), }, Ref(op_place_val) => match arg.mode { PassMode::Indirect { attrs, on_stack, .. } => { diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 4bcf037ecce07..0abdef85b1980 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -499,9 +499,12 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( PassMode::Direct(_) => { let llarg = bx.get_param(llarg_idx); llarg_idx += 1; - return local(OperandRef::from_immediate_or_packed_pair( - bx, llarg, arg.layout, - )); + debug_assert!(bx.is_backend_immediate(arg.layout)); + return local(OperandRef { + val: OperandValue::Immediate(llarg), + layout: arg.layout, + move_annotation: None, + }); } PassMode::Pair(..) => { let (a, b) = (bx.get_param(llarg_idx), bx.get_param(llarg_idx + 1)); diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index c0c71edd4d905..68a84ebdae9fc 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -306,6 +306,9 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { /// If this operand is a `Pair`, we return an aggregate with the two values. /// For other cases, see `immediate`. + /// + /// Note: The use of this is discouraged outside cg_llvm, as some other backends + /// don't natively support packing multiple things into one like this. pub fn immediate_or_packed_pair>( self, bx: &mut Bx, @@ -324,6 +327,9 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { } /// If the type is a pair, we return a `Pair`, otherwise, an `Immediate`. + /// + /// Note: The use of this is discouraged outside cg_llvm, as some other backends + /// don't natively support packing multiple things into one like this. pub fn from_immediate_or_packed_pair>( bx: &mut Bx, llval: V, From a96cc82f159d32a00e6169074689d2a0f126a206 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 May 2026 14:23:15 +0200 Subject: [PATCH 20/23] miri: require (almost) all 1-ZST arguments to be actually passed --- .../rustc_const_eval/src/interpret/call.rs | 86 +++++++++++-------- .../tests/fail/c-variadic-ignored-argument.rs | 13 +++ .../fail/c-variadic-ignored-argument.stderr | 18 ++++ .../abi_mismatch_closure_non_capturing.rs | 19 ++++ .../abi_mismatch_closure_non_capturing.stderr | 26 ++++++ .../tests/fail/validity/fn_arg_never_type.rs | 13 +++ .../fail/validity/fn_arg_never_type.stderr | 18 ++++ .../tests/pass/c-variadic-ignored-argument.rs | 21 ----- .../tests/pass/function_calls/abi_compat.rs | 5 ++ 9 files changed, 164 insertions(+), 55 deletions(-) create mode 100644 src/tools/miri/tests/fail/c-variadic-ignored-argument.rs create mode 100644 src/tools/miri/tests/fail/c-variadic-ignored-argument.stderr create mode 100644 src/tools/miri/tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs create mode 100644 src/tools/miri/tests/fail/function_pointers/abi_mismatch_closure_non_capturing.stderr create mode 100644 src/tools/miri/tests/fail/validity/fn_arg_never_type.rs create mode 100644 src/tools/miri/tests/fail/validity/fn_arg_never_type.stderr delete mode 100644 src/tools/miri/tests/pass/c-variadic-ignored-argument.rs diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 6aa88b86e4e60..40ba31d37f2f0 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -272,8 +272,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { caller_args: &mut impl Iterator< Item = (&'x FnArg<'tcx, M::Provenance>, &'y ArgAbi<'tcx, Ty<'tcx>>), >, - callee_abi: &ArgAbi<'tcx, Ty<'tcx>>, - callee_arg_idx: usize, + callee_args_abis: &mut impl Iterator>)>, callee_arg: &mir::Place<'tcx>, callee_ty: Ty<'tcx>, already_live: bool, @@ -282,15 +281,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { 'tcx: 'x, 'tcx: 'y, { + // Get next callee arg. + let (callee_arg_idx, callee_abi) = callee_args_abis.next().unwrap(); assert_eq!(callee_ty, callee_abi.layout.ty); - if callee_abi.is_ignore() { - // This one is skipped. Still must be made live though! - if !already_live { - self.storage_live(callee_arg.as_local().unwrap())?; - } - return interp_ok(()); - } - // Find next caller arg. + // Get next caller arg. let Some((caller_arg, caller_abi)) = caller_args.next() else { throw_ub_format!("calling a function with fewer arguments than it requires"); }; @@ -348,6 +342,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { mut cont: ReturnContinuation, ) -> InterpResult<'tcx> { let _trace = enter_trace_span!(M, step::init_stack_frame, %instance, tracing_separate_thread = Empty); + let def_id = instance.def_id(); // The first order of business is to figure out the callee signature. // However, that requires the list of variadic arguments. @@ -423,10 +418,25 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { "spread_arg: {:?}, locals: {:#?}", body.spread_arg, body.args_iter() - .map(|local| (local, self.layout_of_local(self.frame(), local, None).unwrap().ty,)) + .map(|local| (local, self.layout_of_local(self.frame(), local, None).unwrap().ty)) .collect::>() ); + // Determine whether there is a special VaList argument. This is always the + // last argument, and since arguments start at index 1 that's `arg_count`. + let va_list_arg = callee_fn_abi.c_variadic.then(|| mir::Local::from_usize(body.arg_count)); + // Determine whether this is a non-capturing closure. That's relevant as their first + // argument can be skipped (and that's the only kind of argument skipping we allow). + let is_non_capturing_closure = + (matches!(instance.def, ty::InstanceKind::ClosureOnceShim { .. }) + || self.tcx.is_closure_like(def_id)) + && { + let arg = &callee_fn_abi.args[0]; + matches!(arg.layout.ty.kind(), ty::Closure (_def, closure_args) if { + closure_args.as_closure().upvar_tys().is_empty() + }) + }; + // In principle, we have two iterators: Where the arguments come from, and where // they go to. @@ -439,21 +449,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { caller_fn_abi.args.len(), "mismatch between caller ABI and caller arguments", ); - let mut caller_args = args - .iter() - .zip(caller_fn_abi.args.iter()) - .filter(|arg_and_abi| !arg_and_abi.1.is_ignore()); + let mut caller_args = args.iter().zip(caller_fn_abi.args.iter()); // Now we have to spread them out across the callee's locals, // taking into account the `spread_arg`. If we could write // this is a single iterator (that handles `spread_arg`), then - // `pass_argument` would be the loop body. It takes care to - // not advance `caller_iter` for ignored arguments. + // `pass_argument` would be the loop body. let mut callee_args_abis = callee_fn_abi.args.iter().enumerate(); - // Determine whether there is a special VaList argument. This is always the - // last argument, and since arguments start at index 1 that's `arg_count`. - let va_list_arg = callee_fn_abi.c_variadic.then(|| mir::Local::from_usize(body.arg_count)); - // During argument passing, we want retagging with protectors. M::with_retag_mode(self, RetagMode::FnEntry, |ecx| { for local in body.args_iter() { @@ -466,7 +468,32 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // type, but the result gets cached so this avoids calling the instantiation // query *again* the next time this local is accessed. let ty = ecx.layout_of_local(ecx.frame(), local, None)?.ty; - if Some(local) == va_list_arg { + + // Some arguments are special: the first (`self`) argument of a non-capturing + // closure; the va_list argument; and the spread_arg. + if is_non_capturing_closure && local == mir::Local::arg(0) { + assert!(va_list_arg.is_none()); + assert!(Some(local) != body.spread_arg); + // This argument might be missing on the caller side. So just initialize it in + // the callee. + let (callee_arg_idx, callee_abi) = callee_args_abis.next().unwrap(); + assert!(callee_abi.layout.is_1zst() && callee_abi.is_ignore()); + ecx.storage_live(local)?; + // And skip it in the caller, if present. We can tell whether it is present by + // comparing the number of arguments on the caller and callee side. + if caller_fn_abi.args.len() == callee_fn_abi.args.len() { + let (_caller_arg, caller_abi) = caller_args.next().unwrap(); + if !caller_abi.layout.is_1zst() { + // The caller gave us some other, non-ignorable argument. + throw_ub!(AbiMismatchArgument { + arg_idx: callee_arg_idx, + caller_ty: caller_abi.layout.ty, + callee_ty: callee_abi.layout.ty + }); + } + assert!(caller_abi.is_ignore()); + } + } else if Some(local) == va_list_arg { // This is the last callee-side argument of a variadic function. // This argument is a VaList holding the remaining caller-side arguments. ecx.storage_live(local)?; @@ -476,12 +503,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Consume the remaining arguments by putting them into the variable argument // list. - let varargs = ecx.allocate_varargs( - &mut caller_args, - // "Ignored" arguments aren't actually passed, so the callee should also - // ignore them. (`pass_argument` does this for regular arguments.) - (&mut callee_args_abis).filter(|(_, abi)| !abi.is_ignore()), - )?; + let varargs = ecx.allocate_varargs(&mut caller_args, &mut callee_args_abis)?; // When the frame is dropped, these variable arguments are deallocated. ecx.frame_mut().va_list = varargs.clone(); let key = ecx.va_list_ptr(varargs.into()); @@ -507,11 +529,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { &[mir::ProjectionElem::Field(FieldIdx::from_usize(i), field_ty)], *ecx.tcx, ); - let (idx, callee_abi) = callee_args_abis.next().unwrap(); ecx.pass_argument( &mut caller_args, - callee_abi, - idx, + &mut callee_args_abis, &dest, field_ty, /* already_live */ true, @@ -519,11 +539,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } else { // Normal argument. Cannot mark it as live yet, it might be unsized! - let (idx, callee_abi) = callee_args_abis.next().unwrap(); ecx.pass_argument( &mut caller_args, - callee_abi, - idx, + &mut callee_args_abis, &dest, ty, /* already_live */ false, diff --git a/src/tools/miri/tests/fail/c-variadic-ignored-argument.rs b/src/tools/miri/tests/fail/c-variadic-ignored-argument.rs new file mode 100644 index 0000000000000..77dab904fdbba --- /dev/null +++ b/src/tools/miri/tests/fail/c-variadic-ignored-argument.rs @@ -0,0 +1,13 @@ +#![feature(c_variadic)] + +// While 1-ZST are currently ignored on most ABIs, we don't guarantee that, and it's UB to +// rely on it. + +fn main() { + unsafe extern "C" fn variadic(mut ap: ...) { + ap.next_arg::(); + ap.next_arg::(); //~ERROR: requested `i32` is incompatible with next argument of type `()` + } + + unsafe { variadic(0i32, (), 1i32) } +} diff --git a/src/tools/miri/tests/fail/c-variadic-ignored-argument.stderr b/src/tools/miri/tests/fail/c-variadic-ignored-argument.stderr new file mode 100644 index 0000000000000..6c1291611c4ae --- /dev/null +++ b/src/tools/miri/tests/fail/c-variadic-ignored-argument.stderr @@ -0,0 +1,18 @@ +error: Undefined Behavior: va_arg type mismatch: requested `i32` is incompatible with next argument of type `()` + --> tests/fail/c-variadic-ignored-argument.rs:LL:CC + | +LL | ap.next_arg::(); + | ^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: stack backtrace: + 0: main::variadic + at tests/fail/c-variadic-ignored-argument.rs:LL:CC + 1: main + at tests/fail/c-variadic-ignored-argument.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs new file mode 100644 index 0000000000000..064b5a510f3ea --- /dev/null +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs @@ -0,0 +1,19 @@ +#![feature(fn_traits, unboxed_closures)] + +use std::mem::transmute; + +#[repr(align(4))] +struct Zst; + +fn foo(_: F) { + // Calls the given F FnOnce, but passing an over-aligned ZST instead of the closure / function item + let f = unsafe { transmute::(F::call_once) }; + f(Zst) +} + +fn main() { + foo(move || { + //~^ERROR: /calling a function whose parameter #1 has type .* passing argument of type Zst/ + println!("non-capturing closure"); + }); +} diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_closure_non_capturing.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_closure_non_capturing.stderr new file mode 100644 index 0000000000000..56f56e606f79d --- /dev/null +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_closure_non_capturing.stderr @@ -0,0 +1,26 @@ +error: Undefined Behavior: calling a function whose parameter #1 has type {closure@tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs:LL:CC} passing argument of type Zst + --> tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs:LL:CC + | +LL | foo(move || { + | _________^ +LL | | +LL | | println!("non-capturing closure"); +LL | | }); + | |_____^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets + = help: if you think this code should be accepted anyway, please report an issue with Miri + = note: stack backtrace: + 0: main::{closure#0} + at tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs:LL:CC + 1: foo::<{closure@tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs:LL:CC}> + at tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs:LL:CC + 2: main + at tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/validity/fn_arg_never_type.rs b/src/tools/miri/tests/fail/validity/fn_arg_never_type.rs new file mode 100644 index 0000000000000..a6ffb325191b0 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/fn_arg_never_type.rs @@ -0,0 +1,13 @@ +use std::mem::transmute; + +enum Never {} + +fn foo(x: Never) { //~ERROR: invalid value of type Never + let ptr = &raw const x; + println!("{ptr:p}"); +} + +fn main() { + let f = unsafe { transmute::(foo) }; + f(()); +} diff --git a/src/tools/miri/tests/fail/validity/fn_arg_never_type.stderr b/src/tools/miri/tests/fail/validity/fn_arg_never_type.stderr new file mode 100644 index 0000000000000..2995492bc9456 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/fn_arg_never_type.stderr @@ -0,0 +1,18 @@ +error: Undefined Behavior: constructing invalid value of type Never: encountered a value of zero-variant enum `Never` + --> tests/fail/validity/fn_arg_never_type.rs:LL:CC + | +LL | fn foo(x: Never) { + | ^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: stack backtrace: + 0: foo + at tests/fail/validity/fn_arg_never_type.rs:LL:CC + 1: main + at tests/fail/validity/fn_arg_never_type.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/pass/c-variadic-ignored-argument.rs b/src/tools/miri/tests/pass/c-variadic-ignored-argument.rs deleted file mode 100644 index fe09a03edfffc..0000000000000 --- a/src/tools/miri/tests/pass/c-variadic-ignored-argument.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ ignore-target: windows # does not ignore ZST arguments -//@ ignore-target: powerpc # does not ignore ZST arguments -//@ ignore-target: s390x # does not ignore ZST arguments -//@ ignore-target: sparc # does not ignore ZST arguments -#![feature(c_variadic)] - -// Some platforms ignore ZSTs, meaning that the argument is not passed, even though it is part -// of the callee's ABI. Test that this doesn't trip any asserts. -// -// NOTE: this test only succeeds when the `()` argument uses `Passmode::Ignore`. For some targets, -// notably msvc, such arguments are not ignored, which would cause UB when attempting to read the -// second `i32` argument while the next item in the variable argument list is `()`. - -fn main() { - unsafe extern "C" fn variadic(mut ap: ...) { - ap.next_arg::(); - ap.next_arg::(); - } - - unsafe { variadic(0i32, (), 1i32) } -} diff --git a/src/tools/miri/tests/pass/function_calls/abi_compat.rs b/src/tools/miri/tests/pass/function_calls/abi_compat.rs index 37795daa55c84..94cb5695fac50 100644 --- a/src/tools/miri/tests/pass/function_calls/abi_compat.rs +++ b/src/tools/miri/tests/pass/function_calls/abi_compat.rs @@ -151,4 +151,9 @@ fn main() { let rc = Rc::new(0); let rc_ptr: *mut i32 = unsafe { mem::transmute_copy(&rc) }; test_abi_compat(rc, rc_ptr); + + // Non-capturing closures are special because we rely on them being `PassMode::Ignore`. + // Make sure that does not break newtype wrapping for them. + let non_capturing_closure = || {}; + test_abi_compat(non_capturing_closure.clone(), Wrapper(non_capturing_closure)); } From b592dd8219984dfb1ceb284d6200c70b9484e834 Mon Sep 17 00:00:00 2001 From: apiraino Date: Mon, 1 Jun 2026 12:07:06 +0200 Subject: [PATCH 21/23] Tune backport Zulip messages --- triagebot.toml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index ce8ef564c5f21..248d9fe89ccb2 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -776,6 +776,10 @@ message_on_add = [ PR #{number} "{title}" fixes a regression and has been nominated for backport. {recipients}, what do you think about it? This topic will help T-compiler getting context about it. + +Tip: to approve or decline from this Zulip thread, use: +@_**triagebot** backport approve beta #{number} +@_**triagebot** backport decline beta #{number} """, """\ /poll Should #{number} be beta backported? @@ -801,6 +805,11 @@ message_on_add = [ """\ PR #{number} "{title}" fixes a regression and has been nominated for backport. {recipients}, what do you think about it? +This topic will help T-compiler getting context about it. + +Tip: to approve or decline from this Zulip thread, use: +@_**triagebot** backport approve stable #{number} +@_**triagebot** backport decline stable #{number} """, """\ /poll Approve stable backport of #{number}? From 6fac60de91b53010acf8531de39caa36164ee51c Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Mon, 1 Jun 2026 14:47:31 +0300 Subject: [PATCH 22/23] Trace `?id.local_def_index` instead of `id` in `def_path_hash` --- compiler/rustc_hir/src/definitions.rs | 4 +++- tests/ui/rustc-env/def-path-hash-ice-157238.rs | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 tests/ui/rustc-env/def-path-hash-ice-157238.rs diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 97e739a7f3893..8b37ee2835e6c 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -252,7 +252,9 @@ impl Definitions { self.def_id_to_key[id] } - #[instrument(level = "trace", skip(self), ret)] + // Log debug version of `local_def_index` (just a number), as tracing of this function + // is called too early and cause errors if `LocalDefId` is logged (#157238). + #[instrument(level = "trace", skip(self, id), fields(def_index=?id.local_def_index), ret)] #[inline(always)] pub fn def_path_hash(&self, id: LocalDefId) -> DefPathHash { DefPathHash::new(self.stable_crate_id, self.def_path_hashes[id]) diff --git a/tests/ui/rustc-env/def-path-hash-ice-157238.rs b/tests/ui/rustc-env/def-path-hash-ice-157238.rs new file mode 100644 index 0000000000000..42bf83001d5b7 --- /dev/null +++ b/tests/ui/rustc-env/def-path-hash-ice-157238.rs @@ -0,0 +1,9 @@ +//@ run-pass +// +// Ensure that `trace` level instrumentation in `def_path_hash` works, +// see #157238. +// +//@ dont-check-compiler-stdout +//@ dont-check-compiler-stderr +//@ rustc-env:RUSTC_LOG=trace +fn main() {} From 4a647a5084fa9100cb506185fa9ee9ed454374ab Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 1 Jun 2026 12:25:20 +0000 Subject: [PATCH 23/23] Don't drop uninit memory when panics --- library/core/src/iter/adapters/map_windows.rs | 31 +++++++----- .../tests/iter/adapters/map_windows.rs | 47 ++++++++++++++++++- 2 files changed, 66 insertions(+), 12 deletions(-) diff --git a/library/core/src/iter/adapters/map_windows.rs b/library/core/src/iter/adapters/map_windows.rs index bcda315f7a4a0..5c12600eac19d 100644 --- a/library/core/src/iter/adapters/map_windows.rs +++ b/library/core/src/iter/adapters/map_windows.rs @@ -1,5 +1,5 @@ use crate::iter::FusedIterator; -use crate::mem::{MaybeUninit, SizedTypeProperties}; +use crate::mem::{ManuallyDrop, MaybeUninit, SizedTypeProperties}; use crate::{fmt, ptr}; /// An iterator over the mapped windows of another iterator. @@ -30,14 +30,17 @@ struct MapWindowsInner { buffer: Option>, } -// `Buffer` uses two times of space to reduce moves among the iterations. -// `Buffer` is semantically `[MaybeUninit; 2 * N]`. However, due -// to limitations of const generics, we use this different type. Note that -// it has the same underlying memory layout. +/// `Buffer` is semantically `[MaybeUninit; 2 * N]`. This helps +/// reduce moves while iterating. However, due +/// to limitations of const generics, we use this different type. Note that +/// it has the same underlying memory layout. +/// +/// # Safety invariant +/// +/// `self.buffer[self.start..self.start + N]` must be initialized, +/// with all other elements being uninitialized. This also +/// implies that `self.start <= N`. struct Buffer { - // Invariant: `self.buffer[self.start..self.start + N]` is initialized, - // with all other elements being uninitialized. This also - // implies that `self.start <= N`. buffer: [[MaybeUninit; N]; 2], start: usize, } @@ -194,12 +197,18 @@ impl Buffer { impl Clone for Buffer { fn clone(&self) -> Self { - let mut buffer = Buffer { + // Use `ManuallyDrop` until buffer is fully written to avoid dropping uninitialized elements on panic. + // (See `Buffer` rustdoc for safety invariant) + let mut buffer = ManuallyDrop::new(Buffer { buffer: [[const { MaybeUninit::uninit() }; N], [const { MaybeUninit::uninit() }; N]], start: self.start, - }; + }); + + // `clone()` could panic; `ManuallyDrop` guards against that. buffer.as_uninit_array_mut().write(self.as_array_ref().clone()); - buffer + + // We initialized the buffer above, so we are good now + ManuallyDrop::into_inner(buffer) } } diff --git a/library/coretests/tests/iter/adapters/map_windows.rs b/library/coretests/tests/iter/adapters/map_windows.rs index 994ec087e5e8b..fa84f9d1c9cb4 100644 --- a/library/coretests/tests/iter/adapters/map_windows.rs +++ b/library/coretests/tests/iter/adapters/map_windows.rs @@ -5,7 +5,7 @@ use std::sync::atomic::Ordering::SeqCst; mod drop_checks { //! These tests mainly make sure the elements are correctly dropped. - use std::sync::atomic::Ordering::SeqCst; + use std::sync::atomic::Ordering::{Relaxed, SeqCst}; use std::sync::atomic::{AtomicBool, AtomicUsize}; #[derive(Debug)] @@ -143,6 +143,51 @@ mod drop_checks { check::<5>(5, 1); check::<5>(5, 4); } + + /// Regression test for #156501 + #[test] + fn panicking_clone() { + static CLONE_COUNTER: AtomicUsize = AtomicUsize::new(0); + static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0); + + struct PanickingClone(u8); + + impl Clone for PanickingClone { + fn clone(&self) -> Self { + if CLONE_COUNTER.fetch_add(1, Relaxed) == 3 { + panic!( + "⚞(· <:::> ·)⚟ aaaaaah its the turbofish monster!!! its gonna eat us all!!!1!" + ); + } + + Self(self.0) + } + } + + impl Drop for PanickingClone { + fn drop(&mut self) { + assert_eq!(self.0, 42); + + DROP_COUNTER.fetch_add(1, Relaxed); + } + } + + let array = [const { PanickingClone(42) }; 17]; + let mut iter = array.into_iter().map_windows::<_, (), 17>(|_| ()); + + // initialize the buffer + iter.next(); + + let result = std::panic::catch_unwind(|| { + // now do the clones and panic. + // this should't try to drop uninitialized memory + let _ = iter.clone(); + }); + + assert!(result.is_err()); + + assert_eq!(DROP_COUNTER.load(Relaxed), 3); + } } #[test]