From 6ed7615608bf0330f65a9438292038f24aa63ce5 Mon Sep 17 00:00:00 2001 From: Oscar Bray Date: Fri, 13 Feb 2026 11:18:24 +0000 Subject: [PATCH] Port #[rustc_test_marker] to the attribute parser --- .../src/attributes/test_attrs.rs | 33 +++++++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 1 + .../rustc_hir/src/attrs/data_structures.rs | 3 ++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 2 +- src/tools/clippy/clippy_utils/src/lib.rs | 6 +--- 6 files changed, 40 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index 41b1836588deb..ac1d360c62809 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -257,3 +257,36 @@ impl SingleAttributeParser for TestRunnerParser { Some(AttributeKind::TestRunner(meta.path().0.clone())) } } + +pub(crate) struct RustcTestMarkerParser; + +impl SingleAttributeParser for RustcTestMarkerParser { + const PATH: &[Symbol] = &[sym::rustc_test_marker]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Const), + Allow(Target::Fn), + Allow(Target::Static), + ]); + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "test_path"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { + let Some(name_value) = args.name_value() else { + cx.expected_name_value(cx.attr_span, Some(sym::rustc_test_marker)); + return None; + }; + + let Some(value_str) = name_value.value_as_str() else { + cx.expected_string_literal(name_value.value_span, None); + return None; + }; + + if value_str.as_str().trim().is_empty() { + cx.expected_non_empty_string_literal(name_value.value_span); + return None; + } + + Some(AttributeKind::RustcTestMarker(value_str)) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index e11bb66685399..b0a6ef34195b3 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -217,6 +217,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 8d9b53498934e..d6a9c2dc872fd 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1336,6 +1336,9 @@ pub enum AttributeKind { /// Represents `#[rustc_symbol_name]` RustcSymbolName(Span), + /// Represents `#[rustc_test_marker]` + RustcTestMarker(Symbol), + /// Represents `#[rustc_then_this_would_need]` RustcThenThisWouldNeed(Span, ThinVec), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index ec4d543fdc208..f103be915a5a2 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -170,6 +170,7 @@ impl AttributeKind { RustcStdInternalSymbol(..) => No, RustcStrictCoherence(..) => Yes, RustcSymbolName(..) => Yes, + RustcTestMarker(..) => No, RustcThenThisWouldNeed(..) => No, RustcTrivialFieldReads => Yes, RustcUnsafeSpecializationMarker(..) => No, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 3362ea667b931..d2cea03921296 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -361,6 +361,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcStdInternalSymbol (..) | AttributeKind::RustcStrictCoherence(..) | AttributeKind::RustcSymbolName(..) + | AttributeKind::RustcTestMarker(..) | AttributeKind::RustcThenThisWouldNeed(..) | AttributeKind::RustcTrivialFieldReads | AttributeKind::RustcUnsafeSpecializationMarker(..) @@ -401,7 +402,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::rustc_on_unimplemented | sym::rustc_do_not_const_check | sym::rustc_doc_primitive - | sym::rustc_test_marker | sym::rustc_layout | sym::rustc_proc_macro_decls | sym::rustc_autodiff diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 269a7f333dc58..c479ea59b884a 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -2343,11 +2343,7 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl FnOnce(& // We could also check for the type name `test::TestDescAndFn` && let Res::Def(DefKind::Struct, _) = path.res { - let has_test_marker = tcx - .hir_attrs(item.hir_id()) - .iter() - .any(|a| a.has_name(sym::rustc_test_marker)); - if has_test_marker { + if find_attr!(tcx.hir_attrs(item.hir_id()), AttributeKind::RustcTestMarker(..)) { names.push(ident.name); } }