From 5b39c1515912ff15c618651b5afd2d7225c6d2f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=9D=E5=80=89=E6=B0=B4=E5=B8=8C?= Date: Sun, 24 May 2026 16:13:12 +0800 Subject: [PATCH] Reject `#[no_mangle]`/`#[link_name]`/`#[export_name]` on EII --- compiler/rustc_builtin_macros/src/eii.rs | 28 ++++++++++---- compiler/rustc_builtin_macros/src/errors.rs | 8 ++++ tests/ui/eii/forbidden_attrs.rs | 43 +++++++++++++++++++++ tests/ui/eii/forbidden_attrs.stderr | 38 ++++++++++++++++++ 4 files changed, 110 insertions(+), 7 deletions(-) create mode 100644 tests/ui/eii/forbidden_attrs.rs create mode 100644 tests/ui/eii/forbidden_attrs.stderr diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index fd0ef8500c6c3..02844d7e6a0a2 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -11,9 +11,9 @@ use thin_vec::{ThinVec, thin_vec}; use crate::errors::{ EiiExternTargetExpectedList, EiiExternTargetExpectedMacro, EiiExternTargetExpectedUnsafe, - EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, EiiSharedMacroInStatementPosition, - EiiSharedMacroTarget, EiiStaticArgumentRequired, EiiStaticDefault, - EiiStaticMultipleImplementations, EiiStaticMutable, + EiiForbiddenAttr, EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, + EiiSharedMacroInStatementPosition, EiiSharedMacroTarget, EiiStaticArgumentRequired, + EiiStaticDefault, EiiStaticMultipleImplementations, EiiStaticMutable, }; /// ```rust @@ -126,8 +126,7 @@ fn eii_( let attrs = attrs.clone(); let vis = vis.clone(); - let attrs_from_decl = - filter_attrs_for_multiple_eii_attr(ecx, attrs, eii_attr_span, &meta_item.path); + let attrs_from_decl = filter_attrs_for_eii_decl(ecx, attrs, eii_attr_span, &meta_item.path); 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 @@ -196,8 +195,9 @@ fn name_for_impl_macro( } } -/// Ensure that in the list of attrs, there's only a single `eii` attribute. -fn filter_attrs_for_multiple_eii_attr( +/// Reject attributes that cannot be used with externally implementable items, +/// and ensure that in the list of attrs, there's only a single `eii` attribute. +fn filter_attrs_for_eii_decl( ecx: &mut ExtCtxt<'_>, attrs: ThinVec, eii_attr_span: Span, @@ -213,6 +213,11 @@ fn filter_attrs_for_multiple_eii_attr( name: path_to_string(eii_attr_path), }); false + } else if let Some(name @ (sym::export_name | sym::link_name | sym::no_mangle)) = + i.name() + { + ecx.dcx().emit_err(EiiForbiddenAttr { span: i.span, name }); + false } else { true } @@ -511,6 +516,15 @@ pub(crate) fn eii_shared_macro( return vec![item]; }; + i.attrs.retain(|attr| { + if let Some(name @ (sym::export_name | sym::link_name | sym::no_mangle)) = attr.name() { + ecx.dcx().emit_err(EiiForbiddenAttr { span: attr.span, name }); + false + } else { + true + } + }); + let eii_impls = match &mut i.kind { ItemKind::Fn(func) => &mut func.eii_impls, ItemKind::Static(stat) => { diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index c64d6871269a6..c755f02de2c92 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1178,6 +1178,14 @@ pub(crate) struct EiiOnlyOnce { pub name: String, } +#[derive(Diagnostic)] +#[diag("`#[{$name}]` cannot be used on externally implementable items")] +pub(crate) struct EiiForbiddenAttr { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + #[derive(Diagnostic)] #[diag("`#[{$name}]` expected no arguments or a single argument: `#[{$name}(default)]`")] pub(crate) struct EiiMacroExpectedMaxOneArgument { diff --git a/tests/ui/eii/forbidden_attrs.rs b/tests/ui/eii/forbidden_attrs.rs new file mode 100644 index 0000000000000..3a3eabaae90e6 --- /dev/null +++ b/tests/ui/eii/forbidden_attrs.rs @@ -0,0 +1,43 @@ +// Tests attributes that are forbidden on EII. +#![feature(extern_item_impls)] + +#[unsafe(no_mangle)] +//~^ ERROR `#[no_mangle]` cannot be used on externally implementable items +#[eii] +fn foo() {} + +#[unsafe(export_name = "bar")] +//~^ ERROR `#[export_name]` cannot be used on externally implementable items +#[eii] +fn bar() {} + +#[link_name = "baz"] +//~^ ERROR `#[link_name]` cannot be used on externally implementable items +#[eii] +fn baz() {} + +#[eii] +fn qux(); + +#[unsafe(no_mangle)] +//~^ ERROR `#[no_mangle]` cannot be used on externally implementable items +#[qux] +fn qux_impl() {} + +#[eii] +fn corge(); + +#[unsafe(export_name = "corge_impl")] +//~^ ERROR `#[export_name]` cannot be used on externally implementable items +#[corge] +fn corge_impl() {} + +#[eii] +fn garply(); + +#[link_name = "garply_impl"] +//~^ ERROR `#[link_name]` cannot be used on externally implementable items +#[garply] +fn garply_impl() {} + +fn main() {} diff --git a/tests/ui/eii/forbidden_attrs.stderr b/tests/ui/eii/forbidden_attrs.stderr new file mode 100644 index 0000000000000..db8f54f8e4110 --- /dev/null +++ b/tests/ui/eii/forbidden_attrs.stderr @@ -0,0 +1,38 @@ +error: `#[no_mangle]` cannot be used on externally implementable items + --> $DIR/forbidden_attrs.rs:4:1 + | +LL | #[unsafe(no_mangle)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: `#[export_name]` cannot be used on externally implementable items + --> $DIR/forbidden_attrs.rs:9:1 + | +LL | #[unsafe(export_name = "bar")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[link_name]` cannot be used on externally implementable items + --> $DIR/forbidden_attrs.rs:14:1 + | +LL | #[link_name = "baz"] + | ^^^^^^^^^^^^^^^^^^^^ + +error: `#[no_mangle]` cannot be used on externally implementable items + --> $DIR/forbidden_attrs.rs:22:1 + | +LL | #[unsafe(no_mangle)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: `#[export_name]` cannot be used on externally implementable items + --> $DIR/forbidden_attrs.rs:30:1 + | +LL | #[unsafe(export_name = "corge_impl")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[link_name]` cannot be used on externally implementable items + --> $DIR/forbidden_attrs.rs:38:1 + | +LL | #[link_name = "garply_impl"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors +