From 125149453ce0beef86d1fa856abc6a45475f22f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 1 Jun 2026 14:09:30 +0200 Subject: [PATCH 1/2] disallow most attrs on eiis --- compiler/rustc_builtin_macros/src/eii.rs | 75 ++++++++++++++----- compiler/rustc_builtin_macros/src/errors.rs | 9 +++ ...ice_contract_attr_on_eii_generated_item.rs | 11 --- ...contract_attr_on_eii_generated_item.stderr | 14 ---- 4 files changed, 66 insertions(+), 43 deletions(-) delete mode 100644 tests/ui/eii/ice_contract_attr_on_eii_generated_item.rs delete mode 100644 tests/ui/eii/ice_contract_attr_on_eii_generated_item.stderr diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index fd0ef8500c6c3..d8d749cd35c4b 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -10,10 +10,10 @@ use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym}; use thin_vec::{ThinVec, thin_vec}; use crate::errors::{ - EiiExternTargetExpectedList, EiiExternTargetExpectedMacro, EiiExternTargetExpectedUnsafe, - EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, EiiSharedMacroInStatementPosition, - EiiSharedMacroTarget, EiiStaticArgumentRequired, EiiStaticDefault, - EiiStaticMultipleImplementations, EiiStaticMutable, + EiiAttributeNotSupported, EiiExternTargetExpectedList, EiiExternTargetExpectedMacro, + EiiExternTargetExpectedUnsafe, EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, + EiiSharedMacroInStatementPosition, EiiSharedMacroTarget, EiiStaticArgumentRequired, + EiiStaticDefault, EiiStaticMultipleImplementations, EiiStaticMutable, }; /// ```rust @@ -128,6 +128,8 @@ fn eii_( let attrs_from_decl = filter_attrs_for_multiple_eii_attr(ecx, attrs, eii_attr_span, &meta_item.path); + let (macro_attrs, foreign_item_attrs, default_func_attrs) = + split_attrs(ecx, item_span, attrs_from_decl); let Ok(macro_name) = name_for_impl_macro(ecx, foreign_item_name, &meta_item) else { // we don't need to wrap in Annotatable::Stmt conditionally since @@ -148,6 +150,7 @@ fn eii_( eii_attr_span, item_span, foreign_item_name, + default_func_attrs, )) } @@ -157,7 +160,7 @@ fn eii_( item_span, kind, vis, - &attrs_from_decl, + foreign_item_attrs, )); module_items.push(generate_attribute_macro_to_implement( ecx, @@ -165,7 +168,7 @@ fn eii_( macro_name, foreign_item_name, impl_unsafe, - &attrs_from_decl, + macro_attrs, )); // we don't need to wrap in Annotatable::Stmt conditionally since @@ -173,6 +176,49 @@ fn eii_( module_items.into_iter().map(Annotatable::Item).collect() } +fn split_attrs( + ecx: &mut ExtCtxt<'_>, + span: Span, + attrs: ThinVec, +) -> (ThinVec, ThinVec, ThinVec) { + let mut macro_attributes = ThinVec::new(); + let mut foreign_item_attributes = ThinVec::new(); + let mut default_attributes = ThinVec::new(); + + for attr in attrs { + match attr.name() { + // Inline only matters for the default function being inlined into callsites + Some(sym::inline) => default_attributes.push(attr), + // If an eii is marked a lang item, that's because we want to call its declaration, so + // mark the foreign item as the lang item + Some(sym::lang) => foreign_item_attributes.push(attr), + // Deprecating an eii means deprecating the macro and the foreign item + Some(sym::deprecated) => { + foreign_item_attributes.push(attr.clone()); + macro_attributes.push(attr); + } + // The stability of an EII affects the usage of the macro and calling the foreign item + Some(sym::stable) | Some(sym::unstable) => { + foreign_item_attributes.push(attr.clone()); + macro_attributes.push(attr); + } + // Doc attributes should be forwarded to the macro and the foreign item, since those are + // the two items you interact with as a user. + // FIXME: idk yet how EIIs show up in docs, might want to customize + _ if attr.is_doc_comment() => { + foreign_item_attributes.push(attr.clone()); + macro_attributes.push(attr); + } + Some(sym::eii) => unreachable!("should already be filtered out"), + _ => { + ecx.dcx().emit_err(EiiAttributeNotSupported { span, attr_span: attr.span() }); + } + } + } + + (macro_attributes, foreign_item_attributes, default_attributes) +} + /// Decide on the name of the macro that can be used to implement the EII. /// This is either an explicitly given name, or the name of the item in the /// declaration of the EII. @@ -228,10 +274,8 @@ fn generate_default_func_impl( eii_attr_span: Span, item_span: Span, foreign_item_name: Ident, + attrs: ThinVec, ) -> Box { - // FIXME: re-add some original attrs - let attrs = ThinVec::new(); - let mut default_func = func.clone(); default_func.eii_impls.push(EiiImpl { node_id: DUMMY_NODE_ID, @@ -289,10 +333,9 @@ fn generate_foreign_item( item_span: Span, item_kind: &ItemKind, vis: Visibility, - attrs_from_decl: &[Attribute], + attrs_from_decl: ThinVec, ) -> Box { - let mut foreign_item_attrs = ThinVec::new(); - foreign_item_attrs.extend_from_slice(attrs_from_decl); + let mut foreign_item_attrs = attrs_from_decl; // Add the rustc_eii_foreign_item on the foreign item. Usually, foreign items are mangled. // This attribute makes sure that we later know that this foreign item's symbol should not be. @@ -381,13 +424,9 @@ fn generate_attribute_macro_to_implement( macro_name: Ident, foreign_item_name: Ident, impl_unsafe: bool, - attrs_from_decl: &[Attribute], + attrs_from_decl: ThinVec, ) -> Box { - let mut macro_attrs = ThinVec::new(); - - // To avoid e.g. `error: attribute macro has missing stability attribute` - // errors for eii's in std. - macro_attrs.extend_from_slice(attrs_from_decl); + let mut macro_attrs = attrs_from_decl; // Avoid "missing stability attribute" errors for eiis in std. See #146993. macro_attrs.push(ecx.attr_name_value_str(sym::rustc_macro_transparency, sym::semiopaque, span)); diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index c64d6871269a6..929c88402b1aa 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1186,6 +1186,15 @@ pub(crate) struct EiiMacroExpectedMaxOneArgument { pub name: String, } +#[derive(Diagnostic)] +#[diag("only a small subset of attributes are supported on externally implementable items")] +pub(crate) struct EiiAttributeNotSupported { + #[primary_span] + pub span: Span, + #[note("this attribute is not supported")] + pub attr_span: Span, +} + #[derive(Diagnostic)] #[diag("named argument `{$named_arg_name}` is not used by name")] pub(crate) struct NamedArgumentUsedPositionally { diff --git a/tests/ui/eii/ice_contract_attr_on_eii_generated_item.rs b/tests/ui/eii/ice_contract_attr_on_eii_generated_item.rs deleted file mode 100644 index fce142f6dc08b..0000000000000 --- a/tests/ui/eii/ice_contract_attr_on_eii_generated_item.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ compile-flags: --crate-type rlib - -#![feature(extern_item_impls)] -#![feature(contracts)] -#![allow(incomplete_features)] - -#[eii] -#[core::contracts::ensures] -//~^ ERROR contract annotations is only supported in functions with bodies -//~| ERROR contract annotations can only be used on functions -fn implementation(); diff --git a/tests/ui/eii/ice_contract_attr_on_eii_generated_item.stderr b/tests/ui/eii/ice_contract_attr_on_eii_generated_item.stderr deleted file mode 100644 index 3335346e55eec..0000000000000 --- a/tests/ui/eii/ice_contract_attr_on_eii_generated_item.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: contract annotations is only supported in functions with bodies - --> $DIR/ice_contract_attr_on_eii_generated_item.rs:8:1 - | -LL | #[core::contracts::ensures] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: contract annotations can only be used on functions - --> $DIR/ice_contract_attr_on_eii_generated_item.rs:8:1 - | -LL | #[core::contracts::ensures] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - From a492d4f8e2f10e19b4af2fb75d4c3059e06d0630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 2 Jun 2026 16:25:33 +0200 Subject: [PATCH 2/2] add test for attrs on eiis --- tests/ui/eii/attrs.rs | 22 ++++++++++++++++++++++ tests/ui/eii/attrs.stderr | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 tests/ui/eii/attrs.rs create mode 100644 tests/ui/eii/attrs.stderr diff --git a/tests/ui/eii/attrs.rs b/tests/ui/eii/attrs.rs new file mode 100644 index 0000000000000..ec6259863e9b0 --- /dev/null +++ b/tests/ui/eii/attrs.rs @@ -0,0 +1,22 @@ +#![feature(extern_item_impls)] +#![deny(deprecated)] //~ NOTE: + +// makes no sense on functions, nor on the macro generated (it's a macrov2). +#[macro_export] //~ NOTE: this attribute is not supported +// makes sense, as long as we only forward it onto the function, +// so we allow and this shouln't cause errors for being on a "wrong target". +#[inline] +// makes sense, should be allowed, and forwarded on both the function and the macro +#[deprecated = "foo"] +#[eii] +fn example() {} +//~^ ERROR only a small subset of attributes are supported on externally implementable items + +// check that both are deprecated vvvv +#[example] +//~^ ERROR use of deprecated macro +fn explicit_impl() {} +fn main() { + example() + //~^ ERROR use of deprecated function +} diff --git a/tests/ui/eii/attrs.stderr b/tests/ui/eii/attrs.stderr new file mode 100644 index 0000000000000..a8d7cbbee1828 --- /dev/null +++ b/tests/ui/eii/attrs.stderr @@ -0,0 +1,32 @@ +error: only a small subset of attributes are supported on externally implementable items + --> $DIR/attrs.rs:12:1 + | +LL | fn example() {} + | ^^^^^^^^^^^^ + | +note: this attribute is not supported + --> $DIR/attrs.rs:5:1 + | +LL | #[macro_export] + | ^^^^^^^^^^^^^^^ + +error: use of deprecated macro `example`: foo + --> $DIR/attrs.rs:16:3 + | +LL | #[example] + | ^^^^^^^ + | +note: the lint level is defined here + --> $DIR/attrs.rs:2:9 + | +LL | #![deny(deprecated)] + | ^^^^^^^^^^ + +error: use of deprecated function `example`: foo + --> $DIR/attrs.rs:20:5 + | +LL | example() + | ^^^^^^^ + +error: aborting due to 3 previous errors +