diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index a36e7f3248dd0..98c6b419b13db 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3936,7 +3936,7 @@ pub struct Fn { /// This function is an implementation of an externally implementable item (EII). /// This means, there was an EII declared somewhere and this function is the /// implementation that should be run when the declaration is called. - pub eii_impls: ThinVec, + pub eii_impl: Option>, } impl Fn { @@ -4028,9 +4028,7 @@ pub struct StaticItem { /// This static is an implementation of an externally implementable item (EII). /// This means, there was an EII declared somewhere and this static is the /// implementation that should be used for the declaration. - /// - /// For statics, there may be at most one `EiiImpl`, but this is a `ThinVec` to make usages of this field nicer. - pub eii_impls: ThinVec, + pub eii_impl: Option>, } #[derive(Clone, Encodable, Decodable, Debug, Walkable)] diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index a768935f38fc3..9d4c32825e1e4 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -933,12 +933,12 @@ macro_rules! common_visitor_and_walkers { _ctxt, // Visibility is visited as a part of the item. _vis, - Fn { defaultness, ident, sig, generics, contract, body, define_opaque, eii_impls }, + Fn { defaultness, ident, sig, generics, contract, body, define_opaque, eii_impl }, ) => { let FnSig { header, decl, span } = sig; visit_visitable!($($mut)? vis, defaultness, ident, header, generics, decl, - contract, body, span, define_opaque, eii_impls + contract, body, span, define_opaque, eii_impl ); } FnKind::Closure(binder, coroutine_kind, decl, body) => diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index caa554c4aa669..89a69a7144200 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -167,15 +167,11 @@ impl<'hir> LoweringContext<'_, 'hir> { i: &ItemKind, ) -> Vec { match i { - ItemKind::Fn(Fn { eii_impls, .. }) | ItemKind::Static(StaticItem { eii_impls, .. }) - if eii_impls.is_empty() => - { - Vec::new() - } - ItemKind::Fn(Fn { eii_impls, .. }) | ItemKind::Static(StaticItem { eii_impls, .. }) => { - vec![hir::Attribute::Parsed(AttributeKind::EiiImpls( - eii_impls.iter().map(|i| self.lower_eii_impl(i)).collect(), - ))] + ItemKind::Fn(Fn { eii_impl: None, .. }) + | ItemKind::Static(StaticItem { eii_impl: None, .. }) => Vec::new(), + ItemKind::Fn(Fn { eii_impl: Some(eii_impl), .. }) + | ItemKind::Static(StaticItem { eii_impl: Some(eii_impl), .. }) => { + vec![hir::Attribute::Parsed(AttributeKind::EiiImpl(self.lower_eii_impl(eii_impl)))] } ItemKind::MacroDef(name, MacroDef { eii_declaration: Some(target), .. }) => self .lower_eii_decl(id, *name, target) @@ -223,7 +219,7 @@ impl<'hir> LoweringContext<'_, 'hir> { kind, vis_span, span: self.lower_span(i.span), - eii: find_attr!(attrs, EiiImpls(..) | EiiDeclaration(..)), + eii: find_attr!(attrs, EiiImpl(..) | EiiDeclaration(..)), }; self.arena.alloc(item) } @@ -256,7 +252,7 @@ impl<'hir> LoweringContext<'_, 'hir> { mutability: m, expr: e, define_opaque, - eii_impls: _, + eii_impl: _, }) => { let ident = self.lower_ident(*ident); let ty = self @@ -693,7 +689,7 @@ impl<'hir> LoweringContext<'_, 'hir> { kind, vis_span, span: this.lower_span(use_tree.span()), - eii: find_attr!(attrs, EiiImpls(..) | EiiDeclaration(..)), + eii: find_attr!(attrs, EiiImpl(..) | EiiDeclaration(..)), }; hir::OwnerNode::Item(this.arena.alloc(item)) }); @@ -760,7 +756,7 @@ impl<'hir> LoweringContext<'_, 'hir> { expr: _, safety, define_opaque, - eii_impls: _, + eii_impl: _, }) => { let ty = self .lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 1276aa8f4fb96..4fcc9017b5220 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1204,10 +1204,10 @@ impl<'a> AstValidator<'a> { } // Check EII implementation attributes against an allowlist. - fn check_eii_impl_attrs(&self, attrs: &[Attribute], eii_impls: &[EiiImpl]) { - if eii_impls.is_empty() { + fn check_eii_impl_attrs(&self, attrs: &[Attribute], eii_impl: &Option>) { + let Some(eii_impl) = eii_impl else { return; - } + }; let allowed_attrs: &[Symbol] = &[ sym::allow, @@ -1234,14 +1234,12 @@ impl<'a> AstValidator<'a> { } let attr_name = pprust::path_to_string(&normal.item.path); - for eii_impl in eii_impls { - self.dcx().emit_err(diagnostics::EiiImplAttributeNotSupported { - attr_span: attr.span, - attr_name: &attr_name, - eii_span: eii_impl.span, - eii_name: pprust::path_to_string(&eii_impl.eii_macro_path), - }); - } + self.dcx().emit_err(diagnostics::EiiImplAttributeNotSupported { + attr_span: attr.span, + attr_name: &attr_name, + eii_span: eii_impl.span, + eii_name: pprust::path_to_string(&eii_impl.eii_macro_path), + }); } } } @@ -1424,16 +1422,16 @@ impl Visitor<'_> for AstValidator<'_> { contract: _, body, define_opaque: _, - eii_impls, + eii_impl, }, ) => { self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident); self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No); - for EiiImpl { eii_macro_path, .. } in eii_impls { + if let Some(EiiImpl { eii_macro_path, .. }) = eii_impl { self.visit_path(eii_macro_path); } - self.check_eii_impl_attrs(&item.attrs, eii_impls); + self.check_eii_impl_attrs(&item.attrs, eii_impl); let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic)); if body.is_none() && !is_intrinsic && !self.is_sdylib_interface { @@ -1609,9 +1607,9 @@ impl Visitor<'_> for AstValidator<'_> { visit::walk_item(self, item); } - ItemKind::Static(StaticItem { expr, safety, eii_impls, .. }) => { + ItemKind::Static(StaticItem { expr, safety, eii_impl, .. }) => { self.check_item_safety(item.span, *safety); - self.check_eii_impl_attrs(&item.attrs, eii_impls); + self.check_eii_impl_attrs(&item.attrs, eii_impl); if matches!(safety, Safety::Unsafe(_)) { self.dcx().emit_err(diagnostics::UnsafeStatic { span: item.span }); } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 14a9750ea4f89..2dbc48cc64868 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -43,7 +43,7 @@ impl<'a> State<'a> { expr, safety, define_opaque, - eii_impls, + eii_impl, }) => self.print_item_const( *ident, Some(*mutability), @@ -54,7 +54,7 @@ impl<'a> State<'a> { *safety, ast::Defaultness::Implicit, define_opaque.as_deref(), - eii_impls, + eii_impl.as_deref(), ), ast::ForeignItemKind::TyAlias(ast::TyAlias { defaultness, @@ -95,10 +95,10 @@ impl<'a> State<'a> { safety: ast::Safety, defaultness: ast::Defaultness, define_opaque: Option<&[(ast::NodeId, ast::Path)]>, - eii_impls: &[EiiImpl], + eii_impl: Option<&EiiImpl>, ) { self.print_define_opaques(define_opaque); - for eii_impl in eii_impls { + if let Some(eii_impl) = eii_impl { self.print_eii_impl(eii_impl); } let (cb, ib) = self.head(""); @@ -197,7 +197,7 @@ impl<'a> State<'a> { mutability: mutbl, expr: body, define_opaque, - eii_impls, + eii_impl, }) => { self.print_safety(*safety); self.print_item_const( @@ -210,7 +210,7 @@ impl<'a> State<'a> { ast::Safety::Default, ast::Defaultness::Implicit, define_opaque.as_deref(), - eii_impls, + eii_impl.as_deref(), ); } ast::ItemKind::ConstBlock(ast::ConstBlockItem { id: _, span: _, block }) => { @@ -243,7 +243,7 @@ impl<'a> State<'a> { ast::Safety::Default, *defaultness, define_opaque.as_deref(), - &[], + None, ); } ast::ItemKind::Fn(func) => { @@ -632,7 +632,7 @@ impl<'a> State<'a> { ast::Safety::Default, *defaultness, define_opaque.as_deref(), - &[], + None, ); } ast::AssocItemKind::Type(ast::TyAlias { @@ -732,12 +732,12 @@ impl<'a> State<'a> { } fn print_fn_full(&mut self, vis: &ast::Visibility, attrs: &[ast::Attribute], func: &ast::Fn) { - let ast::Fn { defaultness, ident, generics, sig, contract, body, define_opaque, eii_impls } = + let ast::Fn { defaultness, ident, generics, sig, contract, body, define_opaque, eii_impl } = func; self.print_define_opaques(define_opaque.as_deref()); - for eii_impl in eii_impls { + if let Some(eii_impl) = eii_impl { self.print_eii_impl(eii_impl); } diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index d50fc78b51e14..57e589ac5a1e8 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -96,7 +96,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span contract: None, body, define_opaque: None, - eii_impls: ThinVec::new(), + eii_impl: None, })); let attrs = thin_vec![cx.attr_word(sym::rustc_std_internal_symbol, span)]; diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 51ab44d8a03ef..0618c28759a66 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -344,7 +344,7 @@ mod llvm_enzyme { contract: None, body: Some(d_body), define_opaque: None, - eii_impls: ThinVec::new(), + eii_impl: None, }); let mut rustc_ad_attr = Box::new(ast::NormalAttr::from_ident(Ident::with_dummy_span(sym::rustc_autodiff))); diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 1a0a65d4f7c64..8f44541bc6d0b 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -1083,7 +1083,7 @@ impl<'a> MethodDef<'a> { contract: None, body: Some(body_block), define_opaque: None, - eii_impls: ThinVec::new(), + eii_impl: None, })), tokens: None, }) diff --git a/compiler/rustc_builtin_macros/src/diagnostics.rs b/compiler/rustc_builtin_macros/src/diagnostics.rs index 6ae0f908a88a0..227c34f25a037 100644 --- a/compiler/rustc_builtin_macros/src/diagnostics.rs +++ b/compiler/rustc_builtin_macros/src/diagnostics.rs @@ -1094,6 +1094,13 @@ pub(crate) struct CfgSelectNoMatches { pub span: Span, } +#[derive(Diagnostic)] +#[diag("a single item cannot both declare and implement EIIs")] +pub(crate) struct EiiBothDeclAndImpl { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag("`#[eii_declaration(...)]` is only valid on macros")] pub(crate) struct EiiExternTargetExpectedMacro { @@ -1117,21 +1124,18 @@ pub(crate) struct EiiExternTargetExpectedUnsafe { } #[derive(Diagnostic)] -#[diag("`#[{$name}]` is only valid on functions and statics")] -pub(crate) struct EiiSharedMacroTarget { +#[diag("a single item cannot implement multiple EIIs")] +pub(crate) struct EiiMultipleImplementations { #[primary_span] pub span: Span, - pub name: String, } #[derive(Diagnostic)] -#[diag("static cannot implement multiple EIIs")] -#[note( - "this is not allowed because multiple externally implementable statics that alias may be unintuitive" -)] -pub(crate) struct EiiStaticMultipleImplementations { +#[diag("`#[{$name}]` is only valid on functions and statics")] +pub(crate) struct EiiSharedMacroTarget { #[primary_span] pub span: Span, + pub name: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index 5a28416900372..cf50460422f52 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::diagnostics::{ - EiiAttributeNotSupported, EiiExternTargetExpectedList, EiiExternTargetExpectedMacro, - EiiExternTargetExpectedUnsafe, EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, - EiiSharedMacroInStatementPosition, EiiSharedMacroTarget, EiiStaticArgumentRequired, - EiiStaticDefaultApple, EiiStaticMultipleImplementations, EiiStaticMutable, + EiiAttributeNotSupported, EiiBothDeclAndImpl, EiiExternTargetExpectedList, + EiiExternTargetExpectedMacro, EiiExternTargetExpectedUnsafe, EiiMacroExpectedMaxOneArgument, + EiiMultipleImplementations, EiiOnlyOnce, EiiSharedMacroInStatementPosition, + EiiSharedMacroTarget, EiiStaticArgumentRequired, EiiStaticDefaultApple, EiiStaticMutable, }; /// ```rust @@ -125,6 +125,22 @@ fn eii_( } }; + match kind { + ItemKind::Fn(func) => { + if func.eii_impl.is_some() { + ecx.dcx().emit_err(EiiBothDeclAndImpl { span: eii_attr_span }); + return vec![Annotatable::Item(item)]; + } + } + ItemKind::Static(stat) => { + if stat.eii_impl.is_some() { + ecx.dcx().emit_err(EiiBothDeclAndImpl { span: eii_attr_span }); + return vec![Annotatable::Item(item)]; + } + } + _ => unreachable!("Target was checked earlier"), + }; + // only clone what we need let attrs = attrs.clone(); let vis = vis.clone(); @@ -298,7 +314,7 @@ fn generate_default_impl( _ => unreachable!("Target was checked earlier"), }; - let eii_impl = EiiImpl { + let eii_impl = Box::new(EiiImpl { node_id: DUMMY_NODE_ID, inner_span: macro_name.span, eii_macro_path: ast::Path::from_ident(macro_name), @@ -315,15 +331,17 @@ fn generate_default_impl( // NOTE: this is why EIIs can't be used on statements vec![Ident::from_str_and_span("self", foreign_item_name.span), foreign_item_name], )), - }; + }); let mut item_kind = item_kind.clone(); match &mut item_kind { ItemKind::Fn(func) => { - func.eii_impls.push(eii_impl); + assert!(func.eii_impl.is_none()); + func.eii_impl = Some(eii_impl); } ItemKind::Static(stat) => { - stat.eii_impls.push(eii_impl); + assert!(stat.eii_impl.is_none()); + stat.eii_impl = Some(eii_impl); } _ => unreachable!("Target was checked earlier"), }; @@ -579,16 +597,9 @@ pub(crate) fn eii_shared_macro( return vec![item]; }; - let eii_impls = match &mut i.kind { - ItemKind::Fn(func) => &mut func.eii_impls, - ItemKind::Static(stat) => { - if !stat.eii_impls.is_empty() { - // Reject multiple implementations on one static item - // because it might be unintuitive for libraries defining statics the defined statics may alias - ecx.dcx().emit_err(EiiStaticMultipleImplementations { span }); - } - &mut stat.eii_impls - } + let eii_impl = match &mut i.kind { + ItemKind::Fn(func) => &mut func.eii_impl, + ItemKind::Static(stat) => &mut stat.eii_impl, _ => { ecx.dcx() .emit_err(EiiSharedMacroTarget { span, name: path_to_string(&meta_item.path) }); @@ -611,7 +622,10 @@ pub(crate) fn eii_shared_macro( return vec![item]; }; - eii_impls.push(EiiImpl { + if eii_impl.is_some() { + ecx.dcx().emit_err(EiiMultipleImplementations { span }); + } + *eii_impl = Some(Box::new(EiiImpl { node_id: DUMMY_NODE_ID, inner_span: meta_item.path.span, eii_macro_path: meta_item.path.clone(), @@ -619,7 +633,7 @@ pub(crate) fn eii_shared_macro( span, is_default, known_eii_macro_resolution: None, - }); + })); vec![item] } diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 72b493e313326..00ed0f52d6a6f 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -97,7 +97,7 @@ impl AllocFnFactory<'_, '_> { contract: None, body, define_opaque: None, - eii_impls: ThinVec::new(), + eii_impl: None, })); let item = self.cx.item(self.span, self.attrs(method), kind); self.cx.stmt_item(self.ty_span, item) diff --git a/compiler/rustc_builtin_macros/src/offload.rs b/compiler/rustc_builtin_macros/src/offload.rs index cdb3ba22ec6c8..e47ccc0d85f7d 100644 --- a/compiler/rustc_builtin_macros/src/offload.rs +++ b/compiler/rustc_builtin_macros/src/offload.rs @@ -85,7 +85,7 @@ pub(crate) fn expand_kernel( contract: None, body, define_opaque: None, - eii_impls: Default::default(), + eii_impl: None, }); let extern_gpu_kernel = ast::Extern::from_abi( @@ -157,7 +157,7 @@ pub(crate) fn expand_kernel( contract: None, body: Some(body), define_opaque: None, - eii_impls: Default::default(), + eii_impl: None, }); for param in host_fn.sig.decl.inputs.iter_mut() { diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index af0c9ed7ee656..19dd721f4a7c8 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -347,7 +347,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> Box { contract: None, body: Some(main_body), define_opaque: None, - eii_impls: ThinVec::new(), + eii_impl: None, })); let main = Box::new(ast::Item { diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 691b13f03e965..c64cee53d7c9f 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -225,32 +225,31 @@ fn process_builtin_attrs( AttributeKind::RustcEiiForeignItem => { codegen_fn_attrs.flags |= CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM; } - AttributeKind::EiiImpls(impls) => { - for i in impls { - let foreign_item = match i.resolution { - EiiImplResolution::Macro(def_id) => { - let Some(extern_item) = find_attr!(tcx, def_id, EiiDeclaration(target) => target.foreign_item - ) else { - tcx.dcx().span_delayed_bug( - i.span, - "resolved to something that's not an EII", - ); - continue; - }; - extern_item - } - EiiImplResolution::Known(def_id) => def_id, - EiiImplResolution::Error(_eg) => continue, - }; + AttributeKind::EiiImpl(i) => { + let foreign_item = match i.resolution { + EiiImplResolution::Macro(def_id) => { + let Some(extern_item) = find_attr!(tcx, def_id, EiiDeclaration(target) => target.foreign_item + ) else { + tcx.dcx().span_delayed_bug( + i.span, + "resolved to something that's not an EII", + ); + continue; + }; + extern_item + } + EiiImplResolution::Known(def_id) => def_id, + EiiImplResolution::Error(_eg) => continue, + }; - // this is to prevent a bug where a single crate defines both the default and explicit implementation - // for an EII. In that case, both of them may be part of the same final object file. I'm not 100% sure - // what happens, either rustc deduplicates the symbol or llvm, or it's random/order-dependent. - // However, the fact that the default one of has weak linkage isn't considered and you sometimes get that - // the default implementation is used while an explicit implementation is given. - if - // if this is a default impl - i.is_default + // this is to prevent a bug where a single crate defines both the default and explicit implementation + // for an EII. In that case, both of them may be part of the same final object file. I'm not 100% sure + // what happens, either rustc deduplicates the symbol or llvm, or it's random/order-dependent. + // However, the fact that the default one of has weak linkage isn't considered and you sometimes get that + // the default implementation is used while an explicit implementation is given. + if + // if this is a default impl + i.is_default // iterate over all implementations *in the current crate* // (this is ok since we generate codegen fn attrs in the local crate) // if any of them is *not default* then don't emit the alias. @@ -258,28 +257,27 @@ fn process_builtin_attrs( let (_, impls) = tcx.externally_implementable_items(LOCAL_CRATE).get(&foreign_item).unwrap_or_else(|| bug!("EII impl should have an entry")); impls.iter().any(|(_, imp)| !imp.is_default) } - { - continue; - } + { + continue; + } - codegen_fn_attrs.foreign_item_symbol_aliases.push(( - foreign_item, - if i.is_default { Linkage::WeakAny } else { Linkage::External }, - Visibility::Default, - )); - codegen_fn_attrs.flags |= CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM; - - // If the declaration is `#[track_caller]`, derive it onto the implementation - // too. The shim that forwards to this impl (see `add_function_aliases`) takes - // its ABI from the impl's `fn_abi`, so every impl must agree on whether the - // caller-location argument is present, otherwise it would be silently dropped. - if tcx - .codegen_fn_attrs(foreign_item) - .flags - .contains(CodegenFnAttrFlags::TRACK_CALLER) - { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER; - } + codegen_fn_attrs.foreign_item_symbol_aliases.push(( + foreign_item, + if i.is_default { Linkage::WeakAny } else { Linkage::External }, + Visibility::Default, + )); + codegen_fn_attrs.flags |= CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM; + + // If the declaration is `#[track_caller]`, derive it onto the implementation + // too. The shim that forwards to this impl (see `add_function_aliases`) takes + // its ABI from the impl's `fn_abi`, so every impl must agree on whether the + // caller-location argument is present, otherwise it would be silently dropped. + if tcx + .codegen_fn_attrs(foreign_item) + .flags + .contains(CodegenFnAttrFlags::TRACK_CALLER) + { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER; } } AttributeKind::ThreadLocal => { diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index b87dfd0198efc..4a8541ed4c6b7 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -707,7 +707,7 @@ impl<'a> ExtCtxt<'a> { mutability, expr: Some(expr), define_opaque: None, - eii_impls: Default::default(), + eii_impl: None, } .into(), ), diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 0c775e22ccf23..6e17f0f7f4702 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -804,7 +804,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { None, ) } - // When a function has EII implementations attached (via `eii_impls`), + // When a function has EII implementations attached (via `eii_impl`), // use fake tokens so the pretty-printer re-emits the EII attribute // (e.g. `#[hello]`) in the token stream. Without this, the EII // attribute is lost during the token roundtrip performed by @@ -812,7 +812,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { // breaking the EII link on the resulting re-parsed item. Annotatable::Item(item_inner) if matches!(&item_inner.kind, - ItemKind::Fn(f) if !f.eii_impls.is_empty()) => + ItemKind::Fn(f) if f.eii_impl.is_some()) => { rustc_parse::fake_token_stream_for_item( &self.cx.sess.psess, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index db492475a3aa4..2f3ae6a52121e 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1085,7 +1085,7 @@ pub enum AttributeKind { EiiDeclaration(EiiDecl), /// Implementation detail of `#[eii]` - EiiImpls(ThinVec), + EiiImpl(EiiImpl), /// Represents [`#[export_name]`](https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute). ExportName { diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 1e634513fdce2..8e83abd2515e0 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -40,7 +40,7 @@ impl AttributeKind { Doc(_) => Yes, DocComment { .. } => Yes, EiiDeclaration(_) => Yes, - EiiImpls(..) => No, + EiiImpl(..) => No, ExportName { .. } => Yes, ExportStable => No, Feature(..) => No, diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index 57824a91a680f..d9fc3bbcf08c2 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -301,8 +301,7 @@ fn check_no_generics<'tcx>( // since in that case it looks like a duplicate error: the declaration of the EII already can't contain generics. // So, we check here if at least one of the eii impls has ImplResolution::Macro, which indicates it's // not generated as part of the declaration. - && find_attr!(tcx, external_impl, EiiImpls(impls) if impls.iter().any(|i| matches!(i.resolution, EiiImplResolution::Macro(_))) - ) + && find_attr!(tcx, external_impl, EiiImpl(i) if matches!(i.resolution, EiiImplResolution::Macro(_))) { tcx.dcx().emit_err(EiiWithGenerics { span: tcx.def_span(external_impl), diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index f59345cd970eb..23835484ac30b 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1153,9 +1153,7 @@ fn check_item_fn( fn check_eiis_fn(tcx: TyCtxt<'_>, def_id: LocalDefId) { // does the function have an EiiImpl attribute? that contains the defid of a *macro* // that was used to mark the implementation. This is a two step process. - for EiiImpl { resolution, span, .. } in - find_attr!(tcx, def_id, EiiImpls(impls) => impls).into_flat_iter() - { + if let Some(EiiImpl { resolution, span, .. }) = find_attr!(tcx, def_id, EiiImpl(i) => i) { let (foreign_item, name) = match resolution { EiiImplResolution::Macro(def_id) => { // we expect this macro to have the `EiiMacroFor` attribute, that points to a function @@ -1166,11 +1164,11 @@ fn check_eiis_fn(tcx: TyCtxt<'_>, def_id: LocalDefId) { (foreign_item, tcx.item_name(*def_id)) } else { tcx.dcx().span_delayed_bug(*span, "resolved to something that's not an EII"); - continue; + return; } } EiiImplResolution::Known(def_id) => (*def_id, tcx.item_name(*def_id)), - EiiImplResolution::Error(_eg) => continue, + EiiImplResolution::Error(_eg) => return, }; let _ = compare_eii_function_types(tcx, def_id, foreign_item, name, *span); @@ -1180,9 +1178,7 @@ fn check_eiis_fn(tcx: TyCtxt<'_>, def_id: LocalDefId) { fn check_eiis_static<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, ty: Ty<'tcx>) { // does the function have an EiiImpl attribute? that contains the defid of a *macro* // that was used to mark the implementation. This is a two step process. - for EiiImpl { resolution, span, .. } in - find_attr!(tcx, def_id, EiiImpls(impls) => impls).into_flat_iter() - { + if let Some(EiiImpl { resolution, span, .. }) = find_attr!(tcx, def_id, EiiImpl(i) => i) { let (foreign_item, name) = match resolution { EiiImplResolution::Macro(def_id) => { // we expect this macro to have the `EiiMacroFor` attribute, that points to a function @@ -1193,11 +1189,11 @@ fn check_eiis_static<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, ty: Ty<'tcx>) (foreign_item, tcx.item_name(*def_id)) } else { tcx.dcx().span_delayed_bug(*span, "resolved to something that's not an EII"); - continue; + return; } } EiiImplResolution::Known(def_id) => (*def_id, tcx.item_name(*def_id)), - EiiImplResolution::Error(_eg) => continue, + EiiImplResolution::Error(_eg) => return, }; let _ = compare_eii_statics(tcx, def_id, ty, foreign_item, name, *span); diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 9ec74543719dc..ce0e87c0dab5e 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -60,7 +60,6 @@ This API is completely unstable and subject to change. #![feature(gen_blocks)] #![feature(iter_intersperse)] #![feature(never_type)] -#![feature(option_into_flat_iter)] #![feature(slice_partition_dedup)] #![feature(try_blocks)] #![feature(unwrap_infallible)] diff --git a/compiler/rustc_metadata/src/eii.rs b/compiler/rustc_metadata/src/eii.rs index 4328e8de901d8..f50166e8212de 100644 --- a/compiler/rustc_metadata/src/eii.rs +++ b/compiler/rustc_metadata/src/eii.rs @@ -35,7 +35,12 @@ pub(crate) fn collect<'tcx>(tcx: TyCtxt<'tcx>, LocalCrate: LocalCrate) -> EiiMap // iterate over all items in the current crate for id in tcx.hir_crate_items(()).eiis() { - for i in find_attr!(tcx, id, EiiImpls(e) => e).into_flat_iter() { + // if we find a new declaration, add it to the list without a known implementation + if let Some(decl) = find_attr!(tcx, id, EiiDeclaration(d) => *d) { + eiis.entry(decl.foreign_item).or_insert((decl, Default::default())); + } + + if let Some(i) = find_attr!(tcx, id, EiiImpl(i) => i) { let (foreign_item, decl) = match i.resolution { EiiImplResolution::Macro(macro_defid) => { // find the decl for this one if it wasn't in yet (maybe it's from the local crate? not very useful but not illegal) @@ -65,11 +70,6 @@ pub(crate) fn collect<'tcx>(tcx: TyCtxt<'tcx>, LocalCrate: LocalCrate) -> EiiMap .1 .insert(id.into(), *i); } - - // if we find a new declaration, add it to the list without a known implementation - if let Some(decl) = find_attr!(tcx, id, EiiDeclaration(d) => *d) { - eiis.entry(decl.foreign_item).or_insert((decl, Default::default())); - } } eiis diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 1b06c80f83687..7d54df51067b3 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -286,7 +286,7 @@ impl<'a> Parser<'a> { contract, body, define_opaque: None, - eii_impls: ThinVec::new(), + eii_impl: None, })) } else if self.eat_keyword_case(exp!(Extern), case) { if self.eat_keyword_case(exp!(Crate), case) { @@ -1260,7 +1260,7 @@ impl<'a> Parser<'a> { mutability: _, expr, define_opaque, - eii_impls: _, + eii_impl: _, }) => { self.dcx() .emit_err(diagnostics::AssociatedStaticItemNotAllowed { span }); @@ -1526,7 +1526,7 @@ impl<'a> Parser<'a> { expr: body, safety: Safety::Default, define_opaque: None, - eii_impls: ThinVec::default(), + eii_impl: None, })) } _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"), @@ -1664,15 +1664,8 @@ impl<'a> Parser<'a> { self.expect_semi()?; - let item = StaticItem { - ident, - ty, - safety, - mutability, - expr, - define_opaque: None, - eii_impls: ThinVec::default(), - }; + let item = + StaticItem { ident, ty, safety, mutability, expr, define_opaque: None, eii_impl: None }; Ok(ItemKind::Static(Box::new(item))) } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index f9b508476689e..170370a2b2420 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -217,7 +217,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_rustc_legacy_const_generics(item, *attr_span, fn_indexes) } AttributeKind::Doc(attr) => self.check_doc_attrs(attr, hir_id, target), - AttributeKind::EiiImpls(impls) => self.check_eii_impl(impls, target), + AttributeKind::EiiImpl(eii_impl) => self.check_eii_impl(eii_impl, target), AttributeKind::RustcMustImplementOneOf { attr_span, fn_names } => { self.check_rustc_must_implement_one_of(*attr_span, fn_names, hir_id, target) } @@ -472,45 +472,44 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_eii_impl(&self, impls: &[EiiImpl], target: Target) { - for EiiImpl { span, inner_span, resolution, impl_marked_unsafe, is_default: _ } in impls { - match target { - Target::Fn | Target::Static => {} - _ => { - self.dcx().emit_err(diagnostics::EiiImplTarget { span: *span }); - } + fn check_eii_impl(&self, eii_impl: &EiiImpl, target: Target) { + let EiiImpl { span, inner_span, resolution, impl_marked_unsafe, is_default: _ } = eii_impl; + match target { + Target::Fn | Target::Static => {} + _ => { + self.dcx().emit_err(diagnostics::EiiImplTarget { span: *span }); } + } - let needs_unsafe = match resolution { - EiiImplResolution::Macro(eii_macro) => { - find_attr!(self.tcx, *eii_macro, EiiDeclaration(EiiDecl { impl_unsafe, .. }) if *impl_unsafe) - } - EiiImplResolution::Known(foreign_item_did) => { - let foreign_item_did = *foreign_item_did; - self.tcx - .externally_implementable_items(foreign_item_did.krate) - .get(&foreign_item_did) - .map(|(decl, _)| decl.impl_unsafe) - .unwrap_or(false) - } - EiiImplResolution::Error(_) => false, - }; - - if needs_unsafe && !impl_marked_unsafe { - let name = match resolution { - EiiImplResolution::Macro(eii_macro) => self.tcx.item_name(*eii_macro), - EiiImplResolution::Known(def_id) => self.tcx.item_name(*def_id), - EiiImplResolution::Error(_) => unreachable!(), - }; - self.dcx().emit_err(diagnostics::EiiImplRequiresUnsafe { - span: *span, - name, - suggestion: diagnostics::EiiImplRequiresUnsafeSuggestion { - left: inner_span.shrink_to_lo(), - right: inner_span.shrink_to_hi(), - }, - }); + let needs_unsafe = match resolution { + EiiImplResolution::Macro(eii_macro) => { + find_attr!(self.tcx, *eii_macro, EiiDeclaration(EiiDecl { impl_unsafe, .. }) if *impl_unsafe) } + EiiImplResolution::Known(foreign_item_did) => { + let foreign_item_did = *foreign_item_did; + self.tcx + .externally_implementable_items(foreign_item_did.krate) + .get(&foreign_item_did) + .map(|(decl, _)| decl.impl_unsafe) + .unwrap_or(false) + } + EiiImplResolution::Error(_) => false, + }; + + if needs_unsafe && !impl_marked_unsafe { + let name = match resolution { + EiiImplResolution::Macro(eii_macro) => self.tcx.item_name(*eii_macro), + EiiImplResolution::Known(def_id) => self.tcx.item_name(*def_id), + EiiImplResolution::Error(_) => unreachable!(), + }; + self.dcx().emit_err(diagnostics::EiiImplRequiresUnsafe { + span: *span, + name, + suggestion: diagnostics::EiiImplRequiresUnsafeSuggestion { + left: inner_span.shrink_to_lo(), + right: inner_span.shrink_to_hi(), + }, + }); } } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 0b54b265fcee7..2dfea195bec8a 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -303,7 +303,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { expr: _, safety, define_opaque: _, - eii_impls: _, + eii_impl: _, }) => { let safety = match safety { ast::Safety::Unsafe(_) | ast::Safety::Default => hir::Safety::Unsafe, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 535d11d00d718..c34c47401bdca 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1147,7 +1147,7 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc debug!("(resolving function) entering function"); if let FnKind::Fn(_, _, f) = fn_kind { - self.resolve_eii(&f.eii_impls); + self.resolve_eii(f.eii_impl.as_deref()); } // Create a value rib for the function. @@ -2940,7 +2940,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } ItemKind::Static(ast::StaticItem { - ident, ty, expr, define_opaque, eii_impls, .. + ident, ty, expr, define_opaque, eii_impl, .. }) => { self.with_static_rib(def_kind, |this| { this.with_lifetime_rib(LifetimeRibKind::elided(LifetimeRes::Static), |this| { @@ -2953,7 +2953,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } }); self.resolve_define_opaques(define_opaque); - self.resolve_eii(&eii_impls); + self.resolve_eii(eii_impl.as_deref()); } ItemKind::Const(ast::ConstItem { @@ -5568,8 +5568,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } } - fn resolve_eii(&mut self, eii_impls: &[EiiImpl]) { - for EiiImpl { node_id, eii_macro_path, known_eii_macro_resolution, .. } in eii_impls { + fn resolve_eii(&mut self, eii_impl: Option<&EiiImpl>) { + if let Some(EiiImpl { node_id, eii_macro_path, known_eii_macro_resolution, .. }) = eii_impl + { // See docs on the `known_eii_macro_resolution` field: // if we already know the resolution statically, don't bother resolving it. if let Some(target) = known_eii_macro_resolution { diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 3f0b99aa4d780..523e799ef2522 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -332,7 +332,7 @@ fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { expr: le, safety: ls, define_opaque: _, - eii_impls: _, + eii_impl: _, }), Static(box StaticItem { ident: ri, @@ -341,7 +341,7 @@ fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { expr: re, safety: rs, define_opaque: _, - eii_impls: _, + eii_impl: _, }), ) => eq_id(*li, *ri) && lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le.as_deref(), re.as_deref()), ( @@ -381,7 +381,7 @@ fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { contract: lc, body: lb, define_opaque: _, - eii_impls: _, + eii_impl: _, }), Fn(box ast::Fn { defaultness: rd, @@ -391,7 +391,7 @@ fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { contract: rc, body: rb, define_opaque: _, - eii_impls: _, + eii_impl: _, }), ) => { eq_defaultness(*ld, *rd) @@ -539,7 +539,7 @@ fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { expr: le, safety: ls, define_opaque: _, - eii_impls: _, + eii_impl: _, }), Static(box StaticItem { ident: ri, @@ -548,7 +548,7 @@ fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { expr: re, safety: rs, define_opaque: _, - eii_impls: _, + eii_impl: _, }), ) => eq_id(*li, *ri) && eq_ty(lt, rt) && lm == rm && eq_expr_opt(le.as_deref(), re.as_deref()) && ls == rs, ( @@ -560,7 +560,7 @@ fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { contract: lc, body: lb, define_opaque: _, - eii_impls: _, + eii_impl: _, }), Fn(box ast::Fn { defaultness: rd, @@ -570,7 +570,7 @@ fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { contract: rc, body: rb, define_opaque: _, - eii_impls: _, + eii_impl: _, }), ) => { eq_defaultness(*ld, *rd) @@ -649,7 +649,7 @@ fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { contract: lc, body: lb, define_opaque: _, - eii_impls: _, + eii_impl: _, }), Fn(box ast::Fn { defaultness: rd, @@ -659,7 +659,7 @@ fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { contract: rc, body: rb, define_opaque: _, - eii_impls: _, + eii_impl: _, }), ) => { eq_defaultness(*ld, *rd) diff --git a/tests/ui/eii/duplicate/both_decl_and_impl.rs b/tests/ui/eii/duplicate/both_decl_and_impl.rs new file mode 100644 index 0000000000000..a2fc571d3f497 --- /dev/null +++ b/tests/ui/eii/duplicate/both_decl_and_impl.rs @@ -0,0 +1,27 @@ +//@ ignore-backends: gcc +// FIXME(#125418): linking on Windows GNU targets is not yet supported. +//@ ignore-windows-gnu +// Tests that one item can't both define and impl an EII at the same time +#![feature(extern_item_impls)] + +#[eii] +fn a(x: u64); + +#[a] +#[eii] +//~^ ERROR a single item cannot both declare and implement EIIs +fn b(x: u64) {} + +#[eii] +fn c(x: u64); +//~^ ERROR `#[c]` function required, but not found + +#[eii] +#[c] +fn d(x: u64) {} +//~^ ERROR only a small subset of attributes are supported on externally implementable items + +fn main() { + a(42); + b(42); +} diff --git a/tests/ui/eii/duplicate/both_decl_and_impl.stderr b/tests/ui/eii/duplicate/both_decl_and_impl.stderr new file mode 100644 index 0000000000000..1cec485a90cff --- /dev/null +++ b/tests/ui/eii/duplicate/both_decl_and_impl.stderr @@ -0,0 +1,28 @@ +error: a single item cannot both declare and implement EIIs + --> $DIR/both_decl_and_impl.rs:11:1 + | +LL | #[eii] + | ^^^^^^ + +error: only a small subset of attributes are supported on externally implementable items + --> $DIR/both_decl_and_impl.rs:21:1 + | +LL | fn d(x: u64) {} + | ^^^^^^^^^^^^ + | +note: this attribute is not supported + --> $DIR/both_decl_and_impl.rs:20:1 + | +LL | #[c] + | ^^^^ + +error: `#[c]` function required, but not found + --> $DIR/both_decl_and_impl.rs:16:4 + | +LL | fn c(x: u64); + | ^ expected because `#[c]` was declared here in crate `both_decl_and_impl` + | + = help: expected at least one implementation in crate `both_decl_and_impl` or any of its dependencies + +error: aborting due to 3 previous errors + diff --git a/tests/ui/eii/duplicate/multiple_impls.rs b/tests/ui/eii/duplicate/multiple_impls.rs index 80f6147789743..3e541cb16b131 100644 --- a/tests/ui/eii/duplicate/multiple_impls.rs +++ b/tests/ui/eii/duplicate/multiple_impls.rs @@ -1,25 +1,37 @@ -//@ run-pass -//@ check-run-results //@ ignore-backends: gcc // FIXME(#125418): linking on Windows GNU targets is not yet supported. //@ ignore-windows-gnu -// Tests whether one function could implement two EIIs. +// Tests that one item can't implement two EIIs #![feature(extern_item_impls)] #[eii] fn a(x: u64); +//~^ ERROR `#[a]` function required, but not found #[eii] fn b(x: u64); #[a] #[b] +//~^ ERROR a single item cannot implement multiple EIIs fn implementation(x: u64) { println!("{x:?}") } -// what you would write: +#[eii(c)] +//~^ ERROR `#[c]` static required, but not found +static C: u64; + +#[eii(d)] +static D: u64; + +#[c] +#[d] +//~^ ERROR a single item cannot implement multiple EIIs +static IMPL: u64 = 5; + fn main() { a(42); b(42); + println!("{C} {D} {IMPL}") } diff --git a/tests/ui/eii/duplicate/multiple_impls.run.stdout b/tests/ui/eii/duplicate/multiple_impls.run.stdout deleted file mode 100644 index daaac9e303029..0000000000000 --- a/tests/ui/eii/duplicate/multiple_impls.run.stdout +++ /dev/null @@ -1,2 +0,0 @@ -42 -42 diff --git a/tests/ui/eii/duplicate/multiple_impls.stderr b/tests/ui/eii/duplicate/multiple_impls.stderr new file mode 100644 index 0000000000000..efeec635c859a --- /dev/null +++ b/tests/ui/eii/duplicate/multiple_impls.stderr @@ -0,0 +1,30 @@ +error: a single item cannot implement multiple EIIs + --> $DIR/multiple_impls.rs:15:1 + | +LL | #[b] + | ^^^^ + +error: a single item cannot implement multiple EIIs + --> $DIR/multiple_impls.rs:29:1 + | +LL | #[d] + | ^^^^ + +error: `#[a]` function required, but not found + --> $DIR/multiple_impls.rs:8:4 + | +LL | fn a(x: u64); + | ^ expected because `#[a]` was declared here in crate `multiple_impls` + | + = help: expected at least one implementation in crate `multiple_impls` or any of its dependencies + +error: `#[c]` static required, but not found + --> $DIR/multiple_impls.rs:21:7 + | +LL | #[eii(c)] + | ^ expected because `#[c]` was declared here in crate `multiple_impls` + | + = help: expected at least one implementation in crate `multiple_impls` or any of its dependencies + +error: aborting due to 4 previous errors + diff --git a/tests/ui/eii/static/multiple_impls.rs b/tests/ui/eii/static/multiple_impls.rs deleted file mode 100644 index 1129417b958ca..0000000000000 --- a/tests/ui/eii/static/multiple_impls.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ ignore-backends: gcc -// FIXME(#125418): linking on Windows GNU targets is not yet supported. -//@ ignore-windows-gnu -// Tests whether one function could implement two EIIs. -#![feature(extern_item_impls)] - -#[eii(a)] -static A: u64; - -#[eii(b)] -static B: u64; - -#[a] -#[b] -//~^ ERROR static cannot implement multiple EIIs -static IMPL: u64 = 5; - -fn main() { - println!("{A} {B} {IMPL}") -} diff --git a/tests/ui/eii/static/multiple_impls.run.stdout b/tests/ui/eii/static/multiple_impls.run.stdout deleted file mode 100644 index 58945c2b48291..0000000000000 --- a/tests/ui/eii/static/multiple_impls.run.stdout +++ /dev/null @@ -1 +0,0 @@ -5 5 5 diff --git a/tests/ui/eii/static/multiple_impls.stderr b/tests/ui/eii/static/multiple_impls.stderr deleted file mode 100644 index b31331f2483f1..0000000000000 --- a/tests/ui/eii/static/multiple_impls.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: static cannot implement multiple EIIs - --> $DIR/multiple_impls.rs:14:1 - | -LL | #[b] - | ^^^^ - | - = note: this is not allowed because multiple externally implementable statics that alias may be unintuitive - -error: aborting due to 1 previous error -