From 94aff96b0852d7426f37d58688271c83fed341bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 10 Mar 2025 15:00:17 +0100 Subject: [PATCH 01/41] add map for eii ids in resolver --- .../rustc_attr_parsing/src/attributes/mod.rs | 1 + compiler/rustc_attr_parsing/src/context.rs | 3 ++- compiler/rustc_middle/src/ty/mod.rs | 5 ++++- compiler/rustc_passes/src/check_attr.rs | 14 +++++++++++++ compiler/rustc_resolve/src/def_collector.rs | 20 ++++++++++++++++++- compiler/rustc_resolve/src/lib.rs | 7 ++++++- compiler/rustc_span/src/lib.rs | 6 ++++++ library/backtrace | 2 +- library/stdarch | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- src/gcc | 2 +- src/llvm-project | 2 +- src/tools/cargo | 2 +- 15 files changed, 60 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 6ecd6b4d7dbb7..970a1e40c2515 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -27,6 +27,7 @@ pub(crate) mod allow_unstable; pub(crate) mod cfg; pub(crate) mod confusables; pub(crate) mod deprecation; +pub(crate) mod eii; pub(crate) mod repr; pub(crate) mod stability; pub(crate) mod transparency; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 55c3df003fe16..9b0f01a41b006 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -14,6 +14,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; +use crate::attributes::eii::EiiParser; use crate::attributes::repr::ReprParser; use crate::attributes::stability::{ BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, @@ -76,6 +77,7 @@ attribute_groups!( // tidy-alphabetical-start Single, Single, + Single, Single, // tidy-alphabetical-end ]; @@ -209,7 +211,6 @@ impl<'sess> AttributeParser<'sess> { attrs: &'a [ast::Attribute], target_span: Span, omit_doc: OmitDoc, - lower_span: impl Copy + Fn(Span) -> Span, ) -> Vec { let mut attributes = Vec::new(); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 2d69a1c2b553e..eb46dd2866e68 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -50,7 +50,7 @@ use rustc_serialize::{Decodable, Encodable}; use rustc_session::lint::LintBuffer; pub use rustc_session::lint::RegisteredTools; use rustc_span::hygiene::MacroKind; -use rustc_span::{DUMMY_SP, ExpnId, ExpnKind, Ident, Span, Symbol, kw, sym}; +use rustc_span::{EiiId, DUMMY_SP, ExpnId, ExpnKind, Ident, Span, Symbol, kw, sym}; pub use rustc_type_ir::data_structures::{DelayedMap, DelayedSet}; #[allow( hidden_glob_reexports, @@ -229,6 +229,9 @@ pub struct ResolverAstLowering { /// Information about functions signatures for delegation items expansion pub delegation_fn_sigs: LocalDefIdMap, + + /// Map of defids for all items marked with #[eii()]. + pub eii: FxHashMap, } #[derive(Debug)] diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c68f8df49fc70..d9913ed456110 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -124,6 +124,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::Stability { span, .. } | AttributeKind::ConstStability { span, .. }, ) => self.check_stability_promotable(*span, target), + Attribute::Parsed(AttributeKind::Eii(attr_span)) => { + self.check_eii(hir_id, *attr_span, span, target) + } Attribute::Parsed(AttributeKind::AllowInternalUnstable(syms)) => self .check_allow_internal_unstable( hir_id, @@ -474,6 +477,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } + /// Checks if an `#[inline]` is applied to a function or a closure. + fn check_eii(&self, _hir_id: HirId, _attr_span: Span, _defn_span: Span, target: Target) { + match target { + Target::ForeignFn => {} + target => { + // TODO: + bug!("wrong target for EII: {target:?}"); + } + } + } + /// Checks that `#[coverage(..)]` is applied to a function/closure/method, /// or to an impl block or module. fn check_coverage(&self, attr: &Attribute, target_span: Span, target: Target) { diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 13dfb59f27fc0..2cc9d5e4080e0 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -8,8 +8,9 @@ use rustc_expand::expand::AstFragment; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::def_id::LocalDefId; +use rustc_middle::bug; use rustc_span::hygiene::LocalExpnId; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{EiiId, Span, Symbol, sym}; use tracing::debug; use crate::{ImplTraitContext, InvocationParent, Resolver}; @@ -137,6 +138,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { &i.attrs, i.span, OmitDoc::Skip, + None, std::convert::identity, ); @@ -261,6 +263,22 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { let def = self.create_def(fi.id, Some(ident.name), def_kind, fi.span); + if let ForeignItemKind::Fn(_) = fi.kind { + for attr in &fi.attrs { + if attr.has_name(sym::eii) + && let Some([arg]) = attr.meta_item_list().as_deref() + && let Some(lit) = arg.lit() + && let LitKind::Int(i, _) = lit.kind + && let Ok(id) = u32::try_from(i.get()) + { + let id = EiiId::from(id); + if let Some(other) = self.resolver.eii.insert(id, def) { + bug!("{def:?}: {id:?} used more than once (used first on {other:?})"); + } + } + } + } + self.with_parent(def, |this| visit::walk_item(this, fi)); } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 4c47e9ed6992c..812dff6d98a14 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -71,7 +71,7 @@ use rustc_query_system::ich::StableHashingContext; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; use rustc_session::lint::{BuiltinLintDiag, LintBuffer}; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency}; -use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, EiiId, Ident, Span, Symbol, kw, sym}; use smallvec::{SmallVec, smallvec}; use tracing::debug; @@ -1225,6 +1225,9 @@ pub struct Resolver<'ra, 'tcx> { current_crate_outer_attr_insert_span: Span, mods_with_parse_errors: FxHashSet, + + /// Map of defids for all items marked with #[eii()]. + eii: FxHashMap, } /// This provides memory for the rest of the crate. The `'ra` lifetime that is @@ -1580,6 +1583,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { impl_binding_keys: Default::default(), current_crate_outer_attr_insert_span, mods_with_parse_errors: Default::default(), + eii: Default::default(), }; let root_parent_scope = ParentScope::module(graph_root, &resolver); @@ -1694,6 +1698,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { lifetime_elision_allowed: self.lifetime_elision_allowed, lint_buffer: Steal::new(self.lint_buffer), delegation_fn_sigs: self.delegation_fn_sigs, + eii: self.eii, }; ResolverOutputs { global_ctxt, ast_lowering } } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 61c96e67c17f8..eebfd6edd3801 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1181,6 +1181,12 @@ rustc_index::newtype_index! { pub struct AttrId {} } +rustc_index::newtype_index! { + #[orderable] + #[debug_format = "EiiId({})"] + pub struct EiiId {} +} + /// This trait is used to allow encoder specific encodings of certain types. /// It is similar to rustc_type_ir's TyEncoder. pub trait SpanEncoder: Encoder { diff --git a/library/backtrace b/library/backtrace index 6c882eb11984d..9d2c34e7e63af 160000 --- a/library/backtrace +++ b/library/backtrace @@ -1 +1 @@ -Subproject commit 6c882eb11984d737f62e85f36703effaf34c2453 +Subproject commit 9d2c34e7e63afe1e71c333b247065e3b7ba4d883 diff --git a/library/stdarch b/library/stdarch index f1c1839c0deb9..4666c7376f25a 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit f1c1839c0deb985a9f98cbd6b38a6d43f2df6157 +Subproject commit 4666c7376f25a265c74535585d622da3da6dfeb1 diff --git a/src/doc/nomicon b/src/doc/nomicon index c76a20f0d9871..0c10c30cc5473 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit c76a20f0d987145dcedf05c5c073ce8d91f2e82a +Subproject commit 0c10c30cc54736c5c194ce98c50e2de84eeb6e79 diff --git a/src/doc/reference b/src/doc/reference index 387392674d746..3340922df189b 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 387392674d74656f7cb437c05a96f0c52ea8e601 +Subproject commit 3340922df189bddcbaad17dc3927d51a76bcd5ed diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 8a8918c698534..0d7964d5b22cf 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 8a8918c698534547fa8a1a693cb3e7277f0bfb2f +Subproject commit 0d7964d5b22cf920237ef1282d869564b4883b88 diff --git a/src/gcc b/src/gcc index 0ea98a1365b81..13cc8243226a9 160000 --- a/src/gcc +++ b/src/gcc @@ -1 +1 @@ -Subproject commit 0ea98a1365b81f7488073512c850e8ee951a4afd +Subproject commit 13cc8243226a9028bb08ab6c5e1c5fe6d533bcdf diff --git a/src/llvm-project b/src/llvm-project index 8448283b4bd34..a9865ceca0810 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 8448283b4bd34ea00d76fd4f18ec730b549d6e1d +Subproject commit a9865ceca08101071e25f3bba97bba8bf0ea9719 diff --git a/src/tools/cargo b/src/tools/cargo index 7918c7eb59614..d811228b14ae2 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 7918c7eb59614c39f1c4e27e99d557720976bdd7 +Subproject commit d811228b14ae2707323f37346aee3f4147e247e6 From 305268a1f23457e78f40dfde16c2945d5a40d139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 10 Mar 2025 18:48:22 +0100 Subject: [PATCH 02/41] eii_macro_for --- compiler/rustc_ast/src/ast.rs | 2 ++ compiler/rustc_ast/src/mut_visit.rs | 5 ++- compiler/rustc_ast/src/visit.rs | 6 ++-- compiler/rustc_ast_lowering/src/item.rs | 34 +++++++++++++++++-- compiler/rustc_builtin_macros/src/lib.rs | 2 ++ compiler/rustc_feature/src/builtin_attrs.rs | 15 ++++++++ compiler/rustc_hir/src/hir.rs | 7 ++-- compiler/rustc_hir/src/intravisit.rs | 4 +-- compiler/rustc_hir/src/target.rs | 2 +- compiler/rustc_hir_analysis/src/collect.rs | 2 +- .../src/collect/resolve_bound_vars.rs | 2 +- .../rustc_hir_analysis/src/collect/type_of.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 5 +-- compiler/rustc_lint/src/non_local_def.rs | 2 +- compiler/rustc_lint/src/types.rs | 2 +- compiler/rustc_metadata/src/rmeta/decoder.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 15 ++++++-- compiler/rustc_metadata/src/rmeta/mod.rs | 1 + compiler/rustc_middle/src/ty/mod.rs | 5 +-- compiler/rustc_parse/src/parser/item.rs | 8 +++-- compiler/rustc_passes/src/check_attr.rs | 10 +++--- compiler/rustc_passes/src/reachable.rs | 2 +- compiler/rustc_privacy/src/lib.rs | 17 +++++++--- compiler/rustc_resolve/src/def_collector.rs | 18 +--------- compiler/rustc_resolve/src/late.rs | 4 +++ compiler/rustc_resolve/src/lib.rs | 7 +--- compiler/rustc_span/src/lib.rs | 6 ---- compiler/rustc_span/src/symbol.rs | 4 +++ library/core/src/lib.rs | 4 +++ library/core/src/macros/mod.rs | 8 +++++ 30 files changed, 135 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 114b9835b98cf..15f926118671a 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1951,6 +1951,8 @@ pub struct MacroDef { pub body: P, /// `true` if macro was defined with `macro_rules`. pub macro_rules: bool, + + pub eii_macro_for: Option, } #[derive(Clone, Encodable, Decodable, Debug, Copy, Hash, Eq, PartialEq)] diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index e49886721e364..224cd2df64386 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -734,7 +734,10 @@ fn walk_mac(vis: &mut T, mac: &mut MacCall) { } fn walk_macro_def(vis: &mut T, macro_def: &mut MacroDef) { - let MacroDef { body, macro_rules: _ } = macro_def; + let MacroDef { body, macro_rules: _, eii_macro_for } = macro_def; + if let Some(path) = eii_macro_for { + vis.visit_path(path); + } visit_delim_args(vis, body); } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 69a186c8cf1b7..255f9edbef0ff 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -47,7 +47,6 @@ pub enum BoundKind { /// Trait bounds in trait object type. /// E.g., `dyn Bound1 + Bound2 + Bound3`. TraitObject, - /// Super traits of a trait. /// E.g., `trait A: B` SuperTraits, @@ -479,7 +478,10 @@ impl WalkItemKind for ItemKind { ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)), ItemKind::MacroDef(ident, ts) => { try_visit!(visitor.visit_ident(ident)); - try_visit!(visitor.visit_mac_def(ts, id)) + try_visit!(visitor.visit_mac_def(ts, id)); + if let Some(i) = &ts.eii_macro_for { + try_visit!(visitor.visit_path(i, id)); + } } ItemKind::Delegation(box Delegation { id, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index f48a571b86a7d..745b28404f35f 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -22,6 +22,7 @@ use super::{ AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode, ResolverAstLoweringExt, }; +use crate::GenericArgsMode; pub(super) struct ItemLowerer<'a, 'hir> { pub(super) tcx: TyCtxt<'hir>, @@ -462,7 +463,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); hir::ItemKind::TraitAlias(ident, generics, bounds) } - ItemKind::MacroDef(ident, MacroDef { body, macro_rules }) => { + ItemKind::MacroDef(ident, MacroDef { body, macro_rules, eii_macro_for }) => { let ident = self.lower_ident(*ident); let body = P(self.lower_delim_args(body)); let def_id = self.local_def_id(id); @@ -473,8 +474,35 @@ impl<'hir> LoweringContext<'_, 'hir> { def_kind.descr(def_id.to_def_id()) ); }; - let macro_def = self.arena.alloc(ast::MacroDef { body, macro_rules: *macro_rules }); - hir::ItemKind::Macro(ident, macro_def, macro_kind) + + let ast_macro_def = self.arena.alloc(ast::MacroDef { + body, + macro_rules: *macro_rules, + eii_macro_for: None, + }); + + hir::ItemKind::Macro { + name: ident, + ast_macro_def, + kind: macro_kind, + eii_macro_for: eii_macro_for.as_ref().map(|path| { + let lowered = self.lower_qpath( + id, + &None, + path, + ParamMode::Explicit, + crate::AllowReturnTypeNotation::No, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); + + let QPath::Resolved(None, path) = lowered else { + panic!("{lowered:?}"); + }; + + path.res.def_id() + }), + } } ItemKind::Delegation(box delegation) => { let delegation_results = self.lower_delegation(delegation, id, false); diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index c2f5bf0f4571f..0fd9d17dee00a 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -45,6 +45,7 @@ mod define_opaque; mod derive; mod deriving; mod edition_panic; +mod eii; mod env; mod errors; mod format; @@ -123,6 +124,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { global_allocator: global_allocator::expand, test: test::expand_test, test_case: test::expand_test_case, + eii_macro_for: eii::eii_macro_for, } register_derive! { diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index c117e0fcf7ccc..ebf63b78a7212 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1073,6 +1073,21 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ "#[rustc_force_inline] forces a free function to be inlined" ), + gated!( + eii, Normal, template!(Word), + ErrorPreceding, EncodeCrossCrate::No, + eii_internals, "internally used to implement EII" + ), + gated!( + eii_impl, Normal, template!(List: "/*opt*/ default"), + ErrorPreceding, EncodeCrossCrate::No, + eii_internals, "internally used to implement EII" + ), + gated!( + eii_macro_for, Normal, template!(List: "path"), + ErrorPreceding, EncodeCrossCrate::No, + eii_internals, "internally used to implement EII" + ), // ========================================================================== // Internal attributes, Testing: // ========================================================================== diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 107aea4e5a401..24bf8502b92e1 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4113,8 +4113,7 @@ impl<'hir> Item<'hir> { expect_fn, (Ident, &FnSig<'hir>, &'hir Generics<'hir>, BodyId), ItemKind::Fn { ident, sig, generics, body, .. }, (*ident, sig, generics, *body); - expect_macro, (Ident, &ast::MacroDef, MacroKind), - ItemKind::Macro(ident, def, mk), (*ident, def, *mk); + expect_macro, (Ident, &ast::MacroDef, MacroKind, Option), ItemKind::Macro {name: ident, ast_macro_def, kind, eii_macro_for}, (*ident, ast_macro_def, *kind, *eii_macro_for); expect_mod, (Ident, &'hir Mod<'hir>), ItemKind::Mod(ident, m), (*ident, m); @@ -4291,7 +4290,7 @@ pub enum ItemKind<'hir> { has_body: bool, }, /// A MBE macro definition (`macro_rules!` or `macro`). - Macro(Ident, &'hir ast::MacroDef, MacroKind), + Macro { name: Ident, ast_macro_def: &'hir ast::MacroDef, kind: MacroKind, eii_macro_for: Option }, /// A module. Mod(Ident, &'hir Mod<'hir>), /// An external module, e.g. `extern { .. }`. @@ -4391,7 +4390,7 @@ impl ItemKind<'_> { ItemKind::Static(..) => "static item", ItemKind::Const(..) => "constant item", ItemKind::Fn { .. } => "function", - ItemKind::Macro(..) => "macro", + ItemKind::Macro { .. } => "macro", ItemKind::Mod(..) => "module", ItemKind::ForeignMod { .. } => "extern block", ItemKind::GlobalAsm { .. } => "global asm item", diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index a60de4b1fc31b..6a34728c8366a 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -566,8 +566,8 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: item.owner_id.def_id, )); } - ItemKind::Macro(ident, _def, _kind) => { - try_visit!(visitor.visit_ident(ident)); + ItemKind::Macro(name, _def, _kind) => { + try_visit!(visitor.visit_ident(name)); } ItemKind::Mod(ident, ref module) => { try_visit!(visitor.visit_ident(ident)); diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs index 601898023fc39..7e428b97b8491 100644 --- a/compiler/rustc_hir/src/target.rs +++ b/compiler/rustc_hir/src/target.rs @@ -109,7 +109,7 @@ impl Target { ItemKind::Static { .. } => Target::Static, ItemKind::Const(..) => Target::Const, ItemKind::Fn { .. } => Target::Fn, - ItemKind::Macro(..) => Target::MacroDef, + ItemKind::Macro { .. } => Target::MacroDef, ItemKind::Mod(..) => Target::Mod, ItemKind::ForeignMod { .. } => Target::ForeignMod, ItemKind::GlobalAsm { .. } => Target::GlobalAsm, diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 4520fbe352cea..b20adc8c5b8f5 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -676,7 +676,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { // These don't define types. hir::ItemKind::ExternCrate(..) | hir::ItemKind::Use(..) - | hir::ItemKind::Macro(..) + | hir::ItemKind::Macro { .. } | hir::ItemKind::Mod(..) | hir::ItemKind::GlobalAsm { .. } => {} hir::ItemKind::ForeignMod { items, .. } => { diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 709446d09cd25..eaf5a41c26d23 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -626,7 +626,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { hir::ItemKind::ExternCrate(..) | hir::ItemKind::Use(..) - | hir::ItemKind::Macro(..) + | hir::ItemKind::Macro { .. } | hir::ItemKind::Mod(..) | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::Static(..) diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index c20b14df7704b..817975c242f5f 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -256,7 +256,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ ItemKind::GlobalAsm { .. } => tcx.typeck(def_id).node_type(hir_id), ItemKind::Trait(..) | ItemKind::TraitAlias(..) - | ItemKind::Macro(..) + | ItemKind::Macro { .. } | ItemKind::Mod(..) | ItemKind::ForeignMod { .. } | ItemKind::ExternCrate(..) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 09bf84ab64fbe..c92cd72ffd650 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -633,8 +633,9 @@ impl<'a> State<'a> { self.end(cb); self.ann.nested(self, Nested::Body(body)); } - hir::ItemKind::Macro(ident, macro_def, _) => { - self.print_mac_def(macro_def, &ident, item.span, |_| {}); + hir::ItemKind::Macro { name: ident, ast_macro_def, kind: _, eii_macro_for: _ } => { + // TODO: print macro for as comment + self.print_mac_def(ast_macro_def, &ident, item.span, |_| {}); } hir::ItemKind::Mod(ident, mod_) => { let (cb, ib) = self.head("mod"); diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index 9ed11d9cc82ff..0a25d81ecbb58 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -240,7 +240,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { }, ) } - ItemKind::Macro(_, _macro, MacroKind::Bang) + ItemKind::Macro { kind: MacroKind::Bang, .. } if cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export) => { cx.emit_span_lint( diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index f1c06dfe6ce0e..5f1f1ed5db491 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1750,7 +1750,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions { | hir::ItemKind::GlobalAsm { .. } | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::Mod(..) - | hir::ItemKind::Macro(..) + | hir::ItemKind::Macro { .. } | hir::ItemKind::Use(..) | hir::ItemKind::ExternCrate(..) => {} } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index bd813cadedcd4..eb7d8bba2dfe2 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1513,7 +1513,7 @@ impl<'a> CrateMetadataRef<'a> { let macro_rules = self.root.tables.is_macro_rules.get(self, id); let body = self.root.tables.macro_definition.get(self, id).unwrap().decode((self, sess)); - ast::MacroDef { macro_rules, body: ast::ptr::P(body) } + ast::MacroDef { macro_rules, body: ast::ptr::P(body), eii_macro_for: None } } _ => bug!(), } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 7ac72ef814a9c..198965a766e99 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1851,9 +1851,18 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_macro(&mut self, def_id: LocalDefId) { let tcx = self.tcx; - let (_, macro_def, _) = tcx.hir_expect_item(def_id).expect_macro(); - self.tables.is_macro_rules.set(def_id.local_def_index, macro_def.macro_rules); - record!(self.tables.macro_definition[def_id.to_def_id()] <- &*macro_def.body); + let hir::ItemKind::Macro { ast_macro_def, kind: _, eii_macro_for } = + tcx.hir().expect_item(def_id).kind + else { + bug!() + }; + self.tables.is_macro_rules.set(def_id.local_def_index, ast_macro_def.macro_rules); + + if let Some(did) = eii_macro_for { + record!(self.tables.eii_macro_for[def_id.to_def_id()] <- did.index); + } + + record!(self.tables.macro_definition[def_id.to_def_id()] <- &*ast_macro_def.body); } fn encode_native_libraries(&mut self) -> LazyArray { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index c86cf567283fe..40a5fe9c2e94e 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -413,6 +413,7 @@ define_tables! { - optional: attributes: Table>, + eii_macro_for: Table>, // For non-reexported names in a module every name is associated with a separate `DefId`, // so we can take their names, visibilities etc from other encoded tables. module_children_non_reexports: Table>, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index eb46dd2866e68..2d69a1c2b553e 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -50,7 +50,7 @@ use rustc_serialize::{Decodable, Encodable}; use rustc_session::lint::LintBuffer; pub use rustc_session::lint::RegisteredTools; use rustc_span::hygiene::MacroKind; -use rustc_span::{EiiId, DUMMY_SP, ExpnId, ExpnKind, Ident, Span, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, ExpnId, ExpnKind, Ident, Span, Symbol, kw, sym}; pub use rustc_type_ir::data_structures::{DelayedMap, DelayedSet}; #[allow( hidden_glob_reexports, @@ -229,9 +229,6 @@ pub struct ResolverAstLowering { /// Information about functions signatures for delegation items expansion pub delegation_fn_sigs: LocalDefIdMap, - - /// Map of defids for all items marked with #[eii()]. - pub eii: FxHashMap, } #[derive(Debug)] diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index babc55ccc0f9e..6059f7b15a494 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2204,7 +2204,9 @@ impl<'a> Parser<'a> { }; self.psess.gated_spans.gate(sym::decl_macro, lo.to(self.prev_token.span)); - Ok(ItemKind::MacroDef(ident, ast::MacroDef { body, macro_rules: false })) + Ok( + ItemKind::MacroDef(ident, ast::MacroDef { body, macro_rules: false, eii_macro_for: None }), + ) } /// Is this a possibly malformed start of a `macro_rules! foo` item definition? @@ -2251,7 +2253,9 @@ impl<'a> Parser<'a> { self.eat_semi_for_macro_if_needed(&body); self.complain_if_pub_macro(vis, true); - Ok(ItemKind::MacroDef(ident, ast::MacroDef { body, macro_rules: true })) + Ok( + ItemKind::MacroDef(ident, ast::MacroDef { body, macro_rules: true, eii_macro_for: None }), + ) } /// Item macro invocations or `macro_rules!` definitions need inherited visibility. diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d9913ed456110..762c81d0889a5 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -299,7 +299,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::lang | sym::needs_allocator | sym::default_lib_allocator - | sym::custom_mir, + | sym::custom_mir + | sym::eii_macro_for, // TODO: remove .. ] => {} [name, ..] => { @@ -2368,7 +2369,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } else { // special case when `#[macro_export]` is applied to a macro 2.0 - let (_, macro_definition, _) = self.tcx.hir_node(hir_id).expect_item().expect_macro(); + let (_, macro_definition, _, _eii_macro_for) = + self.tcx.hir_node(hir_id).expect_item().expect_macro(); let is_decl_macro = !macro_definition.macro_rules; if is_decl_macro { @@ -2694,9 +2696,9 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { // Historically we've run more checks on non-exported than exported macros, // so this lets us continue to run them while maintaining backwards compatibility. // In the long run, the checks should be harmonized. - if let ItemKind::Macro(_, macro_def, _) = item.kind { + if let ItemKind::Macro { name: _, ast_macro_def, kind: _, eii_macro_for: _ } = item.kind { let def_id = item.owner_id.to_def_id(); - if macro_def.macro_rules && !self.tcx.has_attr(def_id, sym::macro_export) { + if ast_macro_def.macro_rules && !self.tcx.has_attr(def_id, sym::macro_export) { check_non_exported_macro_for_invalid_attrs(self.tcx, item); } } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index f0e8fa986feae..554568acd8273 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -235,7 +235,7 @@ impl<'tcx> ReachableContext<'tcx> { hir::ItemKind::ExternCrate(..) | hir::ItemKind::Use(..) | hir::ItemKind::TyAlias(..) - | hir::ItemKind::Macro(..) + | hir::ItemKind::Macro { .. } | hir::ItemKind::Mod(..) | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::Impl { .. } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index a3b479fdb7a98..ac2ea04ab1621 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -576,8 +576,12 @@ impl<'tcx> EmbargoVisitor<'tcx> { // have normal hygiene, so we can treat them like other items without type // privacy and mark them reachable. DefKind::Macro(_) => { - let item = self.tcx.hir_expect_item(def_id); - if let hir::ItemKind::Macro(_, MacroDef { macro_rules: false, .. }, _) = item.kind { + let item = self.tcx.hir().expect_item(def_id); + if let hir::ItemKind::Macro { + ast_macro_def: MacroDef { macro_rules: false, .. }, + .. + } = item.kind + { if vis.is_accessible_from(module, self.tcx) { self.update(def_id, macro_ev, Level::Reachable); } @@ -656,9 +660,14 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { | hir::ItemKind::GlobalAsm { .. } => {} // The interface is empty, and all nested items are processed by `visit_item`. hir::ItemKind::Mod(..) => {} - hir::ItemKind::Macro(_, macro_def, _) => { + hir::ItemKind::Macro { ast_macro_def, .. } => { + // TODO: consider EII for reachability if let Some(item_ev) = item_ev { - self.update_reachability_from_macro(item.owner_id.def_id, macro_def, item_ev); + self.update_reachability_from_macro( + item.owner_id.def_id, + ast_macro_def, + item_ev, + ); } } hir::ItemKind::Const(..) diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 2cc9d5e4080e0..1da86c887ac94 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -10,7 +10,7 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::def_id::LocalDefId; use rustc_middle::bug; use rustc_span::hygiene::LocalExpnId; -use rustc_span::{EiiId, Span, Symbol, sym}; +use rustc_span::{Span, Symbol, sym}; use tracing::debug; use crate::{ImplTraitContext, InvocationParent, Resolver}; @@ -263,22 +263,6 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { let def = self.create_def(fi.id, Some(ident.name), def_kind, fi.span); - if let ForeignItemKind::Fn(_) = fi.kind { - for attr in &fi.attrs { - if attr.has_name(sym::eii) - && let Some([arg]) = attr.meta_item_list().as_deref() - && let Some(lit) = arg.lit() - && let LitKind::Int(i, _) = lit.kind - && let Ok(id) = u32::try_from(i.get()) - { - let id = EiiId::from(id); - if let Some(other) = self.resolver.eii.insert(id, def) { - bug!("{def:?}: {id:?} used more than once (used first on {other:?})"); - } - } - } - } - self.with_parent(def, |this| visit::walk_item(this, fi)); } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index faee0e7dd5ff9..cf21032442653 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2835,6 +2835,10 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let def_id = self.r.local_def_id(item.id); self.parent_scope.macro_rules = self.r.macro_rules_scopes[&def_id]; } + + if let Some(ref path) = macro_def.eii_macro_for { + self.smart_resolve_path(item.id, &None, path, PathSource::Expr(None)); + } } ItemKind::ForeignMod(_) | ItemKind::GlobalAsm(_) => { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 812dff6d98a14..4c47e9ed6992c 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -71,7 +71,7 @@ use rustc_query_system::ich::StableHashingContext; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; use rustc_session::lint::{BuiltinLintDiag, LintBuffer}; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency}; -use rustc_span::{DUMMY_SP, EiiId, Ident, Span, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; use smallvec::{SmallVec, smallvec}; use tracing::debug; @@ -1225,9 +1225,6 @@ pub struct Resolver<'ra, 'tcx> { current_crate_outer_attr_insert_span: Span, mods_with_parse_errors: FxHashSet, - - /// Map of defids for all items marked with #[eii()]. - eii: FxHashMap, } /// This provides memory for the rest of the crate. The `'ra` lifetime that is @@ -1583,7 +1580,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { impl_binding_keys: Default::default(), current_crate_outer_attr_insert_span, mods_with_parse_errors: Default::default(), - eii: Default::default(), }; let root_parent_scope = ParentScope::module(graph_root, &resolver); @@ -1698,7 +1694,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { lifetime_elision_allowed: self.lifetime_elision_allowed, lint_buffer: Steal::new(self.lint_buffer), delegation_fn_sigs: self.delegation_fn_sigs, - eii: self.eii, }; ResolverOutputs { global_ctxt, ast_lowering } } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index eebfd6edd3801..61c96e67c17f8 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1181,12 +1181,6 @@ rustc_index::newtype_index! { pub struct AttrId {} } -rustc_index::newtype_index! { - #[orderable] - #[debug_format = "EiiId({})"] - pub struct EiiId {} -} - /// This trait is used to allow encoder specific encodings of certain types. /// It is similar to rustc_type_ir's TyEncoder. pub trait SpanEncoder: Encoder { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index f2f6d1a3bcf83..46c5a3ce9f2f1 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -875,6 +875,10 @@ symbols! { effects, eh_catch_typeinfo, eh_personality, + eii, + eii_impl, + eii_internals, + eii_macro_for, emit, emit_enum, emit_enum_variant, diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 64a7ec8906b6b..11fb2a1b61799 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -232,6 +232,10 @@ pub mod autodiff { pub use crate::macros::builtin::autodiff; } +#[cfg(not(bootstrap))] +#[unstable(feature = "eii_internals", issue = "none")] +pub use crate::macros::builtin::eii_macro_for; + #[unstable(feature = "contracts", issue = "128044")] pub mod contracts; diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 7dc8c060cd5bc..e043185d0440c 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1783,4 +1783,12 @@ pub(crate) mod builtin { pub macro deref($pat:pat) { builtin # deref($pat) } + + /// Impl detail of EII + #[cfg(not(bootstrap))] + #[unstable(feature = "eii_internals", issue = "none")] + #[rustc_builtin_macro] + pub macro eii_macro_for($item:item) { + /* compiler built-in */ + } } From 76a8f1db585406aa6c2c131460c37447a2a5f896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 12 Mar 2025 16:47:15 +0100 Subject: [PATCH 03/41] some things work --- compiler/rustc_ast/src/ast.rs | 5 +- compiler/rustc_ast/src/mut_visit.rs | 6 ++ compiler/rustc_ast/src/visit.rs | 7 ++ compiler/rustc_ast_lowering/src/block.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 13 ++-- compiler/rustc_ast_lowering/src/item.rs | 74 +++++++++++-------- compiler/rustc_ast_lowering/src/lib.rs | 6 +- compiler/rustc_ast_lowering/src/pat.rs | 2 +- .../rustc_ast_passes/src/ast_validation.rs | 7 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 14 ++++ .../rustc_ast_pretty/src/pprust/state/item.rs | 13 +++- .../src/attributes.rs | 5 ++ .../rustc_attr_data_structures/src/lib.rs | 3 +- .../src/alloc_error_handler.rs | 1 + compiler/rustc_builtin_macros/src/autodiff.rs | 1 + .../src/deriving/generic/mod.rs | 1 + .../src/global_allocator.rs | 1 + compiler/rustc_builtin_macros/src/lib.rs | 1 + .../rustc_builtin_macros/src/test_harness.rs | 1 + compiler/rustc_feature/src/unstable.rs | 4 + compiler/rustc_hir/src/intravisit.rs | 1 + compiler/rustc_parse/src/parser/item.rs | 1 + compiler/rustc_resolve/src/def_collector.rs | 2 - compiler/rustc_resolve/src/late.rs | 18 ++++- compiler/rustc_span/src/symbol.rs | 1 + 25 files changed, 142 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 15f926118671a..30f1888f6a00e 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3580,6 +3580,9 @@ pub struct Fn { pub contract: Option>, pub define_opaque: Option>, pub body: Option>, + + /// This fn implements some EII, pointed to by the `path` + pub eii_impl: ThinVec<(NodeId, MetaItem)>, } #[derive(Clone, Encodable, Decodable, Debug)] @@ -3929,7 +3932,7 @@ mod size_asserts { static_assert_size!(Block, 32); static_assert_size!(Expr, 72); static_assert_size!(ExprKind, 40); - static_assert_size!(Fn, 184); + static_assert_size!(Fn, 192); static_assert_size!(ForeignItem, 80); static_assert_size!(ForeignItemKind, 16); static_assert_size!(GenericArg, 24); diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 224cd2df64386..238b92a93740f 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -839,11 +839,17 @@ fn walk_fn(vis: &mut T, kind: FnKind<'_>) { body, sig: FnSig { header, decl, span }, define_opaque, + eii_impl, }, ) => { // Visibility is visited as a part of the item. visit_defaultness(vis, defaultness); vis.visit_ident(ident); + + for (node_id, mi) in eii_impl { + vis.visit_id(node_id); + vis.visit_path(&mut mi.path); + } vis.visit_fn_header(header); vis.visit_generics(generics); vis.visit_fn_decl(decl); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 255f9edbef0ff..20941dfdbfd3a 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -955,10 +955,17 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu contract, body, define_opaque, + eii_impl, }, ) => { // Visibility is visited as a part of the item. try_visit!(visitor.visit_ident(ident)); + + // Identifier and visibility are visited as a part of the item. + for (node_id, mi) in eii_impl { + try_visit!(visitor.visit_path(&mi.path, *node_id)); + } + try_visit!(visitor.visit_fn_header(header)); try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_fn_decl(decl)); diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index c3222b79e55c9..5fa801c73c916 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -109,7 +109,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; let span = self.lower_span(l.span); let source = hir::LocalSource::Normal; - self.lower_attrs(hir_id, &l.attrs, l.span); + self.lower_attrs(hir_id, &l.attrs, l.span, &[]); self.arena.alloc(hir::LetStmt { hir_id, super_, ty, pat, init, els, span, source }) } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 9f3aed9216c2d..60e310f6b4f21 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -99,7 +99,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } let expr_hir_id = self.lower_node_id(e.id); - self.lower_attrs(expr_hir_id, &e.attrs, e.span); + self.lower_attrs(expr_hir_id, &e.attrs, e.span, &[]); let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), @@ -679,7 +679,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let guard = arm.guard.as_ref().map(|cond| self.lower_expr(cond)); let hir_id = self.next_id(); let span = self.lower_span(arm.span); - self.lower_attrs(hir_id, &arm.attrs, arm.span); + self.lower_attrs(hir_id, &arm.attrs, arm.span, &[]); let is_never_pattern = pat.is_never_pattern(); // We need to lower the body even if it's unneeded for never pattern in match, // ensure that we can get HirId for DefId if need (issue #137708). @@ -852,6 +852,7 @@ impl<'hir> LoweringContext<'_, 'hir> { span: unstable_span, }], span, + &[], ); } } @@ -1690,7 +1691,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> { let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span); + self.lower_attrs(hir_id, &f.attrs, f.span, &[]); hir::ExprField { hir_id, ident: self.lower_ident(f.ident), @@ -1946,7 +1947,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // // Also, add the attributes to the outer returned expr node. let expr = self.expr_drop_temps_mut(for_span, match_expr); - self.lower_attrs(expr.hir_id, &e.attrs, e.span); + self.lower_attrs(expr.hir_id, &e.attrs, e.span, &[]); expr } @@ -2003,7 +2004,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let val_ident = Ident::with_dummy_span(sym::val); let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident); let val_expr = self.expr_ident(span, val_ident, val_pat_nid); - self.lower_attrs(val_expr.hir_id, &attrs, span); + self.lower_attrs(val_expr.hir_id, &attrs, span, &[]); let continue_pat = self.pat_cf_continue(unstable_span, val_pat); self.arm(continue_pat, val_expr) }; @@ -2034,7 +2035,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ret_expr = self.checked_return(Some(from_residual_expr)); self.arena.alloc(self.expr(try_span, ret_expr)) }; - self.lower_attrs(ret_expr.hir_id, &attrs, ret_expr.span); + self.lower_attrs(ret_expr.hir_id, &attrs, ret_expr.span, &[]); let break_pat = self.pat_cf_break(try_span, residual_local); self.arm(break_pat, ret_expr) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 745b28404f35f..c4bf316ee6af7 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -2,10 +2,11 @@ use rustc_abi::ExternAbi; use rustc_ast::ptr::P; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; +use rustc_attr_parsing::AttributeKind; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; -use rustc_hir::{self as hir, HirId, LifetimeSource, PredicateOrigin}; +use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; +use rustc_hir::{self as hir, HirId, LifetimeSource, IsAnonInPath, PredicateOrigin}; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_span::edit_distance::find_best_match_for_name; @@ -93,7 +94,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { self.with_lctx(CRATE_NODE_ID, |lctx| { let module = lctx.lower_mod(&c.items, &c.spans); // FIXME(jdonszelman): is dummy span ever a problem here? - lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs, DUMMY_SP); + lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs, DUMMY_SP, &[]); hir::OwnerNode::Crate(module) }) } @@ -150,7 +151,16 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> { let vis_span = self.lower_span(i.vis.span); let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); + + let mut extra_hir_attributes = Vec::new(); + if let ItemKind::Fn(f) = &i.kind { + extra_hir_attributes.extend(f.eii_impl.iter().map(|(id, mi)| { + let did = self.lower_path_simple_eii(*id, &mi.path); + hir::Attribute::Parsed(AttributeKind::EiiImpl { eii_macro: did }) + })); + } + + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, &extra_hir_attributes); let kind = self.lower_item_kind(i.span, i.id, hir_id, attrs, vis_span, &i.kind); let item = hir::Item { owner_id: hir_id.expect_owner(), @@ -222,6 +232,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body, contract, define_opaque, + eii_impl, .. }) => { self.with_new_scopes(*fn_sig_span, |this| { @@ -485,23 +496,9 @@ impl<'hir> LoweringContext<'_, 'hir> { name: ident, ast_macro_def, kind: macro_kind, - eii_macro_for: eii_macro_for.as_ref().map(|path| { - let lowered = self.lower_qpath( - id, - &None, - path, - ParamMode::Explicit, - crate::AllowReturnTypeNotation::No, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), - None, - ); - - let QPath::Resolved(None, path) = lowered else { - panic!("{lowered:?}"); - }; - - path.res.def_id() - }), + eii_macro_for: eii_macro_for + .as_ref() + .map(|path| self.lower_path_simple_eii(id, path)), } } ItemKind::Delegation(box delegation) => { @@ -520,6 +517,25 @@ impl<'hir> LoweringContext<'_, 'hir> { } } + fn lower_path_simple_eii(&mut self, id: NodeId, path: &Path) -> DefId { + let lowered = self.lower_qpath( + id, + &None, + path, + ParamMode::Explicit, + crate::AllowReturnTypeNotation::No, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); + + let QPath::Resolved(None, path) = lowered else { + // TODO + panic!("{lowered:?}"); + }; + + path.res.def_id() + } + fn lower_const_item( &mut self, ty: &Ty, @@ -663,7 +679,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> { let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); let owner_id = hir_id.expect_owner(); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, &[]); let (ident, kind) = match &i.kind { ForeignItemKind::Fn(box Fn { sig, ident, generics, define_opaque, .. }) => { let fdec = &sig.decl; @@ -672,11 +688,11 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_generics(generics, i.id, itctx, |this| { ( // Disallow `impl Trait` in foreign items. - this.lower_fn_decl(fdec, i.id, sig.span, FnDeclKind::ExternFn, None), this.lower_fn_params_to_idents(fdec), ) }); + // Unmarked safety in unsafe block defaults to unsafe. let header = self.lower_fn_header(sig.header, hir::Safety::Unsafe, attrs); @@ -737,7 +753,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_variant(&mut self, v: &Variant) -> hir::Variant<'hir> { let hir_id = self.lower_node_id(v.id); - self.lower_attrs(hir_id, &v.attrs, v.span); + self.lower_attrs(hir_id, &v.attrs, v.span, &[]); hir::Variant { hir_id, def_id: self.local_def_id(v.id), @@ -799,7 +815,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::FieldDef<'hir> { let ty = self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy)); let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span); + self.lower_attrs(hir_id, &f.attrs, f.span, &[]); hir::FieldDef { span: self.lower_span(f.span), hir_id, @@ -818,7 +834,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> { let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, &[]); let trait_item_def_id = hir_id.expect_owner(); let (ident, generics, kind, has_default) = match &i.kind { @@ -1011,7 +1027,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let has_value = true; let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value); let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, &[]); let (ident, (generics, kind)) = match &i.kind { AssocItemKind::Const(box ConstItem { @@ -1204,7 +1220,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_param(&mut self, param: &Param) -> hir::Param<'hir> { let hir_id = self.lower_node_id(param.id); - self.lower_attrs(hir_id, ¶m.attrs, param.span); + self.lower_attrs(hir_id, ¶m.attrs, param.span, &[]); hir::Param { hir_id, pat: self.lower_pat(¶m.pat), @@ -1913,7 +1929,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate<'hir> { let hir_id = self.lower_node_id(pred.id); let span = self.lower_span(pred.span); - self.lower_attrs(hir_id, &pred.attrs, span); + self.lower_attrs(hir_id, &pred.attrs, span, &[]); let kind = self.arena.alloc(match &pred.kind { WherePredicateKind::BoundPredicate(WhereBoundPredicate { bound_generic_params, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 8597820073a56..bbd86bbf564c9 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -886,11 +886,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { id: HirId, attrs: &[Attribute], target_span: Span, + extra_hir_attributes: &[hir::Attribute], ) -> &'hir [hir::Attribute] { if attrs.is_empty() { &[] } else { - let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span)); + let mut lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span)); + lowered_attrs.extend(extra_hir_attributes.iter().cloned()); debug_assert_eq!(id.owner, self.current_hir_id_owner); let ret = self.arena.alloc_from_iter(lowered_attrs); @@ -1859,7 +1861,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let (name, kind) = self.lower_generic_param_kind(param, source); let hir_id = self.lower_node_id(param.id); - self.lower_attrs(hir_id, ¶m.attrs, param.span()); + self.lower_attrs(hir_id, ¶m.attrs, param.span(), &[]); hir::GenericParam { hir_id, def_id: self.local_def_id(param.id), diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 58dea472f1d3b..7b1665a124baf 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -94,7 +94,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let fs = self.arena.alloc_from_iter(fields.iter().map(|f| { let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span); + self.lower_attrs(hir_id, &f.attrs, f.span, &[]); hir::PatField { hir_id, diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index cbf4f2f5eb2be..e523eab89860e 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -948,13 +948,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> { contract: _, body, define_opaque: _, + eii_impl, }, ) => { self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident); self.check_defaultness(item.span, *defaultness); + for (id, mi) in eii_impl { + self.visit_path(&mi.path, *id); + } + let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic)); - if body.is_none() && !is_intrinsic && !self.is_sdylib_interface { + if body.is_none() && !is_intrinsic { self.dcx().emit_err(errors::FnWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 0990c9b27eb09..5c7d93a61a3b3 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -2128,6 +2128,14 @@ impl<'a> State<'a> { fn print_meta_item(&mut self, item: &ast::MetaItem) { let ib = self.ibox(INDENT_UNIT); + match item.unsafety { + ast::Safety::Unsafe(_) => { + self.word("unsafe"); + self.popen(); + } + ast::Safety::Default | ast::Safety::Safe(_) => {} + } + match &item.kind { ast::MetaItemKind::Word => self.print_path(&item.path, false, 0), ast::MetaItemKind::NameValue(value) => { @@ -2143,6 +2151,12 @@ impl<'a> State<'a> { self.pclose(); } } + + match item.unsafety { + ast::Safety::Unsafe(_) => self.pclose(), + ast::Safety::Default | ast::Safety::Safe(_) => {} + } + self.end(ib); } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 70cf2f2a45982..d3c732c60fabd 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -672,12 +672,21 @@ 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 } = func; - + let ast::Fn { defaultness, ident, generics, sig, contract, body, define_opaque, eii_impl } = func; self.print_define_opaques(define_opaque.as_deref()); let body_cb_ib = body.as_ref().map(|body| (body, self.head(""))); + for (_, mi) in eii_impl { + self.word("#["); + self.print_meta_item(mi); + self.word("]"); + self.hardbreak(); + } + + if body.is_some() { + self.head(""); + } self.print_visibility(vis); self.print_defaultness(*defaultness); self.print_fn(&sig.decl, sig.header, Some(*ident), generics); diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index d2d1285b0756f..18170ff09da0e 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -2,6 +2,7 @@ use rustc_abi::Align; use rustc_ast::token::CommentKind; use rustc_ast::{self as ast, AttrStyle}; use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute}; +use rustc_span::def_id::DefId; use rustc_span::hygiene::Transparency; use rustc_span::{Span, Symbol}; use thin_vec::ThinVec; @@ -189,6 +190,10 @@ pub enum AttributeKind { span: Span, comment: Symbol, }, + Eii(Span), + EiiImpl { + eii_macro: DefId, + }, MacroTransparency(Transparency), Repr(ThinVec<(ReprAttr, Span)>), Stability { diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs index 679fe935484e8..13efbffd16d3e 100644 --- a/compiler/rustc_attr_data_structures/src/lib.rs +++ b/compiler/rustc_attr_data_structures/src/lib.rs @@ -16,6 +16,7 @@ use rustc_abi::Align; use rustc_ast::token::CommentKind; use rustc_ast::{AttrStyle, IntTy, UintTy}; use rustc_ast_pretty::pp::Printer; +use rustc_span::def_id::DefId; use rustc_span::hygiene::Transparency; use rustc_span::{Span, Symbol}; pub use stability::*; @@ -155,7 +156,7 @@ macro_rules! print_tup { print_tup!(A B C D E F G H); print_skip!(Span, ()); print_disp!(u16, bool, NonZero); -print_debug!(Symbol, UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency); +print_debug!(Symbol, UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency, DefId); /// Finds attributes in sequences of attributes by pattern matching. /// diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index ea406e706660d..e637ff1451c41 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -90,6 +90,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span contract: None, body, define_opaque: None, + eii_impl: ThinVec::new(), })); 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 8c5c20c7af48c..1712775d0a191 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -314,6 +314,7 @@ mod llvm_enzyme { contract: None, body: Some(d_body), define_opaque: None, + eii_impl: ThinVec::new(), }); let mut rustc_ad_attr = P(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 d9aac54ee73c7..f293320ef98a2 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -1039,6 +1039,7 @@ impl<'a> MethodDef<'a> { contract: None, body: Some(body_block), define_opaque: None, + eii_impl: ThinVec::new(), })), tokens: None, }) diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 4b1958bce3223..23ed3b983d622 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -85,6 +85,7 @@ impl AllocFnFactory<'_, '_> { contract: None, body, define_opaque: None, + eii_impl: ThinVec::new(), })); let item = self.cx.item(self.span, self.attrs(), kind); self.cx.stmt_item(self.ty_span, item) diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 0fd9d17dee00a..343f3a2b11f86 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -125,6 +125,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { test: test::expand_test, test_case: test::expand_test_case, eii_macro_for: eii::eii_macro_for, + eii_macro: eii::eii_macro, } register_derive! { diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 56a67b0534d98..aefbcc72e219f 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -348,6 +348,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { contract: None, body: Some(main_body), define_opaque: None, + eii_impl: ThinVec::new(), })); let main = P(ast::Item { diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index a5f89b7a076ae..c59b60efe8c70 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -211,6 +211,8 @@ declare_features! ( (internal, compiler_builtins, "1.13.0", None), /// Allows writing custom MIR (internal, custom_mir, "1.65.0", None), + /// Implementation details of externally implementatble items + (unstable, eii_internals, "CURRENT_RUSTC_VERSION", None), /// Outputs useful `assert!` messages (unstable, generic_assert, "1.63.0", None), /// Allows using the #[rustc_intrinsic] attribute. @@ -495,6 +497,8 @@ declare_features! ( (unstable, extern_system_varargs, "1.86.0", Some(136946)), /// Allows defining `extern type`s. (unstable, extern_types, "1.23.0", Some(43467)), + /// Externally implementatble items + (unstable, eii, "CURRENT_RUSTC_VERSION", Some(125418)), /// Allow using 128-bit (quad precision) floating point numbers. (unstable, f128, "1.78.0", Some(116909)), /// Allow using 16-bit (half precision) floating point numbers. diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 6a34728c8366a..2c8b9959ae7cd 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -66,6 +66,7 @@ use rustc_ast::Label; use rustc_ast::visit::{VisitorResult, try_visit, visit_opt, walk_list}; +use rustc_attr_data_structures::find_attr; use rustc_span::def_id::LocalDefId; use rustc_span::{Ident, Span, Symbol}; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 6059f7b15a494..9c40c0938f738 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -224,6 +224,7 @@ impl<'a> Parser<'a> { contract, body, define_opaque: None, + eii_impl: ThinVec::new(), })) } else if self.eat_keyword(exp!(Extern)) { if self.eat_keyword(exp!(Crate)) { diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 1da86c887ac94..13dfb59f27fc0 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -8,7 +8,6 @@ use rustc_expand::expand::AstFragment; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::def_id::LocalDefId; -use rustc_middle::bug; use rustc_span::hygiene::LocalExpnId; use rustc_span::{Span, Symbol, sym}; use tracing::debug; @@ -138,7 +137,6 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { &i.attrs, i.span, OmitDoc::Skip, - None, std::convert::identity, ); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index cf21032442653..4f800887b521f 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -425,6 +425,8 @@ pub(crate) enum PathSource<'a> { ReturnTypeNotation, /// Paths from `#[define_opaque]` attributes DefineOpaques, + // Resolving a macro + Macro, } impl<'a> PathSource<'a> { @@ -441,6 +443,7 @@ impl<'a> PathSource<'a> { | PathSource::ReturnTypeNotation => ValueNS, PathSource::TraitItem(ns) => ns, PathSource::PreciseCapturingArg(ns) => ns, + PathSource::Macro => MacroNS, } } @@ -456,7 +459,8 @@ impl<'a> PathSource<'a> { | PathSource::TraitItem(..) | PathSource::DefineOpaques | PathSource::Delegation - | PathSource::PreciseCapturingArg(..) => false, + | PathSource::PreciseCapturingArg(..) + | PathSource::Macro => false, } } @@ -497,6 +501,7 @@ impl<'a> PathSource<'a> { }, PathSource::ReturnTypeNotation | PathSource::Delegation => "function", PathSource::PreciseCapturingArg(..) => "type or const parameter", + PathSource::Macro => "macro", } } @@ -591,6 +596,7 @@ impl<'a> PathSource<'a> { Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } ), PathSource::PreciseCapturingArg(MacroNS) => false, + PathSource::Macro => matches!(res, Res::Def(DefKind::Macro(_), _)), } } @@ -610,6 +616,7 @@ impl<'a> PathSource<'a> { (PathSource::TraitItem(..) | PathSource::ReturnTypeNotation, false) => E0576, (PathSource::PreciseCapturingArg(..), true) => E0799, (PathSource::PreciseCapturingArg(..), false) => E0800, + (PathSource::Macro, _) => E0425, } } } @@ -1059,6 +1066,12 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r }; debug!("(resolving function) entering function"); + if let FnKind::Fn(_, _, _, f) = fn_kind { + for (id, mi) in &f.eii_impl { + self.smart_resolve_path(*id, &None, &mi.path, PathSource::Macro); + } + } + // Create a value rib for the function. self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| { // Create a label rib for the function. @@ -2038,7 +2051,8 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { | PathSource::TraitItem(..) | PathSource::Type | PathSource::PreciseCapturingArg(..) - | PathSource::ReturnTypeNotation => false, + | PathSource::ReturnTypeNotation + | PathSource::Macro => false, PathSource::Expr(..) | PathSource::Pat | PathSource::Struct diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 46c5a3ce9f2f1..853dd96c54703 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -878,6 +878,7 @@ symbols! { eii, eii_impl, eii_internals, + eii_macro, eii_macro_for, emit, emit_enum, From 6679336f990bd95d9921adb63e732f046cb0fe82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 12 Mar 2025 16:55:41 +0100 Subject: [PATCH 04/41] add some files --- .../rustc_attr_parsing/src/attributes/eii.rs | 62 +++++++++++++++++++ compiler/rustc_builtin_macros/src/eii.rs | 37 +++++++++++ 2 files changed, 99 insertions(+) create mode 100644 compiler/rustc_attr_parsing/src/attributes/eii.rs create mode 100644 compiler/rustc_builtin_macros/src/eii.rs diff --git a/compiler/rustc_attr_parsing/src/attributes/eii.rs b/compiler/rustc_attr_parsing/src/attributes/eii.rs new file mode 100644 index 0000000000000..83b97b49b7114 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/eii.rs @@ -0,0 +1,62 @@ +use rustc_ast::LitKind; +use rustc_attr_data_structures::AttributeKind; +use rustc_feature::{AttributeTemplate, template}; +use rustc_middle::bug; +use rustc_span::sym; + +use super::{AcceptContext, AttributeOrder, OnDuplicate}; +use crate::attributes::SingleAttributeParser; +use crate::context::Stage; +use crate::parser::ArgParser; + +pub(crate) struct EiiParser; + +impl SingleAttributeParser for EiiParser { + const PATH: &'static [rustc_span::Symbol] = &[sym::eii]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = template!(Word); + + fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + Some(AttributeKind::Eii(cx.attr_span)) + } +} + +// pub(crate) struct EiiImplParser; +// +// impl SingleAttributeParser for EiiImplParser { +// const PATH: &'static [rustc_span::Symbol] = &[sym::eii_impl]; +// const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; +// const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; +// const TEMPLATE: AttributeTemplate = template!(List: ", /*opt*/ default"); +// +// fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { +// let Some(l) = args.list() else { +// cx.expected_list(cx.attr_span); +// return None; +// }; +// +// let mut args = l.mixed(); +// +// let id = args.next().unwrap(); +// let is_default = args.next(); +// assert!(args.next().is_none()); +// +// let Some(id) = id.lit().and_then(|i| if let LitKind::Int(i, _) = i.kind { +// Some(i) +// } else { +// None +// }) else { +// bug!("expected integer"); +// }; +// +// let Ok(id) = u32::try_from(id.get()) else { +// bug!("too large"); +// }; +// let id = EiiId::from(id); +// +// // AttributeKind::EiiImpl { eii: (), is_default: () } +// todo!() +// } +// } +// diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs new file mode 100644 index 0000000000000..cb7eea78e8d9a --- /dev/null +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -0,0 +1,37 @@ +use rustc_ast::{DUMMY_NODE_ID, ItemKind, ast}; +use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_span::Span; + +pub(crate) fn eii_macro_for( + ecx: &mut ExtCtxt<'_>, + _span: Span, + meta_item: &ast::MetaItem, + mut item: Annotatable, +) -> Vec { + let Annotatable::Item(i) = &mut item else { panic!("expected item") }; + let ItemKind::MacroDef(d) = &mut i.kind else { panic!("expected macro def") }; + + let Some(list) = meta_item.meta_item_list() else { panic!("expected list") }; + + d.eii_macro_for = Some(list[0].meta_item().unwrap().path.clone()); + + // Return the original item and the new methods. + vec![item] +} + +pub(crate) fn eii_macro( + ecx: &mut ExtCtxt<'_>, + span: Span, + meta_item: &ast::MetaItem, + mut item: Annotatable, +) -> Vec { + let Annotatable::Item(i) = &mut item else { panic!("expected item") }; + + let ItemKind::Fn(f) = &mut i.kind else { panic!("expected function") }; + + assert!(meta_item.is_word()); + + f.eii_impl.push((DUMMY_NODE_ID, meta_item.clone())); + + vec![item] +} From eef89395ee3e7ac50f097a80dff3a9b30b454cd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 12 Mar 2025 17:07:50 +0100 Subject: [PATCH 05/41] lowering doesn't error --- compiler/rustc_ast_lowering/src/item.rs | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index c4bf316ee6af7..f744b26b633c2 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -156,6 +156,7 @@ impl<'hir> LoweringContext<'_, 'hir> { if let ItemKind::Fn(f) = &i.kind { extra_hir_attributes.extend(f.eii_impl.iter().map(|(id, mi)| { let did = self.lower_path_simple_eii(*id, &mi.path); + hir::Attribute::Parsed(AttributeKind::EiiImpl { eii_macro: did }) })); } @@ -518,22 +519,13 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_path_simple_eii(&mut self, id: NodeId, path: &Path) -> DefId { - let lowered = self.lower_qpath( - id, - &None, - path, - ParamMode::Explicit, - crate::AllowReturnTypeNotation::No, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), - None, - ); - - let QPath::Resolved(None, path) = lowered else { - // TODO - panic!("{lowered:?}"); + let res = self.resolver.get_partial_res(id).unwrap(); + let Some(did) = res.expect_full_res().opt_def_id() else { + self.dcx().span_delayed_bug(path.span, "should have errored in resolve"); + todo!() }; - path.res.def_id() + did } fn lower_const_item( From 3d612643f75e283d7395252e2c94c155b29a84b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 12 Mar 2025 17:16:11 +0100 Subject: [PATCH 06/41] lowering works --- compiler/rustc_ast_lowering/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index bbd86bbf564c9..4835dd3e4252d 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -888,7 +888,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { target_span: Span, extra_hir_attributes: &[hir::Attribute], ) -> &'hir [hir::Attribute] { - if attrs.is_empty() { + if attrs.is_empty() && extra_hir_attributes.is_empty() { &[] } else { let mut lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span)); From 219330177dfec87f2906bff80da1e047cc3a1714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 12 Mar 2025 18:32:03 +0100 Subject: [PATCH 07/41] tidy up things --- compiler/rustc_ast/src/ast.rs | 2 +- compiler/rustc_ast/src/mut_visit.rs | 4 +- compiler/rustc_ast/src/visit.rs | 4 +- compiler/rustc_ast_lowering/src/item.rs | 65 ++++++++++++++----- .../rustc_ast_passes/src/ast_validation.rs | 4 +- .../rustc_ast_pretty/src/pprust/state/item.rs | 4 +- .../src/attributes.rs | 3 + .../rustc_attr_parsing/src/attributes/eii.rs | 62 ------------------ .../rustc_attr_parsing/src/attributes/mod.rs | 1 - compiler/rustc_attr_parsing/src/context.rs | 1 - compiler/rustc_builtin_macros/src/eii.rs | 4 +- compiler/rustc_hir/src/hir.rs | 6 +- compiler/rustc_hir/src/intravisit.rs | 1 - compiler/rustc_hir_pretty/src/lib.rs | 5 +- compiler/rustc_lint/src/non_local_def.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 15 +---- compiler/rustc_metadata/src/rmeta/mod.rs | 1 - compiler/rustc_passes/src/check_attr.rs | 5 +- compiler/rustc_privacy/src/lib.rs | 17 ++--- compiler/rustc_resolve/src/late.rs | 6 +- 20 files changed, 79 insertions(+), 133 deletions(-) delete mode 100644 compiler/rustc_attr_parsing/src/attributes/eii.rs diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 30f1888f6a00e..7123c01de0922 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3582,7 +3582,7 @@ pub struct Fn { pub body: Option>, /// This fn implements some EII, pointed to by the `path` - pub eii_impl: ThinVec<(NodeId, MetaItem)>, + pub eii_impl: ThinVec<(NodeId, Path)>, } #[derive(Clone, Encodable, Decodable, Debug)] diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 238b92a93740f..62748ff8b862c 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -846,9 +846,9 @@ fn walk_fn(vis: &mut T, kind: FnKind<'_>) { visit_defaultness(vis, defaultness); vis.visit_ident(ident); - for (node_id, mi) in eii_impl { + for (node_id, path) in eii_impl { vis.visit_id(node_id); - vis.visit_path(&mut mi.path); + vis.visit_path(path); } vis.visit_fn_header(header); vis.visit_generics(generics); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 20941dfdbfd3a..53538b23709f8 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -962,8 +962,8 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu try_visit!(visitor.visit_ident(ident)); // Identifier and visibility are visited as a part of the item. - for (node_id, mi) in eii_impl { - try_visit!(visitor.visit_path(&mi.path, *node_id)); + for (node_id, path) in eii_impl { + try_visit!(visitor.visit_path(path, *node_id)); } try_visit!(visitor.visit_fn_header(header)); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index f744b26b633c2..079f313e709d8 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -148,21 +148,57 @@ impl<'hir> LoweringContext<'_, 'hir> { } } + fn generate_extra_attrs_for_item_kind( + &mut self, + id: NodeId, + i: &ItemKind, + ) -> Vec { + match i { + ItemKind::Fn(box Fn { eii_impl, .. }) => { + let mut res = Vec::new(); + + for (id, path) in eii_impl { + let did = self.lower_path_simple_eii(*id, path); + res.push(hir::Attribute::Parsed(AttributeKind::EiiImpl { eii_macro: did })); + } + + res + } + ItemKind::MacroDef(_, MacroDef { eii_macro_for: Some(path), .. }) => { + vec![hir::Attribute::Parsed(AttributeKind::EiiMacroFor { + eii_extern_item: self.lower_path_simple_eii(id, path), + })] + } + ItemKind::ExternCrate(..) + | ItemKind::Use(..) + | ItemKind::Static(..) + | ItemKind::Const(..) + | ItemKind::Mod(..) + | ItemKind::ForeignMod(..) + | ItemKind::GlobalAsm(..) + | ItemKind::TyAlias(..) + | ItemKind::Enum(..) + | ItemKind::Struct(..) + | ItemKind::Union(..) + | ItemKind::Trait(..) + | ItemKind::TraitAlias(..) + | ItemKind::Impl(..) + | ItemKind::MacCall(..) + | ItemKind::MacroDef(..) + | ItemKind::Delegation(..) + | ItemKind::DelegationMac(..) => Vec::new(), + } + } + fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> { let vis_span = self.lower_span(i.vis.span); let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - let mut extra_hir_attributes = Vec::new(); - if let ItemKind::Fn(f) = &i.kind { - extra_hir_attributes.extend(f.eii_impl.iter().map(|(id, mi)| { - let did = self.lower_path_simple_eii(*id, &mi.path); - - hir::Attribute::Parsed(AttributeKind::EiiImpl { eii_macro: did }) - })); - } + let extra_hir_attributes = self.generate_extra_attrs_for_item_kind(i.id, &i.kind); let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, &extra_hir_attributes); let kind = self.lower_item_kind(i.span, i.id, hir_id, attrs, vis_span, &i.kind); + let item = hir::Item { owner_id: hir_id.expect_owner(), kind, @@ -233,7 +269,6 @@ impl<'hir> LoweringContext<'_, 'hir> { body, contract, define_opaque, - eii_impl, .. }) => { self.with_new_scopes(*fn_sig_span, |this| { @@ -475,7 +510,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); hir::ItemKind::TraitAlias(ident, generics, bounds) } - ItemKind::MacroDef(ident, MacroDef { body, macro_rules, eii_macro_for }) => { + ItemKind::MacroDef(ident, MacroDef { body, macro_rules, eii_macro_for: _ }) => { let ident = self.lower_ident(*ident); let body = P(self.lower_delim_args(body)); let def_id = self.local_def_id(id); @@ -493,14 +528,7 @@ impl<'hir> LoweringContext<'_, 'hir> { eii_macro_for: None, }); - hir::ItemKind::Macro { - name: ident, - ast_macro_def, - kind: macro_kind, - eii_macro_for: eii_macro_for - .as_ref() - .map(|path| self.lower_path_simple_eii(id, path)), - } + hir::ItemKind::Macro(ident, ast_macro_def, macro_kind) } ItemKind::Delegation(box delegation) => { let delegation_results = self.lower_delegation(delegation, id, false); @@ -680,6 +708,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_generics(generics, i.id, itctx, |this| { ( // Disallow `impl Trait` in foreign items. + this.lower_fn_decl(fdec, i.id, sig.span, FnDeclKind::ExternFn, None), this.lower_fn_params_to_idents(fdec), ) }); diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index e523eab89860e..b1a56b307613d 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -954,8 +954,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident); self.check_defaultness(item.span, *defaultness); - for (id, mi) in eii_impl { - self.visit_path(&mi.path, *id); + for (id, path) in eii_impl { + self.visit_path(path, *id); } let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic)); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index d3c732c60fabd..92c13022967f8 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -677,9 +677,9 @@ impl<'a> State<'a> { let body_cb_ib = body.as_ref().map(|body| (body, self.head(""))); - for (_, mi) in eii_impl { + for (_, path) in eii_impl { self.word("#["); - self.print_meta_item(mi); + self.print_path(path, false, 0); self.word("]"); self.hardbreak(); } diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 18170ff09da0e..8527bd4a0ab8b 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -194,6 +194,9 @@ pub enum AttributeKind { EiiImpl { eii_macro: DefId, }, + EiiMacroFor { + eii_extern_item: DefId, + }, MacroTransparency(Transparency), Repr(ThinVec<(ReprAttr, Span)>), Stability { diff --git a/compiler/rustc_attr_parsing/src/attributes/eii.rs b/compiler/rustc_attr_parsing/src/attributes/eii.rs deleted file mode 100644 index 83b97b49b7114..0000000000000 --- a/compiler/rustc_attr_parsing/src/attributes/eii.rs +++ /dev/null @@ -1,62 +0,0 @@ -use rustc_ast::LitKind; -use rustc_attr_data_structures::AttributeKind; -use rustc_feature::{AttributeTemplate, template}; -use rustc_middle::bug; -use rustc_span::sym; - -use super::{AcceptContext, AttributeOrder, OnDuplicate}; -use crate::attributes::SingleAttributeParser; -use crate::context::Stage; -use crate::parser::ArgParser; - -pub(crate) struct EiiParser; - -impl SingleAttributeParser for EiiParser { - const PATH: &'static [rustc_span::Symbol] = &[sym::eii]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; - const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; - const TEMPLATE: AttributeTemplate = template!(Word); - - fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { - Some(AttributeKind::Eii(cx.attr_span)) - } -} - -// pub(crate) struct EiiImplParser; -// -// impl SingleAttributeParser for EiiImplParser { -// const PATH: &'static [rustc_span::Symbol] = &[sym::eii_impl]; -// const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; -// const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; -// const TEMPLATE: AttributeTemplate = template!(List: ", /*opt*/ default"); -// -// fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { -// let Some(l) = args.list() else { -// cx.expected_list(cx.attr_span); -// return None; -// }; -// -// let mut args = l.mixed(); -// -// let id = args.next().unwrap(); -// let is_default = args.next(); -// assert!(args.next().is_none()); -// -// let Some(id) = id.lit().and_then(|i| if let LitKind::Int(i, _) = i.kind { -// Some(i) -// } else { -// None -// }) else { -// bug!("expected integer"); -// }; -// -// let Ok(id) = u32::try_from(id.get()) else { -// bug!("too large"); -// }; -// let id = EiiId::from(id); -// -// // AttributeKind::EiiImpl { eii: (), is_default: () } -// todo!() -// } -// } -// diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 970a1e40c2515..6ecd6b4d7dbb7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -27,7 +27,6 @@ pub(crate) mod allow_unstable; pub(crate) mod cfg; pub(crate) mod confusables; pub(crate) mod deprecation; -pub(crate) mod eii; pub(crate) mod repr; pub(crate) mod stability; pub(crate) mod transparency; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 9b0f01a41b006..eee655e422e02 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -14,7 +14,6 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; -use crate::attributes::eii::EiiParser; use crate::attributes::repr::ReprParser; use crate::attributes::stability::{ BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index cb7eea78e8d9a..42acf6d86ae4c 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -9,7 +9,7 @@ pub(crate) fn eii_macro_for( mut item: Annotatable, ) -> Vec { let Annotatable::Item(i) = &mut item else { panic!("expected item") }; - let ItemKind::MacroDef(d) = &mut i.kind else { panic!("expected macro def") }; + let ItemKind::MacroDef(_, d) = &mut i.kind else { panic!("expected macro def") }; let Some(list) = meta_item.meta_item_list() else { panic!("expected list") }; @@ -31,7 +31,7 @@ pub(crate) fn eii_macro( assert!(meta_item.is_word()); - f.eii_impl.push((DUMMY_NODE_ID, meta_item.clone())); + f.eii_impl.push((DUMMY_NODE_ID, meta_item.path.clone())); vec![item] } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 24bf8502b92e1..2f7620a1ffc62 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4113,7 +4113,7 @@ impl<'hir> Item<'hir> { expect_fn, (Ident, &FnSig<'hir>, &'hir Generics<'hir>, BodyId), ItemKind::Fn { ident, sig, generics, body, .. }, (*ident, sig, generics, *body); - expect_macro, (Ident, &ast::MacroDef, MacroKind, Option), ItemKind::Macro {name: ident, ast_macro_def, kind, eii_macro_for}, (*ident, ast_macro_def, *kind, *eii_macro_for); + expect_macro, (Ident, &ast::MacroDef, MacroKind), ItemKind::Macro(ident, def, mk), (*ident, def, *mk); expect_mod, (Ident, &'hir Mod<'hir>), ItemKind::Mod(ident, m), (*ident, m); @@ -4290,7 +4290,7 @@ pub enum ItemKind<'hir> { has_body: bool, }, /// A MBE macro definition (`macro_rules!` or `macro`). - Macro { name: Ident, ast_macro_def: &'hir ast::MacroDef, kind: MacroKind, eii_macro_for: Option }, + Macro(Ident, &'hir ast::MacroDef, MacroKind), /// A module. Mod(Ident, &'hir Mod<'hir>), /// An external module, e.g. `extern { .. }`. @@ -4390,7 +4390,7 @@ impl ItemKind<'_> { ItemKind::Static(..) => "static item", ItemKind::Const(..) => "constant item", ItemKind::Fn { .. } => "function", - ItemKind::Macro { .. } => "macro", + ItemKind::Macro(..) => "macro", ItemKind::Mod(..) => "module", ItemKind::ForeignMod { .. } => "extern block", ItemKind::GlobalAsm { .. } => "global asm item", diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 2c8b9959ae7cd..6a34728c8366a 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -66,7 +66,6 @@ use rustc_ast::Label; use rustc_ast::visit::{VisitorResult, try_visit, visit_opt, walk_list}; -use rustc_attr_data_structures::find_attr; use rustc_span::def_id::LocalDefId; use rustc_span::{Ident, Span, Symbol}; diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index c92cd72ffd650..09bf84ab64fbe 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -633,9 +633,8 @@ impl<'a> State<'a> { self.end(cb); self.ann.nested(self, Nested::Body(body)); } - hir::ItemKind::Macro { name: ident, ast_macro_def, kind: _, eii_macro_for: _ } => { - // TODO: print macro for as comment - self.print_mac_def(ast_macro_def, &ident, item.span, |_| {}); + hir::ItemKind::Macro(ident, macro_def, _) => { + self.print_mac_def(macro_def, &ident, item.span, |_| {}); } hir::ItemKind::Mod(ident, mod_) => { let (cb, ib) = self.head("mod"); diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index 0a25d81ecbb58..9ed11d9cc82ff 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -240,7 +240,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { }, ) } - ItemKind::Macro { kind: MacroKind::Bang, .. } + ItemKind::Macro(_, _macro, MacroKind::Bang) if cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export) => { cx.emit_span_lint( diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 198965a766e99..09e6242aa3994 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1851,18 +1851,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_macro(&mut self, def_id: LocalDefId) { let tcx = self.tcx; - let hir::ItemKind::Macro { ast_macro_def, kind: _, eii_macro_for } = - tcx.hir().expect_item(def_id).kind - else { - bug!() - }; - self.tables.is_macro_rules.set(def_id.local_def_index, ast_macro_def.macro_rules); - - if let Some(did) = eii_macro_for { - record!(self.tables.eii_macro_for[def_id.to_def_id()] <- did.index); - } - - record!(self.tables.macro_definition[def_id.to_def_id()] <- &*ast_macro_def.body); + let hir::ItemKind::Macro(_, macro_def, _) = tcx.hir_expect_item(def_id).kind else { bug!() }; + self.tables.is_macro_rules.set(def_id.local_def_index, macro_def.macro_rules); + record!(self.tables.macro_definition[def_id.to_def_id()] <- &*macro_def.body); } fn encode_native_libraries(&mut self) -> LazyArray { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 40a5fe9c2e94e..c86cf567283fe 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -413,7 +413,6 @@ define_tables! { - optional: attributes: Table>, - eii_macro_for: Table>, // For non-reexported names in a module every name is associated with a separate `DefId`, // so we can take their names, visibilities etc from other encoded tables. module_children_non_reexports: Table>, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 762c81d0889a5..336611eec3133 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -2369,8 +2369,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } else { // special case when `#[macro_export]` is applied to a macro 2.0 - let (_, macro_definition, _, _eii_macro_for) = - self.tcx.hir_node(hir_id).expect_item().expect_macro(); + let (_, macro_definition, _) = self.tcx.hir_node(hir_id).expect_item().expect_macro(); let is_decl_macro = !macro_definition.macro_rules; if is_decl_macro { @@ -2696,7 +2695,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { // Historically we've run more checks on non-exported than exported macros, // so this lets us continue to run them while maintaining backwards compatibility. // In the long run, the checks should be harmonized. - if let ItemKind::Macro { name: _, ast_macro_def, kind: _, eii_macro_for: _ } = item.kind { + if let ItemKind::Macro(_, ast_macro_def, _) = item.kind { let def_id = item.owner_id.to_def_id(); if ast_macro_def.macro_rules && !self.tcx.has_attr(def_id, sym::macro_export) { check_non_exported_macro_for_invalid_attrs(self.tcx, item); diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index ac2ea04ab1621..a3b479fdb7a98 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -576,12 +576,8 @@ impl<'tcx> EmbargoVisitor<'tcx> { // have normal hygiene, so we can treat them like other items without type // privacy and mark them reachable. DefKind::Macro(_) => { - let item = self.tcx.hir().expect_item(def_id); - if let hir::ItemKind::Macro { - ast_macro_def: MacroDef { macro_rules: false, .. }, - .. - } = item.kind - { + let item = self.tcx.hir_expect_item(def_id); + if let hir::ItemKind::Macro(_, MacroDef { macro_rules: false, .. }, _) = item.kind { if vis.is_accessible_from(module, self.tcx) { self.update(def_id, macro_ev, Level::Reachable); } @@ -660,14 +656,9 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { | hir::ItemKind::GlobalAsm { .. } => {} // The interface is empty, and all nested items are processed by `visit_item`. hir::ItemKind::Mod(..) => {} - hir::ItemKind::Macro { ast_macro_def, .. } => { - // TODO: consider EII for reachability + hir::ItemKind::Macro(_, macro_def, _) => { if let Some(item_ev) = item_ev { - self.update_reachability_from_macro( - item.owner_id.def_id, - ast_macro_def, - item_ev, - ); + self.update_reachability_from_macro(item.owner_id.def_id, macro_def, item_ev); } } hir::ItemKind::Const(..) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 4f800887b521f..65140412c99a1 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1066,9 +1066,9 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r }; debug!("(resolving function) entering function"); - if let FnKind::Fn(_, _, _, f) = fn_kind { - for (id, mi) in &f.eii_impl { - self.smart_resolve_path(*id, &None, &mi.path, PathSource::Macro); + if let FnKind::Fn(_, _, f) = fn_kind { + for (id, path) in &f.eii_impl { + self.smart_resolve_path(*id, &None, &path, PathSource::Macro); } } From fa839c88ecf414d240e57ccc0dbf1177f96a38a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 13 Mar 2025 14:44:32 +0100 Subject: [PATCH 08/41] typecheck EII --- .../src/check/compare_eii.rs | 218 ++++++++++++++++++ compiler/rustc_hir_analysis/src/check/mod.rs | 1 + .../rustc_hir_analysis/src/check/wfcheck.rs | 19 ++ compiler/rustc_middle/src/traits/mod.rs | 7 + .../src/error_reporting/traits/suggestions.rs | 3 + 5 files changed, 248 insertions(+) create mode 100644 compiler/rustc_hir_analysis/src/check/compare_eii.rs diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs new file mode 100644 index 0000000000000..979ae12cbc1e0 --- /dev/null +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -0,0 +1,218 @@ +use std::borrow::Cow; +use std::iter; + +use rustc_data_structures::fx::FxIndexSet; +use rustc_errors::{Applicability, E0053, struct_span_code_err}; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::{self as hir, HirId, ItemKind}; +use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; +use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; +use rustc_middle::ty; +use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; +use rustc_span::{ErrorGuaranteed, Ident, Span}; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; +use rustc_trait_selection::regions::InferCtxtRegionExt; +use rustc_trait_selection::traits::ObligationCtxt; +use rustc_type_ir::TypingMode; +use tracing::{debug, instrument}; + +// checks whether the signature of some `external_impl`, matches +// the signature of `declaration`, which it is supposed to be compatible +// with in order to implement the item. +pub(crate) fn compare_eii_predicate_entailment<'tcx>( + tcx: TyCtxt<'tcx>, + external_impl: LocalDefId, + declaration: DefId, +) -> Result<(), ErrorGuaranteed> { + let external_impl_span = tcx.def_span(external_impl); + let cause = ObligationCause::new( + external_impl_span, + external_impl, + ObligationCauseCode::CompareEII { external_impl, declaration }, + ); + + // no trait bounds + let param_env = ty::ParamEnv::empty(); + + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); + + // We now need to check that the signature of the impl method is + // compatible with that of the trait method. We do this by + // checking that `impl_fty <: trait_fty`. + // + // FIXME. Unfortunately, this doesn't quite work right now because + // associated type normalization is not integrated into subtype + // checks. For the comparison to be valid, we need to + // normalize the associated types in the impl/trait methods + // first. However, because function types bind regions, just + // calling `FnCtxt::normalize` would have no effect on + // any associated types appearing in the fn arguments or return + // type. + + let wf_tys = FxIndexSet::default(); + + let external_impl_sig = infcx.instantiate_binder_with_fresh_vars( + external_impl_span, + infer::HigherRankedType, + tcx.fn_sig(external_impl).instantiate_identity(), + ); + + let norm_cause = ObligationCause::misc(external_impl_span, external_impl); + let external_impl_sig = ocx.normalize(&norm_cause, param_env, external_impl_sig); + debug!(?external_impl_sig); + + let declaration_sig = tcx.fn_sig(declaration).no_bound_vars().expect("no bound vars"); + let declaration_sig = + tcx.liberate_late_bound_regions(external_impl.to_def_id(), declaration_sig); + let declaration_sig = ocx.normalize(&norm_cause, param_env, declaration_sig); + + // FIXME: We'd want to keep more accurate spans than "the method signature" when + // processing the comparison between the trait and impl fn, but we sadly lose them + // and point at the whole signature when a trait bound or specific input or output + // type would be more appropriate. In other places we have a `Vec` + // corresponding to their `Vec`, but we don't have that here. + // Fixing this would improve the output of test `issue-83765.rs`. + let result = ocx.sup(&cause, param_env, declaration_sig, external_impl_sig); + + if let Err(terr) = result { + debug!(?external_impl_sig, ?declaration_sig, ?terr, "sub_types failed"); + + // TODO: nice error + let emitted = report_eii_mismatch( + infcx, + cause, + param_env, + terr, + (declaration, declaration_sig), + (external_impl, external_impl_sig), + ); + return Err(emitted); + } + + // Check that all obligations are satisfied by the implementation's + // version. + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + let reported = infcx.err_ctxt().report_fulfillment_errors(errors); + return Err(reported); + } + + // Finally, resolve all regions. This catches wily misuses of + // lifetime parameters. + let errors = infcx.resolve_regions(external_impl, param_env, wf_tys); + if !errors.is_empty() { + return Err(infcx + .tainted_by_errors() + .unwrap_or_else(|| infcx.err_ctxt().report_region_errors(external_impl, &errors))); + } + + Ok(()) +} + +fn report_eii_mismatch<'tcx>( + infcx: &InferCtxt<'tcx>, + mut cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + terr: TypeError<'tcx>, + (declaration_did, declaration_sig): (DefId, ty::FnSig<'tcx>), + (external_impl_did, external_impl_sig): (LocalDefId, ty::FnSig<'tcx>), +) -> ErrorGuaranteed { + let tcx = infcx.tcx; + let (impl_err_span, trait_err_span, external_impl_name) = + extract_spans_for_error_reporting(infcx, terr, &cause, declaration_did, external_impl_did); + + let mut diag = struct_span_code_err!( + tcx.dcx(), + impl_err_span, + E0053, // TODO: new error code + "function `{}` has a type that is incompatible with the declaration", + external_impl_name + ); + match &terr { + TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => { + if declaration_sig.inputs().len() == *i { + // Suggestion to change output type. We do not suggest in `async` functions + // to avoid complex logic or incorrect output. + if let ItemKind::Fn { sig, .. } = &tcx.hir().expect_item(external_impl_did).kind + && !sig.header.asyncness.is_async() + { + let msg = "change the output type to match the declaration"; + let ap = Applicability::MachineApplicable; + match sig.decl.output { + hir::FnRetTy::DefaultReturn(sp) => { + let sugg = format!(" -> {}", declaration_sig.output()); + diag.span_suggestion_verbose(sp, msg, sugg, ap); + } + hir::FnRetTy::Return(hir_ty) => { + let sugg = declaration_sig.output(); + diag.span_suggestion_verbose(hir_ty.span, msg, sugg, ap); + } + }; + }; + } else if let Some(trait_ty) = declaration_sig.inputs().get(*i) { + diag.span_suggestion_verbose( + impl_err_span, + "change the parameter type to match the declaration", + trait_ty, + Applicability::MachineApplicable, + ); + } + } + _ => {} + } + + cause.span = impl_err_span; + infcx.err_ctxt().note_type_err( + &mut diag, + &cause, + trait_err_span.map(|sp| (sp, Cow::from("type in declaration"), false)), + Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound { + expected: ty::Binder::dummy(declaration_sig), + found: ty::Binder::dummy(external_impl_sig), + }))), + terr, + false, + None, + ); + + diag.emit() +} + +#[instrument(level = "debug", skip(infcx))] +fn extract_spans_for_error_reporting<'tcx>( + infcx: &infer::InferCtxt<'tcx>, + terr: TypeError<'_>, + cause: &ObligationCause<'tcx>, + declaration: DefId, + external_impl: LocalDefId, +) -> (Span, Option, Ident) { + let tcx = infcx.tcx; + let (mut external_impl_args, external_impl_name) = { + let item = tcx.hir().expect_item(external_impl); + let (sig, _, _) = item.expect_fn(); + ( + sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())), + item.ident, + ) + }; + + let declaration_args = declaration.as_local().map(|def_id| { + let hir_id: HirId = tcx.local_def_id_to_hir_id(def_id); + if let Some(sig) = tcx.hir_fn_sig_by_hir_id(hir_id) { + sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) + } else { + panic!("expected {def_id:?} to be a foreign function"); + } + }); + + match terr { + TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => ( + external_impl_args.nth(i).unwrap(), + declaration_args.and_then(|mut args| args.nth(i)), + external_impl_name, + ), + _ => (cause.span, tcx.hir().span_if_local(declaration), external_impl_name), + } +} diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index fad8abf5fae85..70791a70fab3c 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -64,6 +64,7 @@ a type parameter). pub mod always_applicable; mod check; +mod compare_eii; mod compare_impl_item; mod entry; pub mod intrinsic; diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 2ec14b2f018c3..70bd131e78e4f 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -3,6 +3,7 @@ use std::ops::{ControlFlow, Deref}; use hir::intravisit::{self, Visitor}; use rustc_abi::ExternAbi; +use rustc_attr_parsing::{AttributeKind, find_attr}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; @@ -39,6 +40,7 @@ use rustc_trait_selection::traits::{ use tracing::{debug, instrument}; use {rustc_ast as ast, rustc_hir as hir}; +use super::compare_eii::compare_eii_predicate_entailment; use crate::autoderef::Autoderef; use crate::collect::CollectItemTypesVisitor; use crate::constrained_generic_params::{Parameter, identify_constrained_generic_params}; @@ -1320,6 +1322,23 @@ fn check_item_fn( decl: &hir::FnDecl<'_>, ) -> Result<(), ErrorGuaranteed> { enter_wf_checking_ctxt(tcx, span, def_id, |wfcx| { + // 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. + if let Some(eii_macro) = + find_attr!(tcx.get_all_attrs(def_id), AttributeKind::EiiImpl {eii_macro} => *eii_macro) + { + // we expect this macro to have the `EiiMacroFor` attribute, that points to a function + // signature that we'd like to compare the function we're currently checking with + if let Some(eii_extern_item) = find_attr!(tcx.get_all_attrs(eii_macro), AttributeKind::EiiMacroFor {eii_extern_item} => *eii_extern_item) + { + let _ = compare_eii_predicate_entailment(tcx, def_id, eii_extern_item); + } else { + panic!( + "EII impl macro {eii_macro:?} did not have an eii macro for attribute pointing to a function" + ) + } + } + let sig = tcx.fn_sig(def_id).instantiate_identity(); check_fn_or_method(wfcx, ident.span, sig, decl, def_id); Ok(()) diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 27079af06fcd3..aa33964ef0706 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -309,6 +309,13 @@ pub enum ObligationCauseCode<'tcx> { kind: ty::AssocKind, }, + /// Error derived when checking an impl item is compatible with + /// its corresponding trait item's definition + CompareEII { + external_impl: LocalDefId, + declaration: DefId, + }, + /// Checking that the bounds of a trait's associated type hold for a given impl CheckAssociatedTypeBounds { impl_item_def_id: LocalDefId, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 8801397b77541..b4ae0de1d9952 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3571,6 +3571,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } err.span_note(assoc_span, msg); } + ObligationCauseCode::CompareEII { .. } => { + panic!("trait bounds on EII not yet supported ") + } ObligationCauseCode::TrivialBound => { err.help("see issue #48214"); tcx.disabled_nightly_features( From 60b645dd02721168b89a9b01cdeec458fd0aa5a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 14 Mar 2025 09:45:00 +0100 Subject: [PATCH 09/41] rename compare fn --- compiler/rustc_hir_analysis/src/check/compare_eii.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index 979ae12cbc1e0..b4c41b843b30b 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -20,7 +20,7 @@ use tracing::{debug, instrument}; // checks whether the signature of some `external_impl`, matches // the signature of `declaration`, which it is supposed to be compatible // with in order to implement the item. -pub(crate) fn compare_eii_predicate_entailment<'tcx>( +pub(crate) fn compare_eii_function_types<'tcx>( tcx: TyCtxt<'tcx>, external_impl: LocalDefId, declaration: DefId, From 93971894d922a55d4b7d6770b5348401df7c42dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 14 Mar 2025 11:59:35 +0100 Subject: [PATCH 10/41] unsafe impl --- compiler/rustc_ast/src/ast.rs | 19 ++++++++- compiler/rustc_ast/src/mut_visit.rs | 8 ++-- compiler/rustc_ast/src/visit.rs | 9 ++-- compiler/rustc_ast_lowering/src/item.rs | 23 ++++++---- .../rustc_ast_passes/src/ast_validation.rs | 4 +- .../rustc_ast_pretty/src/pprust/state/item.rs | 14 +++++-- .../src/attributes.rs | 15 +++++-- compiler/rustc_builtin_macros/src/eii.rs | 30 +++++++++++-- .../rustc_hir_analysis/src/check/wfcheck.rs | 14 ++++--- compiler/rustc_passes/messages.ftl | 6 +++ compiler/rustc_passes/src/check_attr.rs | 42 ++++++++++++++----- compiler/rustc_passes/src/errors.rs | 28 +++++++++++++ compiler/rustc_resolve/src/late.rs | 16 +++++-- 13 files changed, 175 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 7123c01de0922..afa1a65ad4b2d 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1952,7 +1952,13 @@ pub struct MacroDef { /// `true` if macro was defined with `macro_rules`. pub macro_rules: bool, - pub eii_macro_for: Option, + pub eii_macro_for: Option, +} + +#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] +pub struct EiiMacroFor { + pub extern_item_path: Path, + pub impl_unsafe: bool, } #[derive(Clone, Encodable, Decodable, Debug, Copy, Hash, Eq, PartialEq)] @@ -3582,7 +3588,16 @@ pub struct Fn { pub body: Option>, /// This fn implements some EII, pointed to by the `path` - pub eii_impl: ThinVec<(NodeId, Path)>, + pub eii_impl: ThinVec, +} + +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct EIIImpl { + pub node_id: NodeId, + pub eii_macro_path: Path, + pub impl_safety: Safety, + pub span: Span, + pub inner_span: Span, } #[derive(Clone, Encodable, Decodable, Debug)] diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 62748ff8b862c..296ef04c5659e 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -735,8 +735,8 @@ fn walk_mac(vis: &mut T, mac: &mut MacCall) { fn walk_macro_def(vis: &mut T, macro_def: &mut MacroDef) { let MacroDef { body, macro_rules: _, eii_macro_for } = macro_def; - if let Some(path) = eii_macro_for { - vis.visit_path(path); + if let Some(EiiMacroFor { extern_item_path, impl_unsafe: _ }) = eii_macro_for { + vis.visit_path(extern_item_path); } visit_delim_args(vis, body); } @@ -846,9 +846,9 @@ fn walk_fn(vis: &mut T, kind: FnKind<'_>) { visit_defaultness(vis, defaultness); vis.visit_ident(ident); - for (node_id, path) in eii_impl { + for EIIImpl { node_id, eii_macro_path, .. } in eii_impl { vis.visit_id(node_id); - vis.visit_path(path); + vis.visit_path(eii_macro_path); } vis.visit_fn_header(header); vis.visit_generics(generics); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 53538b23709f8..01bf121da30e6 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -479,8 +479,8 @@ impl WalkItemKind for ItemKind { ItemKind::MacroDef(ident, ts) => { try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_mac_def(ts, id)); - if let Some(i) = &ts.eii_macro_for { - try_visit!(visitor.visit_path(i, id)); + if let Some(EiiMacroFor { extern_item_path, impl_unsafe: _ }) = &ts.eii_macro_for { + try_visit!(visitor.visit_path(extern_item_path, id)); } } ItemKind::Delegation(box Delegation { @@ -961,9 +961,8 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu // Visibility is visited as a part of the item. try_visit!(visitor.visit_ident(ident)); - // Identifier and visibility are visited as a part of the item. - for (node_id, path) in eii_impl { - try_visit!(visitor.visit_path(path, *node_id)); + for EIIImpl { node_id, eii_macro_path, .. } in eii_impl { + try_visit!(visitor.visit_path(eii_macro_path, *node_id)); } try_visit!(visitor.visit_fn_header(header)); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 079f313e709d8..857922d094b01 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -155,18 +155,25 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> Vec { match i { ItemKind::Fn(box Fn { eii_impl, .. }) => { - let mut res = Vec::new(); - - for (id, path) in eii_impl { - let did = self.lower_path_simple_eii(*id, path); - res.push(hir::Attribute::Parsed(AttributeKind::EiiImpl { eii_macro: did })); + let mut eii_impls = ThinVec::new(); + for EIIImpl { node_id, eii_macro_path, impl_safety, span, inner_span } in eii_impl { + let did = self.lower_path_simple_eii(*node_id, eii_macro_path); + eii_impls.push(rustc_attr_parsing::EIIImpl { + eii_macro: did, + span: self.lower_span(*span), + inner_span: self.lower_span(*inner_span), + impl_marked_unsafe: self + .lower_safety(*impl_safety, hir::Safety::Safe) + .is_unsafe(), + }) } - res + vec![hir::Attribute::Parsed(AttributeKind::EiiImpl(eii_impls))] } - ItemKind::MacroDef(_, MacroDef { eii_macro_for: Some(path), .. }) => { + ItemKind::MacroDef(_, MacroDef { eii_macro_for: Some(EiiMacroFor { extern_item_path, impl_unsafe }), .. }) => { vec![hir::Attribute::Parsed(AttributeKind::EiiMacroFor { - eii_extern_item: self.lower_path_simple_eii(id, path), + eii_extern_item: self.lower_path_simple_eii(id, extern_item_path), + impl_unsafe: *impl_unsafe, })] } ItemKind::ExternCrate(..) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index b1a56b307613d..e7609b8e05286 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -954,8 +954,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident); self.check_defaultness(item.span, *defaultness); - for (id, path) in eii_impl { - self.visit_path(path, *id); + for EIIImpl { node_id, eii_macro_path, .. } in eii_impl { + self.visit_path(eii_macro_path, *node_id); } let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic)); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 92c13022967f8..997e94674c9cb 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -1,8 +1,7 @@ use ast::StaticItem; use itertools::{Itertools, Position}; -use rustc_ast as ast; -use rustc_ast::ModKind; use rustc_ast::ptr::P; +use rustc_ast::{self as ast, EIIImpl, ModKind, Safety}; use rustc_span::Ident; use crate::pp::BoxMarker; @@ -677,9 +676,16 @@ impl<'a> State<'a> { let body_cb_ib = body.as_ref().map(|body| (body, self.head(""))); - for (_, path) in eii_impl { + for EIIImpl { eii_macro_path, impl_safety, .. } in eii_impl { self.word("#["); - self.print_path(path, false, 0); + if let Safety::Unsafe(..) = impl_safety { + self.word("unsafe"); + self.popen(); + } + self.print_path(eii_macro_path, false, 0); + if let Safety::Unsafe(..) = impl_safety { + self.pclose(); + } self.word("]"); self.hardbreak(); } diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 8527bd4a0ab8b..e06f46497849c 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -139,6 +139,14 @@ impl Deprecation { } } +#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] +pub struct EIIImpl { + pub eii_macro: DefId, + pub impl_marked_unsafe: bool, + pub span: Span, + pub inner_span: Span, +} + /// Represent parsed, *built in*, inert attributes. /// /// That means attributes that are not actually ever expanded. @@ -190,12 +198,11 @@ pub enum AttributeKind { span: Span, comment: Symbol, }, - Eii(Span), - EiiImpl { - eii_macro: DefId, - }, + EiiImpl(ThinVec), EiiMacroFor { eii_extern_item: DefId, + /// whether or not it is unsafe to implement this EII + impl_unsafe: bool, }, MacroTransparency(Transparency), Repr(ThinVec<(ReprAttr, Span)>), diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index 42acf6d86ae4c..8e60563fc4eb3 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -1,6 +1,6 @@ -use rustc_ast::{DUMMY_NODE_ID, ItemKind, ast}; +use rustc_ast::{DUMMY_NODE_ID, EIIImpl, EiiMacroFor, ItemKind, ast}; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::Span; +use rustc_span::{Span, kw}; pub(crate) fn eii_macro_for( ecx: &mut ExtCtxt<'_>, @@ -13,7 +13,22 @@ pub(crate) fn eii_macro_for( let Some(list) = meta_item.meta_item_list() else { panic!("expected list") }; - d.eii_macro_for = Some(list[0].meta_item().unwrap().path.clone()); + let Some(extern_item_path) = list.get(0).and_then(|i| i.meta_item()).map(|i| i.path.clone()) + else { + panic!("expected a path to an `extern` item"); + }; + + let impl_unsafe = if let Some(i) = list.get(1) { + if i.lit().and_then(|i| i.kind.str()).is_some_and(|i| i == kw::Unsafe) { + true + } else { + panic!("expected the string `\"unsafe\"` here or no other arguments"); + } + } else { + false + }; + + d.eii_macro_for = Some(EiiMacroFor { extern_item_path, impl_unsafe }); // Return the original item and the new methods. vec![item] @@ -31,7 +46,14 @@ pub(crate) fn eii_macro( assert!(meta_item.is_word()); - f.eii_impl.push((DUMMY_NODE_ID, meta_item.path.clone())); + f.eii_impl.push(EIIImpl { + node_id: DUMMY_NODE_ID, + eii_macro_path: meta_item.path.clone(), + impl_safety: meta_item.unsafety, + span, + inner_span: meta_item.span, + is_default: false, + }); vec![item] } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 70bd131e78e4f..6feb08a6749ef 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -3,7 +3,7 @@ use std::ops::{ControlFlow, Deref}; use hir::intravisit::{self, Visitor}; use rustc_abi::ExternAbi; -use rustc_attr_parsing::{AttributeKind, find_attr}; +use rustc_attr_parsing::{AttributeKind, EIIImpl, find_attr}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; @@ -40,7 +40,7 @@ use rustc_trait_selection::traits::{ use tracing::{debug, instrument}; use {rustc_ast as ast, rustc_hir as hir}; -use super::compare_eii::compare_eii_predicate_entailment; +use super::compare_eii::{compare_eii_function_types, compare_eii_predicate_entailment}; use crate::autoderef::Autoderef; use crate::collect::CollectItemTypesVisitor; use crate::constrained_generic_params::{Parameter, identify_constrained_generic_params}; @@ -1324,14 +1324,16 @@ fn check_item_fn( enter_wf_checking_ctxt(tcx, span, def_id, |wfcx| { // 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. - if let Some(eii_macro) = - find_attr!(tcx.get_all_attrs(def_id), AttributeKind::EiiImpl {eii_macro} => *eii_macro) + for EIIImpl { eii_macro, .. } in + find_attr!(tcx.get_all_attrs(def_id), AttributeKind::EiiImpl(impls) => impls) + .into_iter() + .flatten() { // we expect this macro to have the `EiiMacroFor` attribute, that points to a function // signature that we'd like to compare the function we're currently checking with - if let Some(eii_extern_item) = find_attr!(tcx.get_all_attrs(eii_macro), AttributeKind::EiiMacroFor {eii_extern_item} => *eii_extern_item) + if let Some(eii_extern_item) = find_attr!(tcx.get_all_attrs(*eii_macro), AttributeKind::EiiMacroFor {eii_extern_item, ..} => *eii_extern_item) { - let _ = compare_eii_predicate_entailment(tcx, def_id, eii_extern_item); + let _ = compare_eii_function_types(tcx, def_id, eii_extern_item); } else { panic!( "EII impl macro {eii_macro:?} did not have an eii macro for attribute pointing to a function" diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 6d815e510ea20..994348272b2c1 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -311,6 +311,12 @@ passes_duplicate_lang_item_crate_depends = .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} .second_definition_path = second definition in `{$crate_name}` loaded from {$path} +passes_eii_impl_not_function = + `eii_macro_for` is only valid on functions + +passes_eii_impl_requires_unsafe = + `#[{$name}]` is unsafe to implement +passes_eii_impl_requires_unsafe_suggestion = wrap the attribute in `unsafe(...)` passes_export_name = attribute should be applied to a free function, impl method or static .label = not a free function, impl method or static diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 336611eec3133..525d3cccbe1f9 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -10,7 +10,7 @@ use std::collections::hash_map::Entry; use rustc_abi::{Align, ExternAbi, Size}; use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast}; -use rustc_attr_parsing::{AttributeKind, ReprAttr, find_attr}; +use rustc_attr_parsing::{AttributeKind, EIIImpl, ReprAttr, find_attr}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; @@ -124,8 +124,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::Stability { span, .. } | AttributeKind::ConstStability { span, .. }, ) => self.check_stability_promotable(*span, target), - Attribute::Parsed(AttributeKind::Eii(attr_span)) => { - self.check_eii(hir_id, *attr_span, span, target) + Attribute::Parsed(AttributeKind::EiiImpl(impls)) => { + self.check_eii_impl(hir_id, impls, span, target) + } + Attribute::Parsed(AttributeKind::EiiMacroFor { .. }) => { + // no checks needed } Attribute::Parsed(AttributeKind::AllowInternalUnstable(syms)) => self .check_allow_internal_unstable( @@ -478,13 +481,32 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks if an `#[inline]` is applied to a function or a closure. - fn check_eii(&self, _hir_id: HirId, _attr_span: Span, _defn_span: Span, target: Target) { - match target { - Target::ForeignFn => {} - target => { - // TODO: - bug!("wrong target for EII: {target:?}"); + fn check_eii_impl( + &self, + _hir_id: HirId, + impls: &[EIIImpl], + _target_span: Span, + target: Target, + ) { + for EIIImpl { span, inner_span, eii_macro, impl_marked_unsafe } in impls { + match target { + Target::Fn => {} + _ => { + self.dcx().emit_err(errors::EIIImplNotFunction { span: *span }); + } + } + + if find_attr!(self.tcx.get_all_attrs(*eii_macro), AttributeKind::EiiMacroFor { impl_unsafe, .. } if *impl_unsafe) + && !impl_marked_unsafe + { + self.dcx().emit_err(errors::EIIImplRequiresUnsafe { + span: *span, + name: self.tcx.item_name(*eii_macro), + suggestion: errors::EIIImplRequiresUnsafeSuggestion { + left: inner_span.shrink_to_lo(), + right: inner_span.shrink_to_hi(), + }, + }); } } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 00682a9c7a794..49f18a25ac8d3 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1973,3 +1973,31 @@ pub(crate) enum UnexportableItem<'a> { field_name: &'a str, }, } + +#[diag(passes_eii_impl_not_function)] +pub(crate) struct EIIImplNotFunction { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_eii_impl_requires_unsafe)] +pub(crate) struct EIIImplRequiresUnsafe { + #[primary_span] + pub span: Span, + pub name: Symbol, + #[subdiagnostic] + pub suggestion: EIIImplRequiresUnsafeSuggestion, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + passes_eii_impl_requires_unsafe_suggestion, + applicability = "machine-applicable" +)] +pub(crate) struct EIIImplRequiresUnsafeSuggestion { + #[suggestion_part(code = "unsafe(")] + pub left: Span, + #[suggestion_part(code = ")")] + pub right: Span, +} diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 65140412c99a1..665d927dfb6e6 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1066,9 +1066,10 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r }; debug!("(resolving function) entering function"); + if let FnKind::Fn(_, _, f) = fn_kind { - for (id, path) in &f.eii_impl { - self.smart_resolve_path(*id, &None, &path, PathSource::Macro); + for EIIImpl { node_id, eii_macro_path, .. } in &f.eii_impl { + self.smart_resolve_path(*node_id, &None, &eii_macro_path, PathSource::Macro); } } @@ -2850,8 +2851,15 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.parent_scope.macro_rules = self.r.macro_rules_scopes[&def_id]; } - if let Some(ref path) = macro_def.eii_macro_for { - self.smart_resolve_path(item.id, &None, path, PathSource::Expr(None)); + if let Some(EiiMacroFor { extern_item_path, impl_unsafe: _ }) = + ¯o_def.eii_macro_for + { + self.smart_resolve_path( + item.id, + &None, + extern_item_path, + PathSource::Expr(None), + ); } } From 163d12b229a461af8c4d3de154022d379d225f98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 14 Mar 2025 14:14:17 +0100 Subject: [PATCH 11/41] add tests --- .../src/check/compare_eii.rs | 10 +++++--- tests/ui/eii/subtype_1.rs | 25 +++++++++++++++++++ tests/ui/eii/subtype_2.rs | 25 +++++++++++++++++++ tests/ui/eii/unsafe_impl_err.rs | 24 ++++++++++++++++++ tests/ui/eii/unsafe_impl_err.stderr | 13 ++++++++++ tests/ui/eii/unsafe_impl_ok.rs | 25 +++++++++++++++++++ tests/ui/eii/wrong_ret_ty.rs | 25 +++++++++++++++++++ tests/ui/eii/wrong_ret_ty.stderr | 21 ++++++++++++++++ tests/ui/eii/wrong_ty.rs | 25 +++++++++++++++++++ tests/ui/eii/wrong_ty.stderr | 17 +++++++++++++ 10 files changed, 206 insertions(+), 4 deletions(-) create mode 100644 tests/ui/eii/subtype_1.rs create mode 100644 tests/ui/eii/subtype_2.rs create mode 100644 tests/ui/eii/unsafe_impl_err.rs create mode 100644 tests/ui/eii/unsafe_impl_err.stderr create mode 100644 tests/ui/eii/unsafe_impl_ok.rs create mode 100644 tests/ui/eii/wrong_ret_ty.rs create mode 100644 tests/ui/eii/wrong_ret_ty.stderr create mode 100644 tests/ui/eii/wrong_ty.rs create mode 100644 tests/ui/eii/wrong_ty.stderr diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index b4c41b843b30b..d7db8f0398d39 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -2,14 +2,16 @@ use std::borrow::Cow; use std::iter; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{Applicability, E0053, struct_span_code_err}; +use rustc_errors::{ + Applicability, Applicability, E0053, E0053, struct_span_code_err, struct_span_code_err, +}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{self as hir, HirId, ItemKind}; +use rustc_hir::{self as hir, self as hir, HirId, HirId, ItemKind, ItemKind}; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty; use rustc_middle::ty::TyCtxt; -use rustc_middle::ty::error::{ExpectedFound, TypeError}; +use rustc_middle::ty::error::{ExpectedFound, ExpectedFound, TypeError, TypeError}; use rustc_span::{ErrorGuaranteed, Ident, Span}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::regions::InferCtxtRegionExt; @@ -63,7 +65,7 @@ pub(crate) fn compare_eii_function_types<'tcx>( let external_impl_sig = ocx.normalize(&norm_cause, param_env, external_impl_sig); debug!(?external_impl_sig); - let declaration_sig = tcx.fn_sig(declaration).no_bound_vars().expect("no bound vars"); + let declaration_sig = tcx.fn_sig(declaration).instantiate_identity(); let declaration_sig = tcx.liberate_late_bound_regions(external_impl.to_def_id(), declaration_sig); let declaration_sig = ocx.normalize(&norm_cause, param_env, declaration_sig); diff --git a/tests/ui/eii/subtype_1.rs b/tests/ui/eii/subtype_1.rs new file mode 100644 index 0000000000000..5632dc99b4ed5 --- /dev/null +++ b/tests/ui/eii/subtype_1.rs @@ -0,0 +1,25 @@ +//@ compile-flags: --crate-type rlib +//@ check-pass +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[core::eii_macro_for(bar)] +#[rustc_builtin_macro(eii_macro)] +macro foo() { + +} + +unsafe extern "Rust" { + safe fn bar<'a, 'b>(x: &'b u64) -> &'a u64; +} + +#[foo] +fn other<'a, 'b>(x: &'b u64) -> &'b u64 { + &0 +} + +fn main() { + bar(&0); +} diff --git a/tests/ui/eii/subtype_2.rs b/tests/ui/eii/subtype_2.rs new file mode 100644 index 0000000000000..9d8164cef2cd0 --- /dev/null +++ b/tests/ui/eii/subtype_2.rs @@ -0,0 +1,25 @@ +//@ compile-flags: --crate-type rlib +//@ check-pass +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[core::eii_macro_for(bar)] +#[rustc_builtin_macro(eii_macro)] +macro foo() { + +} + +unsafe extern "Rust" { + safe fn bar<'a>(x: &'static u64) -> &'a u64; +} + +#[foo] +fn other<'a>(x: &'a u64) -> &'static u64 { + &0 +} + +fn main() { + bar(&0); +} diff --git a/tests/ui/eii/unsafe_impl_err.rs b/tests/ui/eii/unsafe_impl_err.rs new file mode 100644 index 0000000000000..3f6f07e3b1184 --- /dev/null +++ b/tests/ui/eii/unsafe_impl_err.rs @@ -0,0 +1,24 @@ +//@ compile-flags: --crate-type rlib +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[core::eii_macro_for(bar, "unsafe")] +#[rustc_builtin_macro(eii_macro)] +macro foo() { + +} + +unsafe extern "Rust" { + safe fn bar(x: u64) -> u64; +} + +#[foo] //~ ERROR `#[foo]` is unsafe to implement +fn other(x: u64) -> u64 { + x +} + +fn main() { + bar(0); +} diff --git a/tests/ui/eii/unsafe_impl_err.stderr b/tests/ui/eii/unsafe_impl_err.stderr new file mode 100644 index 0000000000000..6badcbe17f168 --- /dev/null +++ b/tests/ui/eii/unsafe_impl_err.stderr @@ -0,0 +1,13 @@ +error: `#[foo]` is unsafe to implement + --> $DIR/unsafe_impl_err.rs:17:1 + | +LL | #[foo] + | ^^^^^^ + | +help: wrap the attribute in `unsafe(...)` + | +LL | #[unsafe(foo)] + | +++++++ + + +error: aborting due to 1 previous error + diff --git a/tests/ui/eii/unsafe_impl_ok.rs b/tests/ui/eii/unsafe_impl_ok.rs new file mode 100644 index 0000000000000..ecc254ca8ffd8 --- /dev/null +++ b/tests/ui/eii/unsafe_impl_ok.rs @@ -0,0 +1,25 @@ +//@ compile-flags: --crate-type rlib +//@ check-pass +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[core::eii_macro_for(bar, "unsafe")] +#[rustc_builtin_macro(eii_macro)] +macro foo() { + +} + +unsafe extern "Rust" { + safe fn bar(x: u64) -> u64; +} + +#[unsafe(foo)] +fn other(x: u64) -> u64 { + x +} + +fn main() { + bar(0); +} diff --git a/tests/ui/eii/wrong_ret_ty.rs b/tests/ui/eii/wrong_ret_ty.rs new file mode 100644 index 0000000000000..6bd728992bd94 --- /dev/null +++ b/tests/ui/eii/wrong_ret_ty.rs @@ -0,0 +1,25 @@ +//@ compile-flags: --crate-type rlib +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[core::eii_macro_for(bar)] +#[rustc_builtin_macro(eii_macro)] +macro foo() { + +} + +unsafe extern "Rust" { + safe fn bar(x: u64) -> u64; +} + +#[foo] +fn other(_x: u64) { +//~^ ERROR function `other` has a type that is incompatible with the declaration + +} + +fn main() { + bar(0); +} diff --git a/tests/ui/eii/wrong_ret_ty.stderr b/tests/ui/eii/wrong_ret_ty.stderr new file mode 100644 index 0000000000000..c84de5e6e11ed --- /dev/null +++ b/tests/ui/eii/wrong_ret_ty.stderr @@ -0,0 +1,21 @@ +error[E0053]: function `other` has a type that is incompatible with the declaration + --> $DIR/wrong_ret_ty.rs:18:18 + | +LL | fn other(_x: u64) { + | ^ expected `u64`, found `()` + | +note: type in declaration + --> $DIR/wrong_ret_ty.rs:14:28 + | +LL | safe fn bar(x: u64) -> u64; + | ^^^ + = note: expected signature `fn(_) -> u64` + found signature `fn(_) -> ()` +help: change the output type to match the declaration + | +LL | fn other(_x: u64) -> u64 { + | ++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/eii/wrong_ty.rs b/tests/ui/eii/wrong_ty.rs new file mode 100644 index 0000000000000..bcf2ac0f1135d --- /dev/null +++ b/tests/ui/eii/wrong_ty.rs @@ -0,0 +1,25 @@ +//@ compile-flags: --crate-type rlib +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[core::eii_macro_for(bar)] +#[rustc_builtin_macro(eii_macro)] +macro foo() { + +} + +unsafe extern "Rust" { + safe fn bar(x: u64) -> u64; +} + +#[foo] +fn other() -> u64 { +//~^ ERROR function `other` has a type that is incompatible with the declaration + 3 +} + +fn main() { + bar(0); +} diff --git a/tests/ui/eii/wrong_ty.stderr b/tests/ui/eii/wrong_ty.stderr new file mode 100644 index 0000000000000..268440b2b7ea3 --- /dev/null +++ b/tests/ui/eii/wrong_ty.stderr @@ -0,0 +1,17 @@ +error[E0053]: function `other` has a type that is incompatible with the declaration + --> $DIR/wrong_ty.rs:18:1 + | +LL | fn other() -> u64 { + | ^^^^^^^^^^^^^^^^^ incorrect number of function parameters + | +note: type in declaration + --> $DIR/wrong_ty.rs:14:5 + | +LL | safe fn bar(x: u64) -> u64; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: expected signature `fn(u64) -> _` + found signature `fn() -> _` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0053`. From 1544eabdcd91e9d66c0a02fad0d0a3c3d60b5dd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 14 Mar 2025 14:47:16 +0100 Subject: [PATCH 12/41] remove namespace check in nameres --- .../rustc_attr_data_structures/src/lints.rs | 17 +++++++++++++ .../src/check/compare_eii.rs | 12 ++++----- compiler/rustc_resolve/src/ident.rs | 1 - .../auxiliary/cross_crate_eii_declaration.rs | 14 +++++++++++ tests/ui/eii/cross_crate.rs | 18 +++++++++++++ tests/ui/eii/subtype_1.rs | 1 - tests/ui/eii/subtype_3.rs | 25 +++++++++++++++++++ tests/ui/eii/subtype_4.rs | 25 +++++++++++++++++++ tests/ui/eii/wrong_ty.rs | 2 +- tests/ui/eii/wrong_ty.stderr | 17 ++++++++----- tests/ui/eii/wrong_ty_2.rs | 25 +++++++++++++++++++ tests/ui/eii/wrong_ty_2.stderr | 17 +++++++++++++ 12 files changed, 159 insertions(+), 15 deletions(-) create mode 100644 compiler/rustc_attr_data_structures/src/lints.rs create mode 100644 tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs create mode 100644 tests/ui/eii/cross_crate.rs create mode 100644 tests/ui/eii/subtype_3.rs create mode 100644 tests/ui/eii/subtype_4.rs create mode 100644 tests/ui/eii/wrong_ty_2.rs create mode 100644 tests/ui/eii/wrong_ty_2.stderr diff --git a/compiler/rustc_attr_data_structures/src/lints.rs b/compiler/rustc_attr_data_structures/src/lints.rs new file mode 100644 index 0000000000000..48b27e93d3cf0 --- /dev/null +++ b/compiler/rustc_attr_data_structures/src/lints.rs @@ -0,0 +1,17 @@ +// pub type HirDelayedLint = ( +// &'static Lint, +// HirId, +// Span, +// Box FnOnce(&'b mut Diag<'a, ()>) + 'static>, +// ); + +use rustc_span::Span; + +pub enum AttributeLintKind { + UnusedDuplicate { unused: Span, used: Span, warning: bool }, +} + +pub struct AttributeLint { + pub id: Id, + pub kind: AttributeLintKind, +} diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index d7db8f0398d39..19b015412a18b 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -2,16 +2,14 @@ use std::borrow::Cow; use std::iter; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{ - Applicability, Applicability, E0053, E0053, struct_span_code_err, struct_span_code_err, -}; +use rustc_errors::{Applicability, E0053, E0053, struct_span_code_err, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, self as hir, HirId, HirId, ItemKind, ItemKind}; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty; use rustc_middle::ty::TyCtxt; -use rustc_middle::ty::error::{ExpectedFound, ExpectedFound, TypeError, TypeError}; +use rustc_middle::ty::error::{ExpectedFound, TypeError, TypeError}; use rustc_span::{ErrorGuaranteed, Ident, Span}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::regions::InferCtxtRegionExt; @@ -54,11 +52,13 @@ pub(crate) fn compare_eii_function_types<'tcx>( // type. let wf_tys = FxIndexSet::default(); - let external_impl_sig = infcx.instantiate_binder_with_fresh_vars( external_impl_span, infer::HigherRankedType, - tcx.fn_sig(external_impl).instantiate_identity(), + tcx.fn_sig(external_impl).instantiate( + tcx, + infcx.fresh_args_for_item(external_impl_span, external_impl.to_def_id()), + ), ); let norm_cause = ObligationCause::misc(external_impl_span, external_impl); diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 180d6af219d11..26dc01dace5ad 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -294,7 +294,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ribs: &[Rib<'ra>], ignore_binding: Option>, ) -> Option> { - assert!(ns == TypeNS || ns == ValueNS); let orig_ident = ident; let (general_span, normalized_span) = if ident.name == kw::SelfUpper { // FIXME(jseyfried) improve `Self` hygiene diff --git a/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs b/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs new file mode 100644 index 0000000000000..01acf117d743f --- /dev/null +++ b/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs @@ -0,0 +1,14 @@ +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[core::eii_macro_for(bar)] +#[rustc_builtin_macro(eii_macro)] +pub macro foo() { + +} + +unsafe extern "Rust" { + pub safe fn bar(x: u64) -> u64; +} diff --git a/tests/ui/eii/cross_crate.rs b/tests/ui/eii/cross_crate.rs new file mode 100644 index 0000000000000..bd5c9d2ad0eac --- /dev/null +++ b/tests/ui/eii/cross_crate.rs @@ -0,0 +1,18 @@ +//@ compile-flags: --crate-type rlib +//@ check-pass +//@ aux-build: cross_crate_eii_declaration.rs +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +extern crate cross_crate_eii_declaration; + +#[unsafe(cross_crate_eii_declaration::foo)] +fn other(x: u64) -> u64 { + x +} + +fn main() { + cross_crate_eii_declaration::bar(0); +} diff --git a/tests/ui/eii/subtype_1.rs b/tests/ui/eii/subtype_1.rs index 5632dc99b4ed5..7ca7e0e6342cc 100644 --- a/tests/ui/eii/subtype_1.rs +++ b/tests/ui/eii/subtype_1.rs @@ -1,5 +1,4 @@ //@ compile-flags: --crate-type rlib -//@ check-pass #![feature(eii)] #![feature(decl_macro)] #![feature(rustc_attrs)] diff --git a/tests/ui/eii/subtype_3.rs b/tests/ui/eii/subtype_3.rs new file mode 100644 index 0000000000000..e746af84552f2 --- /dev/null +++ b/tests/ui/eii/subtype_3.rs @@ -0,0 +1,25 @@ +//@ compile-flags: --crate-type rlib +//@ check-pass +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[core::eii_macro_for(bar)] +#[rustc_builtin_macro(eii_macro)] +macro foo() { + +} + +unsafe extern "Rust" { + safe fn bar<'a>(x: &'a u64) -> &'a u64; +} + +#[foo] +fn other<'a>(x: &'a u64) -> &'static u64 { + &0 +} + +fn main() { + bar(&0); +} diff --git a/tests/ui/eii/subtype_4.rs b/tests/ui/eii/subtype_4.rs new file mode 100644 index 0000000000000..a3ba6829ba3b8 --- /dev/null +++ b/tests/ui/eii/subtype_4.rs @@ -0,0 +1,25 @@ +//@ compile-flags: --crate-type rlib +//@ check-pass +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[core::eii_macro_for(bar)] +#[rustc_builtin_macro(eii_macro)] +macro foo() { + +} + +unsafe extern "Rust" { + safe fn bar(x: u64) -> u64; +} + +#[foo] +fn other(x: u64) -> u64 { + x +} + +fn main() { + bar(0); +} diff --git a/tests/ui/eii/wrong_ty.rs b/tests/ui/eii/wrong_ty.rs index bcf2ac0f1135d..bc50f67bc10fa 100644 --- a/tests/ui/eii/wrong_ty.rs +++ b/tests/ui/eii/wrong_ty.rs @@ -15,7 +15,7 @@ unsafe extern "Rust" { } #[foo] -fn other() -> u64 { +fn other(x: usize) -> u64 { //~^ ERROR function `other` has a type that is incompatible with the declaration 3 } diff --git a/tests/ui/eii/wrong_ty.stderr b/tests/ui/eii/wrong_ty.stderr index 268440b2b7ea3..e64d4756d0cae 100644 --- a/tests/ui/eii/wrong_ty.stderr +++ b/tests/ui/eii/wrong_ty.stderr @@ -1,16 +1,21 @@ error[E0053]: function `other` has a type that is incompatible with the declaration - --> $DIR/wrong_ty.rs:18:1 + --> $DIR/wrong_ty.rs:18:13 | -LL | fn other() -> u64 { - | ^^^^^^^^^^^^^^^^^ incorrect number of function parameters +LL | fn other(x: usize) -> u64 { + | ^^^^^ expected `u64`, found `usize` | note: type in declaration - --> $DIR/wrong_ty.rs:14:5 + --> $DIR/wrong_ty.rs:14:20 | LL | safe fn bar(x: u64) -> u64; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^ = note: expected signature `fn(u64) -> _` - found signature `fn() -> _` + found signature `fn(usize) -> _` +help: change the parameter type to match the declaration + | +LL - fn other(x: usize) -> u64 { +LL + fn other(x: u64) -> u64 { + | error: aborting due to 1 previous error diff --git a/tests/ui/eii/wrong_ty_2.rs b/tests/ui/eii/wrong_ty_2.rs new file mode 100644 index 0000000000000..bcf2ac0f1135d --- /dev/null +++ b/tests/ui/eii/wrong_ty_2.rs @@ -0,0 +1,25 @@ +//@ compile-flags: --crate-type rlib +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[core::eii_macro_for(bar)] +#[rustc_builtin_macro(eii_macro)] +macro foo() { + +} + +unsafe extern "Rust" { + safe fn bar(x: u64) -> u64; +} + +#[foo] +fn other() -> u64 { +//~^ ERROR function `other` has a type that is incompatible with the declaration + 3 +} + +fn main() { + bar(0); +} diff --git a/tests/ui/eii/wrong_ty_2.stderr b/tests/ui/eii/wrong_ty_2.stderr new file mode 100644 index 0000000000000..907fe404d3757 --- /dev/null +++ b/tests/ui/eii/wrong_ty_2.stderr @@ -0,0 +1,17 @@ +error[E0053]: function `other` has a type that is incompatible with the declaration + --> $DIR/wrong_ty_2.rs:18:1 + | +LL | fn other() -> u64 { + | ^^^^^^^^^^^^^^^^^ incorrect number of function parameters + | +note: type in declaration + --> $DIR/wrong_ty_2.rs:14:5 + | +LL | safe fn bar(x: u64) -> u64; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: expected signature `fn(u64) -> _` + found signature `fn() -> _` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0053`. From 5be94ba24f6fb4e31219fc09928712a3d9263281 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 14 Mar 2025 16:04:51 +0100 Subject: [PATCH 13/41] type checking works (with some tests) for EII --- compiler/rustc_hir_analysis/messages.ftl | 7 + .../src/check/compare_eii.rs | 217 +++++++++++++++++- .../rustc_hir_analysis/src/check/wfcheck.rs | 10 +- compiler/rustc_hir_analysis/src/errors.rs | 15 ++ tests/ui/eii/cross_crate_wrong_ty.rs | 18 ++ tests/ui/eii/cross_crate_wrong_ty.stderr | 11 + tests/ui/eii/subtype_1.rs | 2 + tests/ui/eii/subtype_1.stderr | 13 ++ tests/ui/eii/subtype_2.rs | 2 +- tests/ui/eii/subtype_2.stderr | 13 ++ tests/ui/eii/wrong_ty_2.rs | 2 +- tests/ui/eii/wrong_ty_2.stderr | 19 +- 12 files changed, 302 insertions(+), 27 deletions(-) create mode 100644 tests/ui/eii/cross_crate_wrong_ty.rs create mode 100644 tests/ui/eii/cross_crate_wrong_ty.stderr create mode 100644 tests/ui/eii/subtype_1.stderr create mode 100644 tests/ui/eii/subtype_2.stderr diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 277bb7bd3e15c..0395f5ee2c2d6 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -294,6 +294,13 @@ hir_analysis_lifetime_not_captured = `impl Trait` captures lifetime parameter, b .label = lifetime captured due to being mentioned in the bounds of the `impl Trait` .param_label = this lifetime parameter is captured +hir_analysis_lifetimes_or_bounds_mismatch_on_eii = + lifetime parameters or bounds `{$ident}` do not match the declaration + .label = lifetimes do not match + .generics_label = lifetimes in impl do not match this signature + .where_label = this `where` clause might not match the one in the trait + .bounds_label = this bound might be missing in the implementation + hir_analysis_lifetimes_or_bounds_mismatch_on_trait = lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration .label = lifetimes do not match {$item_kind} in trait diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index 19b015412a18b..16ac4f361bdcf 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -2,14 +2,19 @@ use std::borrow::Cow; use std::iter; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{Applicability, E0053, E0053, struct_span_code_err, struct_span_code_err}; +use rustc_errors::{ + Applicability, Applicability, E0050, E0053, E0053, E0053, struct_span_code_err, + struct_span_code_err, struct_span_code_err, +}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{self as hir, self as hir, HirId, HirId, ItemKind, ItemKind}; +use rustc_hir::{ + self as hir, self as hir, self as hir, FnSig, HirId, HirId, HirId, ItemKind, ItemKind, ItemKind, +}; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty; use rustc_middle::ty::TyCtxt; -use rustc_middle::ty::error::{ExpectedFound, TypeError, TypeError}; +use rustc_middle::ty::error::{ExpectedFound, ExpectedFound, TypeError, TypeError, TypeError}; use rustc_span::{ErrorGuaranteed, Ident, Span}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::regions::InferCtxtRegionExt; @@ -17,6 +22,187 @@ use rustc_trait_selection::traits::ObligationCtxt; use rustc_type_ir::TypingMode; use tracing::{debug, instrument}; +use super::potentially_plural_count; +use crate::errors::LifetimesOrBoundsMismatchOnEII; + +/// Checks a bunch of different properties of the impl/trait methods for +/// compatibility, such as asyncness, number of argument, self receiver kind, +/// and number of early- and late-bound generics. +fn check_is_structurally_compatible<'tcx>( + tcx: TyCtxt<'tcx>, + external_impl: LocalDefId, + declaration: DefId, + eii_name: Symbol, + eii_attr_span: Span, +) -> Result<(), ErrorGuaranteed> { + // FIXME(jdonszelmann): check no generics + compare_number_of_method_arguments(tcx, external_impl, declaration, eii_name, eii_attr_span)?; + check_region_bounds_on_impl_item(tcx, external_impl, declaration, eii_attr_span)?; + Ok(()) +} + +fn check_region_bounds_on_impl_item<'tcx>( + tcx: TyCtxt<'tcx>, + external_impl: LocalDefId, + declaration: DefId, + eii_attr_span: Span, +) -> Result<(), ErrorGuaranteed> { + let external_impl_generics = tcx.generics_of(external_impl.to_def_id()); + let external_impl_params = external_impl_generics.own_counts().lifetimes; + + let declaration_generics = tcx.generics_of(declaration); + let declaration_params = declaration_generics.own_counts().lifetimes; + + debug!(?declaration_generics, ?external_impl_generics); + + // Must have same number of early-bound lifetime parameters. + // Unfortunately, if the user screws up the bounds, then this + // will change classification between early and late. E.g., + // if in trait we have `<'a,'b:'a>`, and in impl we just have + // `<'a,'b>`, then we have 2 early-bound lifetime parameters + // in trait but 0 in the impl. But if we report "expected 2 + // but found 0" it's confusing, because it looks like there + // are zero. Since I don't quite know how to phrase things at + // the moment, give a kind of vague error message. + if declaration_params != external_impl_params { + let span = tcx + .hir_get_generics(external_impl) + .expect("expected impl item to have generics or else we can't compare them") + .span; + + let mut generics_span = None; + let mut bounds_span = vec![]; + let mut where_span = None; + if let Some(declaration_node) = tcx.hir_get_if_local(declaration) + && let Some(declaration_generics) = declaration_node.generics() + { + generics_span = Some(declaration_generics.span); + // FIXME: we could potentially look at the impl's bounds to not point at bounds that + // *are* present in the impl. + for p in declaration_generics.predicates { + if let hir::WherePredicateKind::BoundPredicate(pred) = p.kind { + for b in pred.bounds { + if let hir::GenericBound::Outlives(lt) = b { + bounds_span.push(lt.ident.span); + } + } + } + } + if let Some(declaration_node) = tcx.hir_get_if_local(declaration) + && let Some(declaration_generics) = declaration_node.generics() + { + let mut impl_bounds = 0; + for p in declaration_generics.predicates { + if let hir::WherePredicateKind::BoundPredicate(pred) = p.kind { + for b in pred.bounds { + if let hir::GenericBound::Outlives(_) = b { + impl_bounds += 1; + } + } + } + } + if impl_bounds == bounds_span.len() { + bounds_span = vec![]; + } else if declaration_generics.has_where_clause_predicates { + where_span = Some(declaration_generics.where_clause_span); + } + } + } + let mut diag = tcx.dcx().create_err(LifetimesOrBoundsMismatchOnEII { + span, + ident: tcx.item_name(external_impl.to_def_id()), + generics_span, + bounds_span, + where_span, + }); + + diag.span_label(eii_attr_span, format!("required because of this attribute")); + return Err(diag.emit()); + } + + Ok(()) +} + +fn compare_number_of_method_arguments<'tcx>( + tcx: TyCtxt<'tcx>, + external_impl: LocalDefId, + declaration: DefId, + eii_name: Symbol, + eii_attr_span: Span, +) -> Result<(), ErrorGuaranteed> { + let external_impl_fty = tcx.fn_sig(external_impl); + let declaration_fty = tcx.fn_sig(declaration); + let declaration_number_args = declaration_fty.skip_binder().inputs().skip_binder().len(); + let external_impl_number_args = external_impl_fty.skip_binder().inputs().skip_binder().len(); + let external_impl_name = tcx.item_name(external_impl.to_def_id()); + + if declaration_number_args != external_impl_number_args { + let declaration_span = declaration + .as_local() + .and_then(|def_id| { + let declaration_sig = get_declaration_sig(tcx, def_id).expect("foreign item sig"); + let pos = declaration_number_args.saturating_sub(1); + declaration_sig.decl.inputs.get(pos).map(|arg| { + if pos == 0 { + arg.span + } else { + arg.span.with_lo(declaration_sig.decl.inputs[0].span.lo()) + } + }) + }) + .or_else(|| tcx.hir().span_if_local(declaration)); + + let (external_impl_sig, _, _) = &tcx.hir().expect_item(external_impl).expect_fn(); + let pos = external_impl_number_args.saturating_sub(1); + let impl_span = external_impl_sig + .decl + .inputs + .get(pos) + .map(|arg| { + if pos == 0 { + arg.span + } else { + arg.span.with_lo(external_impl_sig.decl.inputs[0].span.lo()) + } + }) + .unwrap_or_else(|| tcx.def_span(external_impl)); + + let mut err = struct_span_code_err!( + tcx.dcx(), + impl_span, + E0050, // FIXME(jdonszelmann): new error code + "`{external_impl_name}` has {} but #[{eii_name}] requires it to have {}", + potentially_plural_count(external_impl_number_args, "parameter"), + declaration_number_args + ); + + if let Some(declaration_span) = declaration_span { + err.span_label( + declaration_span, + format!( + "requires {}", + potentially_plural_count(declaration_number_args, "parameter") + ), + ); + } + + err.span_label( + impl_span, + format!( + "expected {}, found {}", + potentially_plural_count(declaration_number_args, "parameter"), + external_impl_number_args + ), + ); + + err.span_label(eii_attr_span, format!("required because of this attribute")); + + return Err(err.emit()); + } + + Ok(()) +} + // checks whether the signature of some `external_impl`, matches // the signature of `declaration`, which it is supposed to be compatible // with in order to implement the item. @@ -24,7 +210,11 @@ pub(crate) fn compare_eii_function_types<'tcx>( tcx: TyCtxt<'tcx>, external_impl: LocalDefId, declaration: DefId, + eii_name: Symbol, + eii_attr_span: Span, ) -> Result<(), ErrorGuaranteed> { + check_is_structurally_compatible(tcx, external_impl, declaration, eii_name, eii_attr_span)?; + let external_impl_span = tcx.def_span(external_impl); let cause = ObligationCause::new( external_impl_span, @@ -52,6 +242,12 @@ pub(crate) fn compare_eii_function_types<'tcx>( // type. let wf_tys = FxIndexSet::default(); + let norm_cause = ObligationCause::misc(external_impl_span, external_impl); + + let declaration_sig = tcx.fn_sig(declaration).instantiate_identity(); + let declaration_sig = infcx.enter_forall_and_leak_universe(declaration_sig); + let declaration_sig = ocx.normalize(&norm_cause, param_env, declaration_sig); + let external_impl_sig = infcx.instantiate_binder_with_fresh_vars( external_impl_span, infer::HigherRankedType, @@ -60,16 +256,9 @@ pub(crate) fn compare_eii_function_types<'tcx>( infcx.fresh_args_for_item(external_impl_span, external_impl.to_def_id()), ), ); - - let norm_cause = ObligationCause::misc(external_impl_span, external_impl); let external_impl_sig = ocx.normalize(&norm_cause, param_env, external_impl_sig); debug!(?external_impl_sig); - let declaration_sig = tcx.fn_sig(declaration).instantiate_identity(); - let declaration_sig = - tcx.liberate_late_bound_regions(external_impl.to_def_id(), declaration_sig); - let declaration_sig = ocx.normalize(&norm_cause, param_env, declaration_sig); - // FIXME: We'd want to keep more accurate spans than "the method signature" when // processing the comparison between the trait and impl fn, but we sadly lose them // and point at the whole signature when a trait bound or specific input or output @@ -201,8 +390,7 @@ fn extract_spans_for_error_reporting<'tcx>( }; let declaration_args = declaration.as_local().map(|def_id| { - let hir_id: HirId = tcx.local_def_id_to_hir_id(def_id); - if let Some(sig) = tcx.hir_fn_sig_by_hir_id(hir_id) { + if let Some(sig) = get_declaration_sig(tcx, def_id) { sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) } else { panic!("expected {def_id:?} to be a foreign function"); @@ -218,3 +406,8 @@ fn extract_spans_for_error_reporting<'tcx>( _ => (cause.span, tcx.hir().span_if_local(declaration), external_impl_name), } } + +fn get_declaration_sig<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Option<&'tcx FnSig<'tcx>> { + let hir_id: HirId = tcx.local_def_id_to_hir_id(def_id); + tcx.hir_fn_sig_by_hir_id(hir_id) +} diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 6feb08a6749ef..f9ecadbcf6d41 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1324,7 +1324,7 @@ fn check_item_fn( enter_wf_checking_ctxt(tcx, span, def_id, |wfcx| { // 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 { eii_macro, .. } in + for EIIImpl { eii_macro, span, .. } in find_attr!(tcx.get_all_attrs(def_id), AttributeKind::EiiImpl(impls) => impls) .into_iter() .flatten() @@ -1333,7 +1333,13 @@ fn check_item_fn( // signature that we'd like to compare the function we're currently checking with if let Some(eii_extern_item) = find_attr!(tcx.get_all_attrs(*eii_macro), AttributeKind::EiiMacroFor {eii_extern_item, ..} => *eii_extern_item) { - let _ = compare_eii_function_types(tcx, def_id, eii_extern_item); + let _ = compare_eii_function_types( + tcx, + def_id, + eii_extern_item, + tcx.item_name(*eii_macro), + *span, + ); } else { panic!( "EII impl macro {eii_macro:?} did not have an eii macro for attribute pointing to a function" diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 2b1661aaac8f0..57e0df61cb074 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -207,6 +207,21 @@ pub(crate) struct LifetimesOrBoundsMismatchOnTrait { pub ident: Ident, } +#[derive(Diagnostic)] +#[diag(hir_analysis_lifetimes_or_bounds_mismatch_on_eii)] +pub(crate) struct LifetimesOrBoundsMismatchOnEII { + #[primary_span] + #[label] + pub span: Span, + #[label(hir_analysis_generics_label)] + pub generics_span: Option, + #[label(hir_analysis_where_label)] + pub where_span: Option, + #[label(hir_analysis_bounds_label)] + pub bounds_span: Vec, + pub ident: Symbol, +} + #[derive(Diagnostic)] #[diag(hir_analysis_drop_impl_on_wrong_item, code = E0120)] pub(crate) struct DropImplOnWrongItem { diff --git a/tests/ui/eii/cross_crate_wrong_ty.rs b/tests/ui/eii/cross_crate_wrong_ty.rs new file mode 100644 index 0000000000000..a73f347b359fe --- /dev/null +++ b/tests/ui/eii/cross_crate_wrong_ty.rs @@ -0,0 +1,18 @@ +//@ compile-flags: --crate-type rlib +//@ aux-build: cross_crate_eii_declaration.rs +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +extern crate cross_crate_eii_declaration; + +#[unsafe(cross_crate_eii_declaration::foo)] +fn other() -> u64 { +//~^ ERROR `other` has 0 parameters but #[foo] requires it to have 1 + 0 +} + +fn main() { + cross_crate_eii_declaration::bar(0); +} diff --git a/tests/ui/eii/cross_crate_wrong_ty.stderr b/tests/ui/eii/cross_crate_wrong_ty.stderr new file mode 100644 index 0000000000000..25dc6dbc5cb4f --- /dev/null +++ b/tests/ui/eii/cross_crate_wrong_ty.stderr @@ -0,0 +1,11 @@ +error[E0050]: `other` has 0 parameters but #[foo] requires it to have 1 + --> $DIR/cross_crate_wrong_ty.rs:11:1 + | +LL | #[unsafe(cross_crate_eii_declaration::foo)] + | ------------------------------------------- required because of this attribute +LL | fn other() -> u64 { + | ^^^^^^^^^^^^^^^^^ expected 1 parameter, found 0 + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0050`. diff --git a/tests/ui/eii/subtype_1.rs b/tests/ui/eii/subtype_1.rs index 7ca7e0e6342cc..e20a9b6806dad 100644 --- a/tests/ui/eii/subtype_1.rs +++ b/tests/ui/eii/subtype_1.rs @@ -1,4 +1,5 @@ //@ compile-flags: --crate-type rlib +//FIXME: known ICE #![feature(eii)] #![feature(decl_macro)] #![feature(rustc_attrs)] @@ -16,6 +17,7 @@ unsafe extern "Rust" { #[foo] fn other<'a, 'b>(x: &'b u64) -> &'b u64 { +//~^ ERROR lifetime parameters or bounds `other` do not match the declaration &0 } diff --git a/tests/ui/eii/subtype_1.stderr b/tests/ui/eii/subtype_1.stderr new file mode 100644 index 0000000000000..cf20150b74f7b --- /dev/null +++ b/tests/ui/eii/subtype_1.stderr @@ -0,0 +1,13 @@ +error: lifetime parameters or bounds `other` do not match the declaration + --> $DIR/subtype_1.rs:19:9 + | +LL | safe fn bar<'a, 'b>(x: &'b u64) -> &'a u64; + | -------- lifetimes in impl do not match this signature +... +LL | #[foo] + | ------ required because of this attribute +LL | fn other<'a, 'b>(x: &'b u64) -> &'b u64 { + | ^^^^^^^^ lifetimes do not match + +error: aborting due to 1 previous error + diff --git a/tests/ui/eii/subtype_2.rs b/tests/ui/eii/subtype_2.rs index 9d8164cef2cd0..985eaa9237ec0 100644 --- a/tests/ui/eii/subtype_2.rs +++ b/tests/ui/eii/subtype_2.rs @@ -1,5 +1,4 @@ //@ compile-flags: --crate-type rlib -//@ check-pass #![feature(eii)] #![feature(decl_macro)] #![feature(rustc_attrs)] @@ -17,6 +16,7 @@ unsafe extern "Rust" { #[foo] fn other<'a>(x: &'a u64) -> &'static u64 { +//~^ ERROR lifetime parameters or bounds `other` do not match the declaration &0 } diff --git a/tests/ui/eii/subtype_2.stderr b/tests/ui/eii/subtype_2.stderr new file mode 100644 index 0000000000000..f10d786776ad9 --- /dev/null +++ b/tests/ui/eii/subtype_2.stderr @@ -0,0 +1,13 @@ +error: lifetime parameters or bounds `other` do not match the declaration + --> $DIR/subtype_2.rs:18:9 + | +LL | safe fn bar<'a>(x: &'static u64) -> &'a u64; + | ---- lifetimes in impl do not match this signature +... +LL | #[foo] + | ------ required because of this attribute +LL | fn other<'a>(x: &'a u64) -> &'static u64 { + | ^^^^ lifetimes do not match + +error: aborting due to 1 previous error + diff --git a/tests/ui/eii/wrong_ty_2.rs b/tests/ui/eii/wrong_ty_2.rs index bcf2ac0f1135d..c4f3006efad9c 100644 --- a/tests/ui/eii/wrong_ty_2.rs +++ b/tests/ui/eii/wrong_ty_2.rs @@ -16,7 +16,7 @@ unsafe extern "Rust" { #[foo] fn other() -> u64 { -//~^ ERROR function `other` has a type that is incompatible with the declaration +//~^ ERROR `other` has 0 parameters but #[foo] requires it to have 3 } diff --git a/tests/ui/eii/wrong_ty_2.stderr b/tests/ui/eii/wrong_ty_2.stderr index 907fe404d3757..2ed00f9e55ee0 100644 --- a/tests/ui/eii/wrong_ty_2.stderr +++ b/tests/ui/eii/wrong_ty_2.stderr @@ -1,17 +1,14 @@ -error[E0053]: function `other` has a type that is incompatible with the declaration +error[E0050]: `other` has 0 parameters but #[foo] requires it to have 1 --> $DIR/wrong_ty_2.rs:18:1 | -LL | fn other() -> u64 { - | ^^^^^^^^^^^^^^^^^ incorrect number of function parameters - | -note: type in declaration - --> $DIR/wrong_ty_2.rs:14:5 - | LL | safe fn bar(x: u64) -> u64; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected signature `fn(u64) -> _` - found signature `fn() -> _` + | --- requires 1 parameter +... +LL | #[foo] + | ------ required because of this attribute +LL | fn other() -> u64 { + | ^^^^^^^^^^^^^^^^^ expected 1 parameter, found 0 error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0053`. +For more information about this error, try `rustc --explain E0050`. From 7ee830f4bf94055002de46dda837000d1631ef71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 14 Mar 2025 17:26:04 +0100 Subject: [PATCH 14/41] test attr misuse --- compiler/rustc_builtin_macros/messages.ftl | 7 ++ compiler/rustc_builtin_macros/src/eii.rs | 61 ++++++++++-- compiler/rustc_builtin_macros/src/errors.rs | 38 +++++++ .../src/check/compare_eii.rs | 6 +- tests/ui/eii/errors.rs | 44 +++++++++ tests/ui/eii/errors.stderr | 98 +++++++++++++++++++ 6 files changed, 242 insertions(+), 12 deletions(-) create mode 100644 tests/ui/eii/errors.rs create mode 100644 tests/ui/eii/errors.stderr diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 73be954cefd76..852360ea8df58 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -150,6 +150,13 @@ builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept a builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values .suggestion = remove the value +builtin_macros_eii_macro_expected_function = `#[{$name}]` is only valid on functions +builtin_macros_eii_macro_for_expected_list = `#[eii_macro_for(...)]` expects a list of one or two elements +builtin_macros_eii_macro_for_expected_macro = `#[eii_macro_for(...)]` is only valid on macros +builtin_macros_eii_macro_for_expected_max_one_argument = `#[{$name}]` expected no arguments or a single argument: `#[{$name}(default)]` +builtin_macros_eii_macro_for_expected_unsafe = expected this argument to be "unsafe". + .note = the second argument is optional + builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time .cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead .custom = use `std::env::var({$var_expr})` to read the variable at run time diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index 8e60563fc4eb3..71335ff368337 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -1,28 +1,50 @@ use rustc_ast::{DUMMY_NODE_ID, EIIImpl, EiiMacroFor, ItemKind, ast}; +use rustc_ast_pretty::pprust::path_to_string; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::{Span, kw}; +use crate::errors::{ + EIIMacroExpectedFunction, EIIMacroExpectedMaxOneArgument, EIIMacroForExpectedList, + EIIMacroForExpectedMacro, EIIMacroForExpectedUnsafe, +}; + pub(crate) fn eii_macro_for( ecx: &mut ExtCtxt<'_>, - _span: Span, + span: Span, meta_item: &ast::MetaItem, mut item: Annotatable, ) -> Vec { - let Annotatable::Item(i) = &mut item else { panic!("expected item") }; - let ItemKind::MacroDef(_, d) = &mut i.kind else { panic!("expected macro def") }; + let Annotatable::Item(i) = &mut item else { + ecx.dcx().emit_err(EIIMacroForExpectedMacro { span }); + return vec![item]; + }; + let ItemKind::MacroDef(_, d) = &mut i.kind else { + ecx.dcx().emit_err(EIIMacroForExpectedMacro { span }); + return vec![item]; + }; + + let Some(list) = meta_item.meta_item_list() else { + ecx.dcx().emit_err(EIIMacroForExpectedList { span: meta_item.span }); + return vec![item]; + }; - let Some(list) = meta_item.meta_item_list() else { panic!("expected list") }; + if list.len() > 2 { + ecx.dcx().emit_err(EIIMacroForExpectedList { span: meta_item.span }); + return vec![item]; + } let Some(extern_item_path) = list.get(0).and_then(|i| i.meta_item()).map(|i| i.path.clone()) else { - panic!("expected a path to an `extern` item"); + ecx.dcx().emit_err(EIIMacroForExpectedList { span: meta_item.span }); + return vec![item]; }; let impl_unsafe = if let Some(i) = list.get(1) { if i.lit().and_then(|i| i.kind.str()).is_some_and(|i| i == kw::Unsafe) { true } else { - panic!("expected the string `\"unsafe\"` here or no other arguments"); + ecx.dcx().emit_err(EIIMacroForExpectedUnsafe { span: i.span() }); + return vec![item]; } } else { false @@ -40,11 +62,32 @@ pub(crate) fn eii_macro( meta_item: &ast::MetaItem, mut item: Annotatable, ) -> Vec { - let Annotatable::Item(i) = &mut item else { panic!("expected item") }; + let Annotatable::Item(i) = &mut item else { + ecx.dcx() + .emit_err(EIIMacroExpectedFunction { span, name: path_to_string(&meta_item.path) }); + return vec![item]; + }; - let ItemKind::Fn(f) = &mut i.kind else { panic!("expected function") }; + let ItemKind::Fn(f) = &mut i.kind else { + ecx.dcx() + .emit_err(EIIMacroExpectedFunction { span, name: path_to_string(&meta_item.path) }); + return vec![item]; + }; - assert!(meta_item.is_word()); + let is_default = if meta_item.is_word() { + false + } else if let Some([first]) = meta_item.meta_item_list() + && let Some(m) = first.meta_item() + && m.path.segments.len() == 1 + { + m.path.segments[0].ident.name == kw::Default + } else { + ecx.dcx().emit_err(EIIMacroExpectedMaxOneArgument { + span: meta_item.span, + name: path_to_string(&meta_item.path), + }); + return vec![item]; + }; f.eii_impl.push(EIIImpl { node_id: DUMMY_NODE_ID, diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index d14ad8f40144c..68c3a55a3521f 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1027,3 +1027,41 @@ pub(crate) struct NonGenericPointee { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(builtin_macros_eii_macro_for_expected_macro)] +pub(crate) struct EIIMacroForExpectedMacro { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_eii_macro_for_expected_list)] +pub(crate) struct EIIMacroForExpectedList { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_eii_macro_for_expected_unsafe)] +pub(crate) struct EIIMacroForExpectedUnsafe { + #[primary_span] + #[note] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_eii_macro_expected_function)] +pub(crate) struct EIIMacroExpectedFunction { + #[primary_span] + pub span: Span, + pub name: String, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_eii_macro_for_expected_max_one_argument)] +pub(crate) struct EIIMacroExpectedMaxOneArgument { + #[primary_span] + pub span: Span, + pub name: String, +} diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index 16ac4f361bdcf..248193b2f1ac7 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -3,8 +3,8 @@ use std::iter; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{ - Applicability, Applicability, E0050, E0053, E0053, E0053, struct_span_code_err, - struct_span_code_err, struct_span_code_err, + Applicability, E0050, E0053, E0053, E0053, struct_span_code_err, struct_span_code_err, + struct_span_code_err, }; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{ @@ -14,7 +14,7 @@ use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty; use rustc_middle::ty::TyCtxt; -use rustc_middle::ty::error::{ExpectedFound, ExpectedFound, TypeError, TypeError, TypeError}; +use rustc_middle::ty::error::{ExpectedFound, TypeError, TypeError, TypeError}; use rustc_span::{ErrorGuaranteed, Ident, Span}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::regions::InferCtxtRegionExt; diff --git a/tests/ui/eii/errors.rs b/tests/ui/eii/errors.rs new file mode 100644 index 0000000000000..cea9d3bb53f53 --- /dev/null +++ b/tests/ui/eii/errors.rs @@ -0,0 +1,44 @@ +//@ compile-flags: --crate-type rlib +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[core::eii_macro_for(bar)] //~ ERROR `#[eii_macro_for(...)]` is only valid on macros +fn hello() { + #[core::eii_macro_for(bar)] //~ ERROR `#[eii_macro_for(...)]` is only valid on macros + let x = 3 + 3; +} + +#[core::eii_macro_for] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements +#[core::eii_macro_for()] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements +#[core::eii_macro_for(bar, hello)] //~ ERROR expected this argument to be "unsafe" +#[core::eii_macro_for(bar, "unsafe", hello)] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements +#[core::eii_macro_for(bar, hello, "unsafe")] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements +#[core::eii_macro_for = "unsafe"] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements +#[core::eii_macro_for(bar)] +#[rustc_builtin_macro(eii_macro)] +macro foo() {} + +unsafe extern "Rust" { + safe fn bar(x: u64) -> u64; +} + +#[foo] //~ ERROR `#[foo]` is only valid on functions +static X: u64 = 4; +#[foo] //~ ERROR `#[foo]` is only valid on functions +const Y: u64 = 4; +#[foo] //~ ERROR `#[foo]` is only valid on functions +macro bar() {} + +#[foo()] +//~^ ERROR `#[foo]` expected no arguments or a single argument: `#[foo(default)]` +#[foo(default, bar)] +//~^ ERROR `#[foo]` expected no arguments or a single argument: `#[foo(default)]` +#[foo("default")] +//~^ ERROR `#[foo]` expected no arguments or a single argument: `#[foo(default)]` +#[foo = "default"] +//~^ ERROR `#[foo]` expected no arguments or a single argument: `#[foo(default)]` +fn other(x: u64) -> u64 { + x +} diff --git a/tests/ui/eii/errors.stderr b/tests/ui/eii/errors.stderr new file mode 100644 index 0000000000000..535ba6277c6bb --- /dev/null +++ b/tests/ui/eii/errors.stderr @@ -0,0 +1,98 @@ +error: `#[eii_macro_for(...)]` is only valid on macros + --> $DIR/errors.rs:7:1 + | +LL | #[core::eii_macro_for(bar)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[eii_macro_for(...)]` is only valid on macros + --> $DIR/errors.rs:9:5 + | +LL | #[core::eii_macro_for(bar)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[eii_macro_for(...)]` expects a list of one or two elements + --> $DIR/errors.rs:13:1 + | +LL | #[core::eii_macro_for] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[eii_macro_for(...)]` expects a list of one or two elements + --> $DIR/errors.rs:14:1 + | +LL | #[core::eii_macro_for()] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected this argument to be "unsafe". + --> $DIR/errors.rs:15:28 + | +LL | #[core::eii_macro_for(bar, hello)] + | ^^^^^ + | +note: the second argument is optional + --> $DIR/errors.rs:15:28 + | +LL | #[core::eii_macro_for(bar, hello)] + | ^^^^^ + +error: `#[eii_macro_for(...)]` expects a list of one or two elements + --> $DIR/errors.rs:16:1 + | +LL | #[core::eii_macro_for(bar, "unsafe", hello)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[eii_macro_for(...)]` expects a list of one or two elements + --> $DIR/errors.rs:17:1 + | +LL | #[core::eii_macro_for(bar, hello, "unsafe")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[eii_macro_for(...)]` expects a list of one or two elements + --> $DIR/errors.rs:18:1 + | +LL | #[core::eii_macro_for = "unsafe"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[foo]` is only valid on functions + --> $DIR/errors.rs:27:1 + | +LL | #[foo] + | ^^^^^^ + +error: `#[foo]` is only valid on functions + --> $DIR/errors.rs:29:1 + | +LL | #[foo] + | ^^^^^^ + +error: `#[foo]` is only valid on functions + --> $DIR/errors.rs:31:1 + | +LL | #[foo] + | ^^^^^^ + +error: `#[foo]` expected no arguments or a single argument: `#[foo(default)]` + --> $DIR/errors.rs:34:1 + | +LL | #[foo()] + | ^^^^^^^^ + +error: `#[foo]` expected no arguments or a single argument: `#[foo(default)]` + --> $DIR/errors.rs:36:1 + | +LL | #[foo(default, bar)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: `#[foo]` expected no arguments or a single argument: `#[foo(default)]` + --> $DIR/errors.rs:38:1 + | +LL | #[foo("default")] + | ^^^^^^^^^^^^^^^^^ + +error: `#[foo]` expected no arguments or a single argument: `#[foo(default)]` + --> $DIR/errors.rs:40:1 + | +LL | #[foo = "default"] + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 15 previous errors + From 14fb00b7380bc29e6076e2ebb841fec01ad6c895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 14 Mar 2025 17:31:12 +0100 Subject: [PATCH 15/41] propagate default --- compiler/rustc_ast/src/ast.rs | 5 +-- compiler/rustc_ast/src/mut_visit.rs | 2 +- compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_lowering/src/item.rs | 20 +++++++++--- .../rustc_ast_pretty/src/pprust/state/item.rs | 3 +- .../src/attributes.rs | 1 + compiler/rustc_builtin_macros/src/eii.rs | 8 ++--- .../src/check/compare_eii.rs | 32 +++++++------------ .../rustc_hir_analysis/src/check/wfcheck.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 4 ++- compiler/rustc_parse/src/parser/item.rs | 14 ++++---- compiler/rustc_passes/src/check_attr.rs | 2 +- compiler/rustc_resolve/src/late.rs | 3 +- 13 files changed, 54 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index afa1a65ad4b2d..f5375f7a34957 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1952,11 +1952,11 @@ pub struct MacroDef { /// `true` if macro was defined with `macro_rules`. pub macro_rules: bool, - pub eii_macro_for: Option, + pub eii_macro_for: Option, } #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] -pub struct EiiMacroFor { +pub struct EIIMacroFor { pub extern_item_path: Path, pub impl_unsafe: bool, } @@ -3598,6 +3598,7 @@ pub struct EIIImpl { pub impl_safety: Safety, pub span: Span, pub inner_span: Span, + pub is_default: bool, } #[derive(Clone, Encodable, Decodable, Debug)] diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 296ef04c5659e..3d31e469bc51e 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -735,7 +735,7 @@ fn walk_mac(vis: &mut T, mac: &mut MacCall) { fn walk_macro_def(vis: &mut T, macro_def: &mut MacroDef) { let MacroDef { body, macro_rules: _, eii_macro_for } = macro_def; - if let Some(EiiMacroFor { extern_item_path, impl_unsafe: _ }) = eii_macro_for { + if let Some(EIIMacroFor { extern_item_path, impl_unsafe: _ }) = eii_macro_for { vis.visit_path(extern_item_path); } visit_delim_args(vis, body); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 01bf121da30e6..a399a5451fc64 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -479,7 +479,7 @@ impl WalkItemKind for ItemKind { ItemKind::MacroDef(ident, ts) => { try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_mac_def(ts, id)); - if let Some(EiiMacroFor { extern_item_path, impl_unsafe: _ }) = &ts.eii_macro_for { + if let Some(EIIMacroFor { extern_item_path, impl_unsafe: _ }) = &ts.eii_macro_for { try_visit!(visitor.visit_path(extern_item_path, id)); } } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 857922d094b01..26437ca9e39a2 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -23,7 +23,6 @@ use super::{ AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode, ResolverAstLoweringExt, }; -use crate::GenericArgsMode; pub(super) struct ItemLowerer<'a, 'hir> { pub(super) tcx: TyCtxt<'hir>, @@ -156,7 +155,15 @@ impl<'hir> LoweringContext<'_, 'hir> { match i { ItemKind::Fn(box Fn { eii_impl, .. }) => { let mut eii_impls = ThinVec::new(); - for EIIImpl { node_id, eii_macro_path, impl_safety, span, inner_span } in eii_impl { + for EIIImpl { + node_id, + eii_macro_path, + impl_safety, + span, + inner_span, + is_default, + } in eii_impl + { let did = self.lower_path_simple_eii(*node_id, eii_macro_path); eii_impls.push(rustc_attr_parsing::EIIImpl { eii_macro: did, @@ -165,12 +172,18 @@ impl<'hir> LoweringContext<'_, 'hir> { impl_marked_unsafe: self .lower_safety(*impl_safety, hir::Safety::Safe) .is_unsafe(), + is_default: *is_default, }) } vec![hir::Attribute::Parsed(AttributeKind::EiiImpl(eii_impls))] } - ItemKind::MacroDef(_, MacroDef { eii_macro_for: Some(EiiMacroFor { extern_item_path, impl_unsafe }), .. }) => { + ItemKind::MacroDef( + _, + MacroDef { + eii_macro_for: Some(EIIMacroFor { extern_item_path, impl_unsafe }), .. + }, + ) => { vec![hir::Attribute::Parsed(AttributeKind::EiiMacroFor { eii_extern_item: self.lower_path_simple_eii(id, extern_item_path), impl_unsafe: *impl_unsafe, @@ -720,7 +733,6 @@ impl<'hir> LoweringContext<'_, 'hir> { ) }); - // Unmarked safety in unsafe block defaults to unsafe. let header = self.lower_fn_header(sig.header, hir::Safety::Unsafe, attrs); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 997e94674c9cb..e2e3135a41f26 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -671,7 +671,8 @@ 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_impl } = func; + let ast::Fn { defaultness, ident, generics, sig, contract, body, define_opaque, eii_impl } = + func; self.print_define_opaques(define_opaque.as_deref()); let body_cb_ib = body.as_ref().map(|body| (body, self.head(""))); diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index e06f46497849c..aaaa16140f8cd 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -145,6 +145,7 @@ pub struct EIIImpl { pub impl_marked_unsafe: bool, pub span: Span, pub inner_span: Span, + pub is_default: bool, } /// Represent parsed, *built in*, inert attributes. diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index 71335ff368337..809408d1abd16 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -1,4 +1,4 @@ -use rustc_ast::{DUMMY_NODE_ID, EIIImpl, EiiMacroFor, ItemKind, ast}; +use rustc_ast::{DUMMY_NODE_ID, EIIImpl, EIIMacroFor, ItemKind, ast}; use rustc_ast_pretty::pprust::path_to_string; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::{Span, kw}; @@ -50,7 +50,7 @@ pub(crate) fn eii_macro_for( false }; - d.eii_macro_for = Some(EiiMacroFor { extern_item_path, impl_unsafe }); + d.eii_macro_for = Some(EIIMacroFor { extern_item_path, impl_unsafe }); // Return the original item and the new methods. vec![item] @@ -94,8 +94,8 @@ pub(crate) fn eii_macro( eii_macro_path: meta_item.path.clone(), impl_safety: meta_item.unsafety, span, - inner_span: meta_item.span, - is_default: false, + inner_span: meta_item.path.span, + is_default, }); vec![item] diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index 248193b2f1ac7..42a3886065aca 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -2,24 +2,19 @@ use std::borrow::Cow; use std::iter; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{ - Applicability, E0050, E0053, E0053, E0053, struct_span_code_err, struct_span_code_err, - struct_span_code_err, -}; +use rustc_errors::{Applicability, E0050, E0053, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{ - self as hir, self as hir, self as hir, FnSig, HirId, HirId, HirId, ItemKind, ItemKind, ItemKind, -}; +use rustc_hir::{self as hir, FnSig, HirId, ItemKind}; +use rustc_infer::infer::canonical::ir::TypingMode; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty; use rustc_middle::ty::TyCtxt; -use rustc_middle::ty::error::{ExpectedFound, TypeError, TypeError, TypeError}; -use rustc_span::{ErrorGuaranteed, Ident, Span}; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; +use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::ObligationCtxt; -use rustc_type_ir::TypingMode; use tracing::{debug, instrument}; use super::potentially_plural_count; @@ -150,9 +145,9 @@ fn compare_number_of_method_arguments<'tcx>( } }) }) - .or_else(|| tcx.hir().span_if_local(declaration)); + .or_else(|| tcx.hir_span_if_local(declaration)); - let (external_impl_sig, _, _) = &tcx.hir().expect_item(external_impl).expect_fn(); + let (_, external_impl_sig, _, _) = &tcx.hir_expect_item(external_impl).expect_fn(); let pos = external_impl_number_args.saturating_sub(1); let impl_span = external_impl_sig .decl @@ -326,7 +321,7 @@ fn report_eii_mismatch<'tcx>( if declaration_sig.inputs().len() == *i { // Suggestion to change output type. We do not suggest in `async` functions // to avoid complex logic or incorrect output. - if let ItemKind::Fn { sig, .. } = &tcx.hir().expect_item(external_impl_did).kind + if let ItemKind::Fn { sig, .. } = &tcx.hir_expect_item(external_impl_did).kind && !sig.header.asyncness.is_async() { let msg = "change the output type to match the declaration"; @@ -381,12 +376,9 @@ fn extract_spans_for_error_reporting<'tcx>( ) -> (Span, Option, Ident) { let tcx = infcx.tcx; let (mut external_impl_args, external_impl_name) = { - let item = tcx.hir().expect_item(external_impl); - let (sig, _, _) = item.expect_fn(); - ( - sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())), - item.ident, - ) + let item = tcx.hir_expect_item(external_impl); + let (ident, sig, _, _) = item.expect_fn(); + (sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())), ident) }; let declaration_args = declaration.as_local().map(|def_id| { @@ -403,7 +395,7 @@ fn extract_spans_for_error_reporting<'tcx>( declaration_args.and_then(|mut args| args.nth(i)), external_impl_name, ), - _ => (cause.span, tcx.hir().span_if_local(declaration), external_impl_name), + _ => (cause.span, tcx.hir_span_if_local(declaration), external_impl_name), } } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index f9ecadbcf6d41..7080aef226739 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -40,7 +40,7 @@ use rustc_trait_selection::traits::{ use tracing::{debug, instrument}; use {rustc_ast as ast, rustc_hir as hir}; -use super::compare_eii::{compare_eii_function_types, compare_eii_predicate_entailment}; +use super::compare_eii::compare_eii_function_types; use crate::autoderef::Autoderef; use crate::collect::CollectItemTypesVisitor; use crate::constrained_generic_params::{Parameter, identify_constrained_generic_params}; diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 09e6242aa3994..34e9fc7c5fb10 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1851,7 +1851,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_macro(&mut self, def_id: LocalDefId) { let tcx = self.tcx; - let hir::ItemKind::Macro(_, macro_def, _) = tcx.hir_expect_item(def_id).kind else { bug!() }; + let hir::ItemKind::Macro(_, macro_def, _) = tcx.hir_expect_item(def_id).kind else { + bug!() + }; self.tables.is_macro_rules.set(def_id.local_def_index, macro_def.macro_rules); record!(self.tables.macro_definition[def_id.to_def_id()] <- &*macro_def.body); } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 9c40c0938f738..8b4891f568167 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2205,9 +2205,10 @@ impl<'a> Parser<'a> { }; self.psess.gated_spans.gate(sym::decl_macro, lo.to(self.prev_token.span)); - Ok( - ItemKind::MacroDef(ident, ast::MacroDef { body, macro_rules: false, eii_macro_for: None }), - ) + Ok(ItemKind::MacroDef( + ident, + ast::MacroDef { body, macro_rules: false, eii_macro_for: None }, + )) } /// Is this a possibly malformed start of a `macro_rules! foo` item definition? @@ -2254,9 +2255,10 @@ impl<'a> Parser<'a> { self.eat_semi_for_macro_if_needed(&body); self.complain_if_pub_macro(vis, true); - Ok( - ItemKind::MacroDef(ident, ast::MacroDef { body, macro_rules: true, eii_macro_for: None }), - ) + Ok(ItemKind::MacroDef( + ident, + ast::MacroDef { body, macro_rules: true, eii_macro_for: None }, + )) } /// Item macro invocations or `macro_rules!` definitions need inherited visibility. diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 525d3cccbe1f9..3a89e94ab43d4 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -488,7 +488,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { _target_span: Span, target: Target, ) { - for EIIImpl { span, inner_span, eii_macro, impl_marked_unsafe } in impls { + for EIIImpl { span, inner_span, eii_macro, impl_marked_unsafe, is_default: _ } in impls { match target { Target::Fn => {} _ => { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 665d927dfb6e6..7873d367c51f3 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1066,7 +1066,6 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r }; debug!("(resolving function) entering function"); - if let FnKind::Fn(_, _, f) = fn_kind { for EIIImpl { node_id, eii_macro_path, .. } in &f.eii_impl { self.smart_resolve_path(*node_id, &None, &eii_macro_path, PathSource::Macro); @@ -2851,7 +2850,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.parent_scope.macro_rules = self.r.macro_rules_scopes[&def_id]; } - if let Some(EiiMacroFor { extern_item_path, impl_unsafe: _ }) = + if let Some(EIIMacroFor { extern_item_path, impl_unsafe: _ }) = ¯o_def.eii_macro_for { self.smart_resolve_path( From c1df98da0ca36d16695813229d3698899ca368f7 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 17 Mar 2025 14:15:26 +0100 Subject: [PATCH 16/41] Update. --- compiler/rustc_ast_lowering/src/item.rs | 55 ++--- compiler/rustc_ast_pretty/src/pprust/state.rs | 11 + compiler/rustc_builtin_macros/src/eii.rs | 207 +++++++++++++++++- compiler/rustc_builtin_macros/src/lib.rs | 1 + .../rustc_codegen_ssa/src/codegen_attrs.rs | 12 +- compiler/rustc_feature/src/builtin_attrs.rs | 15 -- library/core/src/lib.rs | 3 + library/core/src/macros/mod.rs | 10 + 8 files changed, 270 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 26437ca9e39a2..eb4968fbfbea8 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -153,30 +153,34 @@ impl<'hir> LoweringContext<'_, 'hir> { i: &ItemKind, ) -> Vec { match i { + ItemKind::Fn(box Fn { eii_impl, .. }) if eii_impl.is_empty() => Vec::new(), ItemKind::Fn(box Fn { eii_impl, .. }) => { - let mut eii_impls = ThinVec::new(); - for EIIImpl { - node_id, - eii_macro_path, - impl_safety, - span, - inner_span, - is_default, - } in eii_impl - { - let did = self.lower_path_simple_eii(*node_id, eii_macro_path); - eii_impls.push(rustc_attr_parsing::EIIImpl { - eii_macro: did, - span: self.lower_span(*span), - inner_span: self.lower_span(*inner_span), - impl_marked_unsafe: self - .lower_safety(*impl_safety, hir::Safety::Safe) - .is_unsafe(), - is_default: *is_default, - }) - } - - vec![hir::Attribute::Parsed(AttributeKind::EiiImpl(eii_impls))] + vec![hir::Attribute::Parsed(AttributeKind::EiiImpl( + eii_impl + .iter() + .map( + |EIIImpl { + node_id, + eii_macro_path, + impl_safety, + span, + inner_span, + is_default, + }| { + let did = self.lower_path_simple_eii(*node_id, eii_macro_path); + rustc_attr_parsing::EIIImpl { + eii_macro: did, + span: self.lower_span(*span), + inner_span: self.lower_span(*inner_span), + impl_marked_unsafe: self + .lower_safety(*impl_safety, hir::Safety::Safe) + .is_unsafe(), + is_default: *is_default, + } + }, + ) + .collect(), + ))] } ItemKind::MacroDef( _, @@ -541,14 +545,13 @@ impl<'hir> LoweringContext<'_, 'hir> { def_kind.descr(def_id.to_def_id()) ); }; - - let ast_macro_def = self.arena.alloc(ast::MacroDef { + let macro_def = self.arena.alloc(ast::MacroDef { body, macro_rules: *macro_rules, eii_macro_for: None, }); - hir::ItemKind::Macro(ident, ast_macro_def, macro_kind) + hir::ItemKind::Macro(ident, macro_def, macro_kind) } ItemKind::Delegation(box delegation) => { let delegation_results = self.lower_delegation(delegation, id, false); diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 5c7d93a61a3b3..669e6de04e080 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -845,6 +845,17 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere sp: Span, print_visibility: impl FnOnce(&mut Self), ) { + if let Some(eii_macro_for) = ¯o_def.eii_macro_for { + self.word("#[eii_macro_for("); + self.print_path(&eii_macro_for.extern_item_path, false, 0); + if eii_macro_for.impl_unsafe { + self.word(","); + self.space(); + self.word("unsafe"); + } + self.word(")]"); + self.hardbreak(); + } let (kw, has_bang) = if macro_def.macro_rules { ("macro_rules", true) } else { diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index 809408d1abd16..3f5a4538a6432 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -1,7 +1,210 @@ -use rustc_ast::{DUMMY_NODE_ID, EIIImpl, EIIMacroFor, ItemKind, ast}; +use rustc_ast::ptr::P; +use rustc_ast::token::{Delimiter, TokenKind}; +use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; +use rustc_ast::{DUMMY_NODE_ID, EIIImpl, EIIMacroFor, ItemKind, ast, token, tokenstream}; use rustc_ast_pretty::pprust::path_to_string; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::{Span, kw}; +use rustc_span::{Ident, Span, kw, sym}; + +/* ```rust + +#[eii] +fn panic_handler(); + +#[eii(panic_handler)] +fn panic_handler(); + +#[eii(panic_handler, unsafe)] +fn panic_handler(); + +// expansion: + +extern "Rust" { + fn panic_handler(); +} + +#[rustc_builtin_macro(eii_macro)] // eii_macro_for: panic_handler +macro panic_handler() {} + +``` */ +pub(crate) fn eii( + ecx: &mut ExtCtxt<'_>, + span: Span, + meta_item: &ast::MetaItem, + item: Annotatable, +) -> Vec { + let span = ecx.with_def_site_ctxt(span); + + let Annotatable::Item(item) = item else { + ecx.dcx() + .emit_err(EIIMacroExpectedFunction { span, name: path_to_string(&meta_item.path) }); + return vec![item]; + }; + + let orig_item = item.clone(); + + let item = item.into_inner(); + + let ast::Item { + attrs, + id: _, + span: item_span, + vis, + kind: ItemKind::Fn(mut func), + tokens: _, + } = item + else { + ecx.dcx() + .emit_err(EIIMacroExpectedFunction { span, name: path_to_string(&meta_item.path) }); + return vec![Annotatable::Item(P(item))]; + }; + + let macro_name = if meta_item.is_word() { + func.ident + } else if let Some([first]) = meta_item.meta_item_list() + && let Some(m) = first.meta_item() + && m.path.segments.len() == 1 + { + m.path.segments[0].ident + } else { + ecx.dcx().emit_err(EIIMacroExpectedMaxOneArgument { + span: meta_item.span, + name: path_to_string(&meta_item.path), + }); + return vec![Annotatable::Item(orig_item)]; + }; + + let impl_unsafe = false; // TODO + + let abi = match func.sig.header.ext { + // extern "X" fn => extern "X" {} + ast::Extern::Explicit(lit, _) => Some(lit), + // extern fn => extern {} + ast::Extern::Implicit(_) => None, + // fn => extern "Rust" {} + ast::Extern::None => Some(ast::StrLit { + symbol: sym::Rust, + suffix: None, + symbol_unescaped: sym::Rust, + style: ast::StrStyle::Cooked, + span, + }), + }; + + // ABI has been moved to the extern {} block, so we remove it from the fn item. + func.sig.header.ext = ast::Extern::None; + + // And mark safe functions explicitly as `safe fn`. + if func.sig.header.safety == ast::Safety::Default { + func.sig.header.safety = ast::Safety::Safe(func.sig.span); + } + + // extern "…" { safe fn item(); } + let extern_block = Annotatable::Item(P(ast::Item { + attrs: ast::AttrVec::default(), + id: ast::DUMMY_NODE_ID, + span, + vis: ast::Visibility { span, kind: ast::VisibilityKind::Inherited, tokens: None }, + kind: ast::ItemKind::ForeignMod(ast::ForeignMod { + extern_span: span, + safety: ast::Safety::Unsafe(span), + abi, + items: From::from([P(ast::ForeignItem { + attrs, + id: ast::DUMMY_NODE_ID, + span: item_span, + vis, + kind: ast::ForeignItemKind::Fn(func.clone()), + tokens: None, + })]), + }), + tokens: None, + })); + + let macro_def = Annotatable::Item(P(ast::Item { + attrs: ast::AttrVec::from_iter([ + // #[eii_macro_for(func.ident)] + ast::Attribute { + kind: ast::AttrKind::Normal(P(ast::NormalAttr { + item: ast::AttrItem { + unsafety: ast::Safety::Default, + path: ast::Path::from_ident(Ident::new(sym::eii_macro_for, span)), + args: ast::AttrArgs::Delimited(ast::DelimArgs { + dspan: DelimSpan::from_single(span), + delim: Delimiter::Parenthesis, + tokens: TokenStream::new(vec![tokenstream::TokenTree::Token( + token::Token::from_ast_ident(func.ident), + Spacing::Alone, + )]), + }), + tokens: None, + }, + tokens: None, + })), + id: ecx.sess.psess.attr_id_generator.mk_attr_id(), + style: ast::AttrStyle::Outer, + span, + }, + // #[builtin_macro(eii_macro)] + ast::Attribute { + kind: ast::AttrKind::Normal(P(ast::NormalAttr { + item: ast::AttrItem { + unsafety: ast::Safety::Default, + path: ast::Path::from_ident(Ident::new(sym::rustc_builtin_macro, span)), + args: ast::AttrArgs::Delimited(ast::DelimArgs { + dspan: DelimSpan::from_single(span), + delim: Delimiter::Parenthesis, + tokens: TokenStream::new(vec![tokenstream::TokenTree::token_alone( + token::TokenKind::Ident(sym::eii_macro, token::IdentIsRaw::No), + span, + )]), + }), + tokens: None, + }, + tokens: None, + })), + id: ecx.sess.psess.attr_id_generator.mk_attr_id(), + style: ast::AttrStyle::Outer, + span, + }, + ]), + id: ast::DUMMY_NODE_ID, + span, + // pub + vis: ast::Visibility { span, kind: ast::VisibilityKind::Public, tokens: None }, + kind: ast::ItemKind::MacroDef( + // macro macro_name + macro_name, + ast::MacroDef { + // { () => {} } + body: P(ast::DelimArgs { + dspan: DelimSpan::from_single(span), + delim: Delimiter::Brace, + tokens: TokenStream::from_iter([ + TokenTree::Delimited( + DelimSpan::from_single(span), + DelimSpacing::new(Spacing::Alone, Spacing::Alone), + Delimiter::Parenthesis, + TokenStream::default(), + ), + TokenTree::token_alone(TokenKind::FatArrow, span), + TokenTree::Delimited( + DelimSpan::from_single(span), + DelimSpacing::new(Spacing::Alone, Spacing::Alone), + Delimiter::Brace, + TokenStream::default(), + ), + ]), + }), + macro_rules: false, + eii_macro_for: None, + } + ), + tokens: None, + })); + + vec![extern_block, macro_def] +} use crate::errors::{ EIIMacroExpectedFunction, EIIMacroExpectedMaxOneArgument, EIIMacroForExpectedList, diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 343f3a2b11f86..eeb825253e1df 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -124,6 +124,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { global_allocator: global_allocator::expand, test: test::expand_test, test_case: test::expand_test_case, + eii: eii::eii, eii_macro_for: eii::eii_macro_for, eii_macro: eii::eii_macro, } diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 5d09e62f2742d..8c2efb01c4a4f 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -112,13 +112,23 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if let hir::Attribute::Parsed(p) = attr { match p { + /* + AttributeKind::EiiImpl(eii_macro) => { + let Some(eii_extern_item) = find_attr!( + tcx.get_all_attrs(eii_macro), + AttributeKind::EiiMacroFor { eii_extern_item, .. } => *eii_extern_item + ) else { + tcx.dcx().span_delayed_bug(attr.span(), "missing attr on EII macro"); + continue; + }; + let _ = eii_extern_item; // XXX mangle as this item or something. + }*/ AttributeKind::Repr(reprs) => { codegen_fn_attrs.alignment = reprs .iter() .filter_map(|(r, _)| if let ReprAlign(x) = r { Some(*x) } else { None }) .max(); } - _ => {} } } diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index ebf63b78a7212..c117e0fcf7ccc 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1073,21 +1073,6 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ "#[rustc_force_inline] forces a free function to be inlined" ), - gated!( - eii, Normal, template!(Word), - ErrorPreceding, EncodeCrossCrate::No, - eii_internals, "internally used to implement EII" - ), - gated!( - eii_impl, Normal, template!(List: "/*opt*/ default"), - ErrorPreceding, EncodeCrossCrate::No, - eii_internals, "internally used to implement EII" - ), - gated!( - eii_macro_for, Normal, template!(List: "path"), - ErrorPreceding, EncodeCrossCrate::No, - eii_internals, "internally used to implement EII" - ), // ========================================================================== // Internal attributes, Testing: // ========================================================================== diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 11fb2a1b61799..6cf8da1151754 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -232,6 +232,9 @@ pub mod autodiff { pub use crate::macros::builtin::autodiff; } +#[cfg(not(bootstrap))] +#[unstable(feature = "eii", issue = "none")] +pub use crate::macros::builtin::eii; #[cfg(not(bootstrap))] #[unstable(feature = "eii_internals", issue = "none")] pub use crate::macros::builtin::eii_macro_for; diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index e043185d0440c..de117deb08779 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1784,6 +1784,16 @@ pub(crate) mod builtin { builtin # deref($pat) } + /// Externally Implementable Item: Defines an attribute macro that can override the item + /// this is applied to. + #[cfg(not(bootstrap))] + #[unstable(feature = "eii", issue = "none")] + #[rustc_builtin_macro] + #[allow_internal_unstable(eii_internals, decl_macro, rustc_attrs)] + pub macro eii($item:item) { + /* compiler built-in */ + } + /// Impl detail of EII #[cfg(not(bootstrap))] #[unstable(feature = "eii_internals", issue = "none")] From e72ed5a8bb668f39f759790f2a59a872d446244f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 17 Mar 2025 15:29:01 +0100 Subject: [PATCH 17/41] Move eii macros to prelude. --- library/core/src/lib.rs | 7 ------- library/core/src/prelude/v1.rs | 8 ++++++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 6cf8da1151754..64a7ec8906b6b 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -232,13 +232,6 @@ pub mod autodiff { pub use crate::macros::builtin::autodiff; } -#[cfg(not(bootstrap))] -#[unstable(feature = "eii", issue = "none")] -pub use crate::macros::builtin::eii; -#[cfg(not(bootstrap))] -#[unstable(feature = "eii_internals", issue = "none")] -pub use crate::macros::builtin::eii_macro_for; - #[unstable(feature = "contracts", issue = "128044")] pub mod contracts; diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index 9737d0baec7ca..497b9cc1dbd97 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -119,3 +119,11 @@ pub use crate::macros::builtin::deref; reason = "`type_alias_impl_trait` has open design concerns" )] pub use crate::macros::builtin::define_opaque; + +#[unstable(feature = "eii", issue = "none")] +#[cfg(not(bootstrap))] +pub use crate::macros::builtin::eii; + +#[unstable(feature = "eii_internals", issue = "none")] +#[cfg(not(bootstrap))] +pub use crate::macros::builtin::eii_macro_for; From 204a589d51ccf5b80b974c08fbd7375461d324ac Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 17 Mar 2025 16:15:13 +0100 Subject: [PATCH 18/41] Add #[unsafe_eii]. --- compiler/rustc_builtin_macros/src/eii.rs | 85 ++++++++++++------------ compiler/rustc_builtin_macros/src/lib.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + library/core/src/macros/mod.rs | 10 +++ library/core/src/prelude/v1.rs | 2 +- 5 files changed, 54 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index 3f5a4538a6432..1de54bc936908 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -6,32 +6,49 @@ use rustc_ast_pretty::pprust::path_to_string; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::{Ident, Span, kw, sym}; -/* ```rust - -#[eii] -fn panic_handler(); - -#[eii(panic_handler)] -fn panic_handler(); - -#[eii(panic_handler, unsafe)] -fn panic_handler(); - -// expansion: - -extern "Rust" { - fn panic_handler(); +// ```rust +// #[eii] +// fn panic_handler(); +// +// // or: +// +// #[eii(panic_handler)] +// fn panic_handler(); +// +// // expansion: +// +// extern "Rust" { +// fn panic_handler(); +// } +// +// #[rustc_builtin_macro(eii_macro)] +// #[eii_macro_for(panic_handler)] +// macro panic_handler() {} +// ``` +pub(crate) fn eii( + ecx: &mut ExtCtxt<'_>, + span: Span, + meta_item: &ast::MetaItem, + item: Annotatable, +) -> Vec { + eii_(ecx, span, meta_item, item, false) } -#[rustc_builtin_macro(eii_macro)] // eii_macro_for: panic_handler -macro panic_handler() {} +pub(crate) fn unsafe_eii( + ecx: &mut ExtCtxt<'_>, + span: Span, + meta_item: &ast::MetaItem, + item: Annotatable, +) -> Vec { + eii_(ecx, span, meta_item, item, true) +} -``` */ -pub(crate) fn eii( +fn eii_( ecx: &mut ExtCtxt<'_>, span: Span, meta_item: &ast::MetaItem, item: Annotatable, + impl_unsafe: bool, ) -> Vec { let span = ecx.with_def_site_ctxt(span); @@ -74,8 +91,6 @@ pub(crate) fn eii( return vec![Annotatable::Item(orig_item)]; }; - let impl_unsafe = false; // TODO - let abi = match func.sig.header.ext { // extern "X" fn => extern "X" {} ast::Extern::Explicit(lit, _) => Some(lit), @@ -123,28 +138,6 @@ pub(crate) fn eii( let macro_def = Annotatable::Item(P(ast::Item { attrs: ast::AttrVec::from_iter([ - // #[eii_macro_for(func.ident)] - ast::Attribute { - kind: ast::AttrKind::Normal(P(ast::NormalAttr { - item: ast::AttrItem { - unsafety: ast::Safety::Default, - path: ast::Path::from_ident(Ident::new(sym::eii_macro_for, span)), - args: ast::AttrArgs::Delimited(ast::DelimArgs { - dspan: DelimSpan::from_single(span), - delim: Delimiter::Parenthesis, - tokens: TokenStream::new(vec![tokenstream::TokenTree::Token( - token::Token::from_ast_ident(func.ident), - Spacing::Alone, - )]), - }), - tokens: None, - }, - tokens: None, - })), - id: ecx.sess.psess.attr_id_generator.mk_attr_id(), - style: ast::AttrStyle::Outer, - span, - }, // #[builtin_macro(eii_macro)] ast::Attribute { kind: ast::AttrKind::Normal(P(ast::NormalAttr { @@ -197,7 +190,11 @@ pub(crate) fn eii( ]), }), macro_rules: false, - eii_macro_for: None, + // #[eii_macro_for(func.ident)] + eii_macro_for: Some(ast::EIIMacroFor { + extern_item_path: ast::Path::from_ident(func.ident), + impl_unsafe, + }), } ), tokens: None, diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index eeb825253e1df..61cc87b6a87dd 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -125,6 +125,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { test: test::expand_test, test_case: test::expand_test_case, eii: eii::eii, + unsafe_eii: eii::unsafe_eii, eii_macro_for: eii::eii_macro_for, eii_macro: eii::eii_macro, } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 853dd96c54703..247ebc219fd3a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2224,6 +2224,7 @@ symbols! { unsafe_block_in_unsafe_fn, unsafe_cell, unsafe_cell_raw_get, + unsafe_eii, unsafe_extern_blocks, unsafe_fields, unsafe_no_drop_flag, diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index de117deb08779..27962cdf0c531 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1794,6 +1794,16 @@ pub(crate) mod builtin { /* compiler built-in */ } + /// Unsafely Externally Implementable Item: Defines an unsafe attribute macro that can override + /// the item this is applied to. + #[cfg(not(bootstrap))] + #[unstable(feature = "eii", issue = "none")] + #[rustc_builtin_macro] + #[allow_internal_unstable(eii_internals, decl_macro, rustc_attrs)] + pub macro unsafe_eii($item:item) { + /* compiler built-in */ + } + /// Impl detail of EII #[cfg(not(bootstrap))] #[unstable(feature = "eii_internals", issue = "none")] diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index 497b9cc1dbd97..4d2d8b5103410 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -122,7 +122,7 @@ pub use crate::macros::builtin::define_opaque; #[unstable(feature = "eii", issue = "none")] #[cfg(not(bootstrap))] -pub use crate::macros::builtin::eii; +pub use crate::macros::builtin::{eii, unsafe_eii}; #[unstable(feature = "eii_internals", issue = "none")] #[cfg(not(bootstrap))] From 52c31bb6ac0148c32783727f5f9d25294e3128f7 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 17 Mar 2025 16:15:20 +0100 Subject: [PATCH 19/41] Add eii macros to std preludes. --- library/std/src/prelude/v1.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 68c9ac1e41463..17f0767eea044 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -112,6 +112,14 @@ pub use core::prelude::v1::deref; )] pub use core::prelude::v1::define_opaque; +#[unstable(feature = "eii", issue = "none")] +#[cfg(not(bootstrap))] +pub use core::prelude::v1::{eii, unsafe_eii}; + +#[unstable(feature = "eii_internals", issue = "none")] +#[cfg(not(bootstrap))] +pub use core::prelude::v1::eii_macro_for; + // The file so far is equivalent to core/src/prelude/v1.rs. It is duplicated // rather than glob imported because we want docs to show these re-exports as // pointing to within `std`. From c42319546a49dfe70980441a34c570740c9bc9d9 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 17 Mar 2025 16:15:50 +0100 Subject: [PATCH 20/41] Update tests. --- .../auxiliary/cross_crate_eii_declaration.rs | 2 +- tests/ui/eii/errors.rs | 18 ++++----- tests/ui/eii/errors.stderr | 40 +++++++++---------- tests/ui/eii/subtype_1.rs | 2 +- tests/ui/eii/subtype_2.rs | 2 +- tests/ui/eii/subtype_3.rs | 2 +- tests/ui/eii/subtype_4.rs | 2 +- tests/ui/eii/unsafe_impl_err.rs | 2 +- tests/ui/eii/unsafe_impl_ok.rs | 2 +- tests/ui/eii/wrong_ret_ty.rs | 2 +- tests/ui/eii/wrong_ty.rs | 2 +- tests/ui/eii/wrong_ty_2.rs | 2 +- 12 files changed, 39 insertions(+), 39 deletions(-) diff --git a/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs b/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs index 01acf117d743f..f077e54b52d19 100644 --- a/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs +++ b/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs @@ -3,7 +3,7 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[core::eii_macro_for(bar)] +#[eii_macro_for(bar)] #[rustc_builtin_macro(eii_macro)] pub macro foo() { diff --git a/tests/ui/eii/errors.rs b/tests/ui/eii/errors.rs index cea9d3bb53f53..fab549c9e4b42 100644 --- a/tests/ui/eii/errors.rs +++ b/tests/ui/eii/errors.rs @@ -4,19 +4,19 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[core::eii_macro_for(bar)] //~ ERROR `#[eii_macro_for(...)]` is only valid on macros +#[eii_macro_for(bar)] //~ ERROR `#[eii_macro_for(...)]` is only valid on macros fn hello() { - #[core::eii_macro_for(bar)] //~ ERROR `#[eii_macro_for(...)]` is only valid on macros + #[eii_macro_for(bar)] //~ ERROR `#[eii_macro_for(...)]` is only valid on macros let x = 3 + 3; } -#[core::eii_macro_for] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements -#[core::eii_macro_for()] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements -#[core::eii_macro_for(bar, hello)] //~ ERROR expected this argument to be "unsafe" -#[core::eii_macro_for(bar, "unsafe", hello)] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements -#[core::eii_macro_for(bar, hello, "unsafe")] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements -#[core::eii_macro_for = "unsafe"] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements -#[core::eii_macro_for(bar)] +#[eii_macro_for] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements +#[eii_macro_for()] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements +#[eii_macro_for(bar, hello)] //~ ERROR expected this argument to be "unsafe" +#[eii_macro_for(bar, "unsafe", hello)] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements +#[eii_macro_for(bar, hello, "unsafe")] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements +#[eii_macro_for = "unsafe"] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements +#[eii_macro_for(bar)] #[rustc_builtin_macro(eii_macro)] macro foo() {} diff --git a/tests/ui/eii/errors.stderr b/tests/ui/eii/errors.stderr index 535ba6277c6bb..b5eba839a1491 100644 --- a/tests/ui/eii/errors.stderr +++ b/tests/ui/eii/errors.stderr @@ -1,56 +1,56 @@ error: `#[eii_macro_for(...)]` is only valid on macros --> $DIR/errors.rs:7:1 | -LL | #[core::eii_macro_for(bar)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[eii_macro_for(bar)] + | ^^^^^^^^^^^^^^^^^^^^^ error: `#[eii_macro_for(...)]` is only valid on macros --> $DIR/errors.rs:9:5 | -LL | #[core::eii_macro_for(bar)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[eii_macro_for(bar)] + | ^^^^^^^^^^^^^^^^^^^^^ error: `#[eii_macro_for(...)]` expects a list of one or two elements --> $DIR/errors.rs:13:1 | -LL | #[core::eii_macro_for] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #[eii_macro_for] + | ^^^^^^^^^^^^^^^^ error: `#[eii_macro_for(...)]` expects a list of one or two elements --> $DIR/errors.rs:14:1 | -LL | #[core::eii_macro_for()] - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[eii_macro_for()] + | ^^^^^^^^^^^^^^^^^^ error: expected this argument to be "unsafe". - --> $DIR/errors.rs:15:28 + --> $DIR/errors.rs:15:22 | -LL | #[core::eii_macro_for(bar, hello)] - | ^^^^^ +LL | #[eii_macro_for(bar, hello)] + | ^^^^^ | note: the second argument is optional - --> $DIR/errors.rs:15:28 + --> $DIR/errors.rs:15:22 | -LL | #[core::eii_macro_for(bar, hello)] - | ^^^^^ +LL | #[eii_macro_for(bar, hello)] + | ^^^^^ error: `#[eii_macro_for(...)]` expects a list of one or two elements --> $DIR/errors.rs:16:1 | -LL | #[core::eii_macro_for(bar, "unsafe", hello)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[eii_macro_for(bar, "unsafe", hello)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[eii_macro_for(...)]` expects a list of one or two elements --> $DIR/errors.rs:17:1 | -LL | #[core::eii_macro_for(bar, hello, "unsafe")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[eii_macro_for(bar, hello, "unsafe")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[eii_macro_for(...)]` expects a list of one or two elements --> $DIR/errors.rs:18:1 | -LL | #[core::eii_macro_for = "unsafe"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[eii_macro_for = "unsafe"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[foo]` is only valid on functions --> $DIR/errors.rs:27:1 diff --git a/tests/ui/eii/subtype_1.rs b/tests/ui/eii/subtype_1.rs index e20a9b6806dad..67f0923cabd25 100644 --- a/tests/ui/eii/subtype_1.rs +++ b/tests/ui/eii/subtype_1.rs @@ -5,7 +5,7 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[core::eii_macro_for(bar)] +#[eii_macro_for(bar)] #[rustc_builtin_macro(eii_macro)] macro foo() { diff --git a/tests/ui/eii/subtype_2.rs b/tests/ui/eii/subtype_2.rs index 985eaa9237ec0..be6482c9cd8d7 100644 --- a/tests/ui/eii/subtype_2.rs +++ b/tests/ui/eii/subtype_2.rs @@ -4,7 +4,7 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[core::eii_macro_for(bar)] +#[eii_macro_for(bar)] #[rustc_builtin_macro(eii_macro)] macro foo() { diff --git a/tests/ui/eii/subtype_3.rs b/tests/ui/eii/subtype_3.rs index e746af84552f2..b685ee1d222a8 100644 --- a/tests/ui/eii/subtype_3.rs +++ b/tests/ui/eii/subtype_3.rs @@ -5,7 +5,7 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[core::eii_macro_for(bar)] +#[eii_macro_for(bar)] #[rustc_builtin_macro(eii_macro)] macro foo() { diff --git a/tests/ui/eii/subtype_4.rs b/tests/ui/eii/subtype_4.rs index a3ba6829ba3b8..c3384bbbfe69d 100644 --- a/tests/ui/eii/subtype_4.rs +++ b/tests/ui/eii/subtype_4.rs @@ -5,7 +5,7 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[core::eii_macro_for(bar)] +#[eii_macro_for(bar)] #[rustc_builtin_macro(eii_macro)] macro foo() { diff --git a/tests/ui/eii/unsafe_impl_err.rs b/tests/ui/eii/unsafe_impl_err.rs index 3f6f07e3b1184..423f5b1a93bec 100644 --- a/tests/ui/eii/unsafe_impl_err.rs +++ b/tests/ui/eii/unsafe_impl_err.rs @@ -4,7 +4,7 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[core::eii_macro_for(bar, "unsafe")] +#[eii_macro_for(bar, "unsafe")] #[rustc_builtin_macro(eii_macro)] macro foo() { diff --git a/tests/ui/eii/unsafe_impl_ok.rs b/tests/ui/eii/unsafe_impl_ok.rs index ecc254ca8ffd8..278dd9084220e 100644 --- a/tests/ui/eii/unsafe_impl_ok.rs +++ b/tests/ui/eii/unsafe_impl_ok.rs @@ -5,7 +5,7 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[core::eii_macro_for(bar, "unsafe")] +#[eii_macro_for(bar, "unsafe")] #[rustc_builtin_macro(eii_macro)] macro foo() { diff --git a/tests/ui/eii/wrong_ret_ty.rs b/tests/ui/eii/wrong_ret_ty.rs index 6bd728992bd94..0d8df934a38cf 100644 --- a/tests/ui/eii/wrong_ret_ty.rs +++ b/tests/ui/eii/wrong_ret_ty.rs @@ -4,7 +4,7 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[core::eii_macro_for(bar)] +#[eii_macro_for(bar)] #[rustc_builtin_macro(eii_macro)] macro foo() { diff --git a/tests/ui/eii/wrong_ty.rs b/tests/ui/eii/wrong_ty.rs index bc50f67bc10fa..0e06359b72526 100644 --- a/tests/ui/eii/wrong_ty.rs +++ b/tests/ui/eii/wrong_ty.rs @@ -4,7 +4,7 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[core::eii_macro_for(bar)] +#[eii_macro_for(bar)] #[rustc_builtin_macro(eii_macro)] macro foo() { diff --git a/tests/ui/eii/wrong_ty_2.rs b/tests/ui/eii/wrong_ty_2.rs index c4f3006efad9c..665a2833da1d8 100644 --- a/tests/ui/eii/wrong_ty_2.rs +++ b/tests/ui/eii/wrong_ty_2.rs @@ -4,7 +4,7 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[core::eii_macro_for(bar)] +#[eii_macro_for(bar)] #[rustc_builtin_macro(eii_macro)] macro foo() { From 3cc5076053a8b43316dbe95be62c8e0c06ed7e7c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 17 Mar 2025 16:50:55 +0100 Subject: [PATCH 21/41] Allow builtin macros to be used more than once. This removes E0773 "A builtin-macro was defined more than once." --- compiler/rustc_builtin_macros/src/eii.rs | 12 +++--------- compiler/rustc_resolve/src/macros.rs | 2 -- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index 1de54bc936908..aa08b30079aa7 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -62,14 +62,8 @@ fn eii_( let item = item.into_inner(); - let ast::Item { - attrs, - id: _, - span: item_span, - vis, - kind: ItemKind::Fn(mut func), - tokens: _, - } = item + let ast::Item { attrs, id: _, span: item_span, vis, kind: ItemKind::Fn(mut func), tokens: _ } = + item else { ecx.dcx() .emit_err(EIIMacroExpectedFunction { span, name: path_to_string(&meta_item.path) }); @@ -195,7 +189,7 @@ fn eii_( extern_item_path: ast::Path::from_ident(func.ident), impl_unsafe, }), - } + }, ), tokens: None, })); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index c58f84805720d..9909af82d58d8 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -1131,8 +1131,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if let Some(builtin_name) = ext.builtin_name { // The macro was marked with `#[rustc_builtin_macro]`. if let Some(builtin_ext_kind) = self.builtin_macros.get(&builtin_name) { - // The macro is a built-in, replace its expander function - // while still taking everything else from the source code. ext.kind = builtin_ext_kind.clone(); rule_spans = Vec::new(); } else { From ff42eed624263445545b045df99173ecc13274be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 17 Mar 2025 18:07:36 +0100 Subject: [PATCH 22/41] better error messages on cross-crate eiis --- .../src/check/compare_eii.rs | 35 ++++++++++--------- tests/ui/eii/cross_crate_wrong_ty.stderr | 5 +++ 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index 42a3886065aca..7ca08fc29afc8 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -68,6 +68,7 @@ fn check_region_bounds_on_impl_item<'tcx>( let mut generics_span = None; let mut bounds_span = vec![]; let mut where_span = None; + if let Some(declaration_node) = tcx.hir_get_if_local(declaration) && let Some(declaration_generics) = declaration_node.generics() { @@ -83,11 +84,9 @@ fn check_region_bounds_on_impl_item<'tcx>( } } } - if let Some(declaration_node) = tcx.hir_get_if_local(declaration) - && let Some(declaration_generics) = declaration_node.generics() - { + if let Some(implementation_generics) = tcx.hir_get_generics(external_impl) { let mut impl_bounds = 0; - for p in declaration_generics.predicates { + for p in implementation_generics.predicates { if let hir::WherePredicateKind::BoundPredicate(pred) = p.kind { for b in pred.bounds { if let hir::GenericBound::Outlives(_) = b { @@ -98,8 +97,8 @@ fn check_region_bounds_on_impl_item<'tcx>( } if impl_bounds == bounds_span.len() { bounds_span = vec![]; - } else if declaration_generics.has_where_clause_predicates { - where_span = Some(declaration_generics.where_clause_span); + } else if implementation_generics.has_where_clause_predicates { + where_span = Some(implementation_generics.where_clause_span); } } } @@ -145,7 +144,8 @@ fn compare_number_of_method_arguments<'tcx>( } }) }) - .or_else(|| tcx.hir_span_if_local(declaration)); + .or_else(|| tcx.hir_span_if_local(declaration)) + .unwrap_or_else(|| tcx.def_span(declaration)); let (_, external_impl_sig, _, _) = &tcx.hir_expect_item(external_impl).expect_fn(); let pos = external_impl_number_args.saturating_sub(1); @@ -171,15 +171,12 @@ fn compare_number_of_method_arguments<'tcx>( declaration_number_args ); - if let Some(declaration_span) = declaration_span { - err.span_label( - declaration_span, - format!( - "requires {}", - potentially_plural_count(declaration_number_args, "parameter") - ), - ); - } + // if let Some(declaration_span) = declaration_span { + err.span_label( + declaration_span, + format!("requires {}", potentially_plural_count(declaration_number_args, "parameter")), + ); + // } err.span_label( impl_span, @@ -395,7 +392,11 @@ fn extract_spans_for_error_reporting<'tcx>( declaration_args.and_then(|mut args| args.nth(i)), external_impl_name, ), - _ => (cause.span, tcx.hir_span_if_local(declaration), external_impl_name), + _ => ( + cause.span, + tcx.hir_span_if_local(declaration).or_else(|| Some(tcx.def_span(declaration))), + external_impl_name, + ), } } diff --git a/tests/ui/eii/cross_crate_wrong_ty.stderr b/tests/ui/eii/cross_crate_wrong_ty.stderr index 25dc6dbc5cb4f..0e46ee43f7467 100644 --- a/tests/ui/eii/cross_crate_wrong_ty.stderr +++ b/tests/ui/eii/cross_crate_wrong_ty.stderr @@ -5,6 +5,11 @@ LL | #[unsafe(cross_crate_eii_declaration::foo)] | ------------------------------------------- required because of this attribute LL | fn other() -> u64 { | ^^^^^^^^^^^^^^^^^ expected 1 parameter, found 0 + | + ::: $DIR/auxiliary/cross_crate_eii_declaration.rs:13:5 + | +LL | pub safe fn bar(x: u64) -> u64; + | ------------------------------- requires 1 parameter error: aborting due to 1 previous error From 4b8c94b60d521a57352dfe6cc2fdb92d5b271eb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 31 Mar 2025 17:07:36 +0200 Subject: [PATCH 23/41] allow eii marked items to have a body which becomes a default --- compiler/rustc_builtin_macros/src/eii.rs | 75 +++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index aa08b30079aa7..91c3d12b5f32c 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -5,6 +5,7 @@ use rustc_ast::{DUMMY_NODE_ID, EIIImpl, EIIMacroFor, ItemKind, ast, token, token use rustc_ast_pretty::pprust::path_to_string; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::{Ident, Span, kw, sym}; +use thin_vec::{ThinVec, thin_vec}; // ```rust // #[eii] @@ -85,6 +86,75 @@ fn eii_( return vec![Annotatable::Item(orig_item)]; }; + let mut return_items = Vec::new(); + + if func.body.is_some() { + let mut default_func = func.clone(); + func.body = None; + default_func.eii_impl.push(ast::EIIImpl { + node_id: DUMMY_NODE_ID, + eii_macro_path: ast::Path::from_ident(macro_name), + impl_safety: if impl_unsafe { ast::Safety::Unsafe(span) } else { ast::Safety::Default }, + span, + inner_span: macro_name.span, + is_default: true, // important! + }); + + return_items.push(Annotatable::Item(P(ast::Item { + attrs: ThinVec::new(), + id: ast::DUMMY_NODE_ID, + span, + vis: ast::Visibility { span, kind: ast::VisibilityKind::Inherited, tokens: None }, + ident: Ident { name: kw::Underscore, span }, + kind: ast::ItemKind::Const(Box::new(ast::ConstItem { + defaultness: ast::Defaultness::Final, + generics: ast::Generics::default(), + ty: P(ast::Ty { + id: DUMMY_NODE_ID, + kind: ast::TyKind::Tup(ThinVec::new()), + span, + tokens: None, + }), + expr: Some(P(ast::Expr { + id: DUMMY_NODE_ID, + kind: ast::ExprKind::Block( + P(ast::Block { + stmts: thin_vec![ast::Stmt { + id: DUMMY_NODE_ID, + kind: ast::StmtKind::Item(P(ast::Item { + attrs: thin_vec![], // TODO: re-add some original attrs + id: DUMMY_NODE_ID, + span: item_span, + vis: ast::Visibility { + span, + kind: ast::VisibilityKind::Inherited, + tokens: None + }, + ident: item_name, + kind: ItemKind::Fn(default_func), + tokens: None, + })), + span + }], + id: DUMMY_NODE_ID, + rules: ast::BlockCheckMode::Default, + span, + tokens: None, + could_be_bare_literal: false, + }), + None, + ), + span, + attrs: ThinVec::new(), + tokens: None, + })), + })), + tokens: None, + }))) + } + + let decl_span = span.to(func.sig.span); + let abi = match func.sig.header.ext { // extern "X" fn => extern "X" {} ast::Extern::Explicit(lit, _) => Some(lit), @@ -194,7 +264,10 @@ fn eii_( tokens: None, })); - vec![extern_block, macro_def] + return_items.push(extern_block); + return_items.push(macro_def); + + return_items } use crate::errors::{ From cb3c389cd84ccd95332447af89376d0c8b2f48b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 31 Mar 2025 18:06:12 +0200 Subject: [PATCH 24/41] codegen eii --- compiler/rustc_ast/src/ast.rs | 1 + compiler/rustc_ast/src/mut_visit.rs | 2 +- compiler/rustc_ast/src/visit.rs | 4 +- compiler/rustc_ast_lowering/src/item.rs | 12 +- .../rustc_ast_pretty/src/pprust/state/item.rs | 7 +- .../src/attributes.rs | 17 ++- .../rustc_attr_parsing/src/attributes/eii.rs | 17 +++ .../rustc_attr_parsing/src/attributes/mod.rs | 1 + compiler/rustc_attr_parsing/src/context.rs | 3 +- compiler/rustc_builtin_macros/src/eii.rs | 33 ++++- compiler/rustc_codegen_ssa/src/back/link.rs | 1 + .../src/back/symbol_export.rs | 8 +- .../rustc_codegen_ssa/src/codegen_attrs.rs | 20 +-- .../rustc_const_eval/src/interpret/call.rs | 1 + compiler/rustc_feature/src/builtin_attrs.rs | 5 + compiler/rustc_hir/src/def.rs | 2 +- .../src/check/compare_eii.rs | 4 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 4 +- compiler/rustc_interface/src/passes.rs | 3 + compiler/rustc_metadata/src/eii.rs | 40 ++++++ compiler/rustc_metadata/src/lib.rs | 1 + compiler/rustc_metadata/src/rmeta/decoder.rs | 7 + .../src/rmeta/decoder/cstore_impl.rs | 10 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 16 +++ compiler/rustc_metadata/src/rmeta/mod.rs | 4 + compiler/rustc_middle/src/arena.rs | 1 + .../src/middle/codegen_fn_attrs.rs | 8 +- .../src/middle/exported_symbols.rs | 2 + compiler/rustc_middle/src/mir/mod.rs | 2 +- compiler/rustc_middle/src/mir/mono.rs | 9 +- compiler/rustc_middle/src/mir/visit.rs | 3 +- compiler/rustc_middle/src/query/mod.rs | 12 ++ compiler/rustc_middle/src/ty/instance.rs | 19 ++- compiler/rustc_middle/src/ty/mod.rs | 37 ++--- compiler/rustc_middle/src/ty/parameterized.rs | 6 + compiler/rustc_mir_transform/src/inline.rs | 3 +- .../rustc_mir_transform/src/inline/cycle.rs | 1 + compiler/rustc_mir_transform/src/shim.rs | 51 +++++++ compiler/rustc_monomorphize/src/collector.rs | 40 +++++- .../rustc_monomorphize/src/partitioning.rs | 12 ++ compiler/rustc_passes/messages.ftl | 16 +++ compiler/rustc_passes/src/check_attr.rs | 7 +- compiler/rustc_passes/src/eii.rs | 135 ++++++++++++++++++ compiler/rustc_passes/src/errors.rs | 38 +++++ compiler/rustc_passes/src/lib.rs | 2 + compiler/rustc_passes/src/reachable.rs | 19 ++- compiler/rustc_resolve/src/late.rs | 2 +- .../rustc_smir/src/rustc_smir/convert/ty.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_symbol_mangling/src/lib.rs | 13 ++ 50 files changed, 580 insertions(+), 83 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/eii.rs create mode 100644 compiler/rustc_metadata/src/eii.rs create mode 100644 compiler/rustc_passes/src/eii.rs diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index f5375f7a34957..bc75d6d79263e 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1959,6 +1959,7 @@ pub struct MacroDef { pub struct EIIMacroFor { pub extern_item_path: Path, pub impl_unsafe: bool, + pub span: Span, } #[derive(Clone, Encodable, Decodable, Debug, Copy, Hash, Eq, PartialEq)] diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 3d31e469bc51e..fc335902d80f5 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -735,7 +735,7 @@ fn walk_mac(vis: &mut T, mac: &mut MacCall) { fn walk_macro_def(vis: &mut T, macro_def: &mut MacroDef) { let MacroDef { body, macro_rules: _, eii_macro_for } = macro_def; - if let Some(EIIMacroFor { extern_item_path, impl_unsafe: _ }) = eii_macro_for { + if let Some(EIIMacroFor { extern_item_path, impl_unsafe: _, span: _ }) = eii_macro_for { vis.visit_path(extern_item_path); } visit_delim_args(vis, body); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index a399a5451fc64..f1aa7b5533a90 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -479,7 +479,9 @@ impl WalkItemKind for ItemKind { ItemKind::MacroDef(ident, ts) => { try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_mac_def(ts, id)); - if let Some(EIIMacroFor { extern_item_path, impl_unsafe: _ }) = &ts.eii_macro_for { + if let Some(EIIMacroFor { extern_item_path, impl_unsafe: _, span: _ }) = + &ts.eii_macro_for + { try_visit!(visitor.visit_path(extern_item_path, id)); } } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index eb4968fbfbea8..e6520d2f7268b 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -2,11 +2,11 @@ use rustc_abi::ExternAbi; use rustc_ast::ptr::P; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; -use rustc_attr_parsing::AttributeKind; +use rustc_attr_parsing::{AttributeKind, EIIDecl}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; -use rustc_hir::{self as hir, HirId, LifetimeSource, IsAnonInPath, PredicateOrigin}; +use rustc_hir::{self as hir, HirId, LifetimeSource, PredicateOrigin}; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_span::edit_distance::find_best_match_for_name; @@ -185,13 +185,15 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::MacroDef( _, MacroDef { - eii_macro_for: Some(EIIMacroFor { extern_item_path, impl_unsafe }), .. + eii_macro_for: Some(EIIMacroFor { extern_item_path, impl_unsafe, span }), + .. }, ) => { - vec![hir::Attribute::Parsed(AttributeKind::EiiMacroFor { + vec![hir::Attribute::Parsed(AttributeKind::EiiMacroFor(EIIDecl { eii_extern_item: self.lower_path_simple_eii(id, extern_item_path), impl_unsafe: *impl_unsafe, - })] + span: self.lower_span(*span), + }))] } ItemKind::ExternCrate(..) | ItemKind::Use(..) diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index e2e3135a41f26..8445988373873 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -675,8 +675,6 @@ impl<'a> State<'a> { func; self.print_define_opaques(define_opaque.as_deref()); - let body_cb_ib = body.as_ref().map(|body| (body, self.head(""))); - for EIIImpl { eii_macro_path, impl_safety, .. } in eii_impl { self.word("#["); if let Safety::Unsafe(..) = impl_safety { @@ -691,9 +689,8 @@ impl<'a> State<'a> { self.hardbreak(); } - if body.is_some() { - self.head(""); - } + let body_cb_ib = body.as_ref().map(|body| (body, self.head(""))); + self.print_visibility(vis); self.print_defaultness(*defaultness); self.print_fn(&sig.decl, sig.header, Some(*ident), generics); diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index aaaa16140f8cd..ced25f307e0bd 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -139,7 +139,7 @@ impl Deprecation { } } -#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] +#[derive(Copy, Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] pub struct EIIImpl { pub eii_macro: DefId, pub impl_marked_unsafe: bool, @@ -148,6 +148,14 @@ pub struct EIIImpl { pub is_default: bool, } +#[derive(Copy, Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] +pub struct EIIDecl { + pub eii_extern_item: DefId, + /// whether or not it is unsafe to implement this EII + pub impl_unsafe: bool, + pub span: Span, +} + /// Represent parsed, *built in*, inert attributes. /// /// That means attributes that are not actually ever expanded. @@ -200,11 +208,8 @@ pub enum AttributeKind { comment: Symbol, }, EiiImpl(ThinVec), - EiiMacroFor { - eii_extern_item: DefId, - /// whether or not it is unsafe to implement this EII - impl_unsafe: bool, - }, + EiiMacroFor(EIIDecl), + EiiMangleExtern, MacroTransparency(Transparency), Repr(ThinVec<(ReprAttr, Span)>), Stability { diff --git a/compiler/rustc_attr_parsing/src/attributes/eii.rs b/compiler/rustc_attr_parsing/src/attributes/eii.rs new file mode 100644 index 0000000000000..3e81d9f5de8d4 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/eii.rs @@ -0,0 +1,17 @@ +use rustc_attr_data_structures::AttributeKind; +use rustc_span::{Span, Symbol, sym}; + +use super::{AcceptContext, SingleAttributeParser}; +use crate::parser::ArgParser; + +pub(crate) struct EiiMangleExternParser; + +impl SingleAttributeParser for EiiMangleExternParser { + const PATH: &'static [Symbol] = &[sym::eii_mangle_extern]; + + fn on_duplicate(_cx: &AcceptContext<'_>, _first_span: Span) {} + fn convert(_cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option { + assert!(args.no_args()); + Some(AttributeKind::EiiMangleExtern) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 6ecd6b4d7dbb7..970a1e40c2515 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -27,6 +27,7 @@ pub(crate) mod allow_unstable; pub(crate) mod cfg; pub(crate) mod confusables; pub(crate) mod deprecation; +pub(crate) mod eii; pub(crate) mod repr; pub(crate) mod stability; pub(crate) mod transparency; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index eee655e422e02..fd990a02c7fe1 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -14,6 +14,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; +use crate::attributes::eii::EiiMangleExternParser; use crate::attributes::repr::ReprParser; use crate::attributes::stability::{ BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, @@ -76,7 +77,7 @@ attribute_groups!( // tidy-alphabetical-start Single, Single, - Single, + Single, Single, // tidy-alphabetical-end ]; diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index 91c3d12b5f32c..4efecdc6eb808 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -63,8 +63,14 @@ fn eii_( let item = item.into_inner(); - let ast::Item { attrs, id: _, span: item_span, vis, kind: ItemKind::Fn(mut func), tokens: _ } = - item + let ast::Item { + mut attrs, + id: _, + span: item_span, + vis, + kind: ItemKind::Fn(mut func), + tokens: _, + } = item else { ecx.dcx() .emit_err(EIIMacroExpectedFunction { span, name: path_to_string(&meta_item.path) }); @@ -105,8 +111,8 @@ fn eii_( id: ast::DUMMY_NODE_ID, span, vis: ast::Visibility { span, kind: ast::VisibilityKind::Inherited, tokens: None }, - ident: Ident { name: kw::Underscore, span }, kind: ast::ItemKind::Const(Box::new(ast::ConstItem { + ident: Ident { name: kw::Underscore, span }, defaultness: ast::Defaultness::Final, generics: ast::Generics::default(), ty: P(ast::Ty { @@ -130,7 +136,6 @@ fn eii_( kind: ast::VisibilityKind::Inherited, tokens: None }, - ident: item_name, kind: ItemKind::Fn(default_func), tokens: None, })), @@ -140,7 +145,6 @@ fn eii_( rules: ast::BlockCheckMode::Default, span, tokens: None, - could_be_bare_literal: false, }), None, ), @@ -148,6 +152,7 @@ fn eii_( attrs: ThinVec::new(), tokens: None, })), + define_opaque: None, })), tokens: None, }))) @@ -179,6 +184,21 @@ fn eii_( } // extern "…" { safe fn item(); } + // #[eii_mangle_extern] + attrs.push(ast::Attribute { + kind: ast::AttrKind::Normal(P(ast::NormalAttr { + item: ast::AttrItem { + unsafety: ast::Safety::Default, + path: ast::Path::from_ident(Ident::new(sym::eii_mangle_extern, span)), + args: ast::AttrArgs::Empty, + tokens: None, + }, + tokens: None, + })), + id: ecx.sess.psess.attr_id_generator.mk_attr_id(), + style: ast::AttrStyle::Outer, + span, + }); let extern_block = Annotatable::Item(P(ast::Item { attrs: ast::AttrVec::default(), id: ast::DUMMY_NODE_ID, @@ -258,6 +278,7 @@ fn eii_( eii_macro_for: Some(ast::EIIMacroFor { extern_item_path: ast::Path::from_ident(func.ident), impl_unsafe, + span: decl_span, }), }, ), @@ -317,7 +338,7 @@ pub(crate) fn eii_macro_for( false }; - d.eii_macro_for = Some(EIIMacroFor { extern_item_path, impl_unsafe }); + d.eii_macro_for = Some(EIIMacroFor { extern_item_path, impl_unsafe, span }); // Return the original item and the new methods. vec![item] diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 159c17b0af757..272dd1d4fcc44 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1988,6 +1988,7 @@ fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor /// used in any sections, so the linker will therefore pick relevant rlibs for linking, but /// unused `#[no_mangle]` or `#[used]` can still be discard by GC sections. /// +// TODO: does EII solves this? /// There's a few internal crates in the standard library (aka libcore and /// libstd) which actually have a circular dependence upon one another. This /// currently arises through "weak lang items" where libcore requires things diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 06ba5b4f6a752..0eec6318aaa73 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -492,7 +492,8 @@ fn upstream_monomorphizations_provider( ExportedSymbol::AsyncDropGlue(def_id, ty) => (def_id, tcx.mk_args(&[ty.into()])), ExportedSymbol::NonGeneric(..) | ExportedSymbol::ThreadLocalShim(..) - | ExportedSymbol::NoDefId(..) => { + | ExportedSymbol::NoDefId(..) + | ExportedSymbol::Alias { .. } => { // These are no monomorphizations continue; } @@ -645,6 +646,7 @@ pub(crate) fn symbol_name_for_instance_in_crate<'tcx>( instantiating_crate, ) } + ExportedSymbol::Alias { original: _, alternative_symbol } => alternative_symbol.to_string(), ExportedSymbol::NoDefId(symbol_name) => symbol_name.to_string(), } } @@ -672,6 +674,10 @@ fn calling_convention_for_symbol<'tcx>( ExportedSymbol::NoDefId(..) => None, // ThreadLocalShim always follow the target's default symbol decoration scheme. ExportedSymbol::ThreadLocalShim(..) => None, + // Aliases have the same calling convention as the thing they alias. + ExportedSymbol::Alias { original, alternative_symbol: _ } => { + Some(Instance::mono(tcx, original)) + } }; instance diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 8c2efb01c4a4f..967a1305c90e2 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -51,7 +51,7 @@ fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage { } } -fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { +fn codegen_fn_attrs<'tcx>(tcx: TyCtxt<'tcx>, did: LocalDefId) -> CodegenFnAttrs { if cfg!(debug_assertions) { let def_kind = tcx.def_kind(did); assert!( @@ -112,17 +112,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if let hir::Attribute::Parsed(p) = attr { match p { - /* - AttributeKind::EiiImpl(eii_macro) => { - let Some(eii_extern_item) = find_attr!( - tcx.get_all_attrs(eii_macro), - AttributeKind::EiiMacroFor { eii_extern_item, .. } => *eii_extern_item - ) else { - tcx.dcx().span_delayed_bug(attr.span(), "missing attr on EII macro"); - continue; - }; - let _ = eii_extern_item; // XXX mangle as this item or something. - }*/ + AttributeKind::EiiMangleExtern => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::EII_MANGLE_EXTERN; + } AttributeKind::Repr(reprs) => { codegen_fn_attrs.alignment = reprs .iter() @@ -765,8 +757,8 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Option { } } -fn check_link_name_xor_ordinal( - tcx: TyCtxt<'_>, +fn check_link_name_xor_ordinal<'tcx>( + tcx: TyCtxt<'tcx>, codegen_fn_attrs: &CodegenFnAttrs, inline_span: Option, ) { diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 216800717fdaa..a58e1241a054d 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -572,6 +572,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { | ty::InstanceKind::AsyncDropGlueCtorShim(..) | ty::InstanceKind::AsyncDropGlue(..) | ty::InstanceKind::FutureDropPollShim(..) + | ty::InstanceKind::EiiShim { .. } | ty::InstanceKind::Item(_) => { // We need MIR for this fn. // Note that this can be an intrinsic, if we are executing its fallback body. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index c117e0fcf7ccc..30aa39024b264 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1072,6 +1072,11 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_force_inline, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, EncodeCrossCrate::Yes, "#[rustc_force_inline] forces a free function to be inlined" ), + gated!( + // Used in resolve: + eii_mangle_extern, Normal, template!(Word), ErrorFollowing, + EncodeCrossCrate::Yes, eii_internals, "`#[eii_mangle_extern]` is for use by rustc only", + ), // ========================================================================== // Internal attributes, Testing: diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 507c94aca8b9a..77a522814f882 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -448,7 +448,7 @@ pub enum Res { // FIXME(generic_const_exprs): Remove this bodge once that feature is stable. forbid_generic: bool, - /// Is this within an `impl Foo for bar`? + /// Is this within an `impl Foo for bar`?: is_trait_impl: bool, }, diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index 7ca08fc29afc8..bd782be641fb5 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -5,12 +5,10 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{Applicability, E0050, E0053, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, FnSig, HirId, ItemKind}; -use rustc_infer::infer::canonical::ir::TypingMode; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; -use rustc_middle::ty; -use rustc_middle::ty::TyCtxt; use rustc_middle::ty::error::{ExpectedFound, TypeError}; +use rustc_middle::ty::{self, TyCtxt, TypingMode}; use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::regions::InferCtxtRegionExt; diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 7080aef226739..b384603680a64 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -3,7 +3,7 @@ use std::ops::{ControlFlow, Deref}; use hir::intravisit::{self, Visitor}; use rustc_abi::ExternAbi; -use rustc_attr_parsing::{AttributeKind, EIIImpl, find_attr}; +use rustc_attr_parsing::{AttributeKind, EIIDecl, EIIImpl, find_attr}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; @@ -1331,7 +1331,7 @@ fn check_item_fn( { // we expect this macro to have the `EiiMacroFor` attribute, that points to a function // signature that we'd like to compare the function we're currently checking with - if let Some(eii_extern_item) = find_attr!(tcx.get_all_attrs(*eii_macro), AttributeKind::EiiMacroFor {eii_extern_item, ..} => *eii_extern_item) + if let Some(eii_extern_item) = find_attr!(tcx.get_all_attrs(*eii_macro), AttributeKind::EiiMacroFor(EIIDecl {eii_extern_item, ..}) => *eii_extern_item) { let _ = compare_eii_function_types( tcx, diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index f4d11a7c0be2d..4993b923b2919 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -946,6 +946,9 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { parallel!( { sess.time("looking_for_entry_point", || tcx.ensure_ok().entry_fn(())); + sess.time("check_externally_implementable_items", || { + tcx.ensure_ok().get_externally_implementable_item_impls(()) + }); sess.time("looking_for_derive_registrar", || { tcx.ensure_ok().proc_macro_decls_static(()) diff --git a/compiler/rustc_metadata/src/eii.rs b/compiler/rustc_metadata/src/eii.rs new file mode 100644 index 0000000000000..e25415e2d5d48 --- /dev/null +++ b/compiler/rustc_metadata/src/eii.rs @@ -0,0 +1,40 @@ +use rustc_attr_parsing::{AttributeKind, EIIDecl, EIIImpl, find_attr}; +use rustc_data_structures::fx::FxIndexMap; +use rustc_hir::def_id::DefId; +use rustc_middle::query::LocalCrate; +use rustc_middle::ty::TyCtxt; + +type EIIMap = FxIndexMap< + DefId, // the defid of the macro that declared the eii + ( + EIIDecl, // the corresponding declaration + FxIndexMap, // all the given implementations, indexed by defid. + // We expect there to be only one, but collect them all to give errors if there are more + // (or if there are none) in the final crate we build. + ), +>; + +pub(crate) fn collect<'tcx>(tcx: TyCtxt<'tcx>, LocalCrate: LocalCrate) -> EIIMap { + let mut eiis = EIIMap::default(); + + // now we've seen all EIIs declared and maybe even implemented in dependencies. Let's look at + // the current crate! + for id in tcx.hir_crate_items(()).definitions() { + for i in + find_attr!(tcx.get_all_attrs(id), AttributeKind::EiiImpl(e) => e).into_iter().flatten() + { + eiis.entry(i.eii_macro) + .or_insert_with(|| { + // 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) + (find_attr!(tcx.get_all_attrs(i.eii_macro), AttributeKind::EiiMacroFor(d) => *d).unwrap(), Default::default()) + }).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.get_all_attrs(id), AttributeKind::EiiMacroFor(d) => *d) { + eiis.entry(id.into()).or_insert((decl, Default::default())); + } + } + + eiis +} diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 3931be1654a35..aa0acb5568e0b 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -22,6 +22,7 @@ extern crate proc_macro; pub use rmeta::provide; mod dependency_format; +mod eii; mod foreign_modules; mod native_libs; mod rmeta; diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index eb7d8bba2dfe2..432599cc88aba 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1473,6 +1473,13 @@ impl<'a> CrateMetadataRef<'a> { self.root.foreign_modules.decode((self, sess)) } + fn get_externally_implementable_items( + self, + sess: &'a Session, + ) -> impl Iterator))> { + self.root.externally_implementable_items.decode((self, sess)) + } + fn get_dylib_dependency_formats<'tcx>( self, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 76bae39ef8c00..4aadc3e2df6f4 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -24,7 +24,7 @@ use super::{Decodable, DecodeContext, DecodeIterator}; use crate::creader::{CStore, LoadedMacro}; use crate::rmeta::AttrFlags; use crate::rmeta::table::IsDefault; -use crate::{foreign_modules, native_libs}; +use crate::{eii, foreign_modules, native_libs}; trait ProcessQueryValue<'tcx, T> { fn process_decoded(self, _tcx: TyCtxt<'tcx>, _err: impl Fn() -> !) -> T; @@ -373,6 +373,13 @@ provide! { tcx, def_id, other, cdata, } native_libraries => { cdata.get_native_libraries(tcx.sess).collect() } foreign_modules => { cdata.get_foreign_modules(tcx.sess).map(|m| (m.def_id, m)).collect() } + externally_implementable_items => { + cdata.get_externally_implementable_items(tcx.sess) + .map(|(decl_did, (decl, impls))| ( + decl_did, + (decl, impls.into_iter().collect()) + )).collect() + } crate_hash => { cdata.root.header.hash } crate_host_hash => { cdata.host_hash } crate_name => { cdata.root.header.name } @@ -450,6 +457,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { }, native_libraries: native_libs::collect, foreign_modules: foreign_modules::collect, + externally_implementable_items: eii::collect, // Returns a map from a sufficiently visible external item (i.e., an // external item that is visible from at least one local module) to a diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 34e9fc7c5fb10..9ad6cf1d9ac0a 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -604,6 +604,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // We have already encoded some things. Get their combined size from the current position. stats.push(("preamble", self.position())); + let externally_implementable_items = stat!("externally-implementable-items", || self + .encode_externally_implementable_items()); + let (crate_deps, dylib_dependency_formats) = stat!("dep", || (self.encode_crate_deps(), self.encode_dylib_dependency_formats())); @@ -714,6 +717,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE), has_alloc_error_handler: tcx.has_alloc_error_handler(LOCAL_CRATE), has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE), + externally_implementable_items, + has_default_lib_allocator: ast::attr::contains_name( attrs, sym::default_lib_allocator, @@ -1870,6 +1875,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy_array(foreign_modules.iter().map(|(_, m)| m).cloned()) } + fn encode_externally_implementable_items( + &mut self, + ) -> LazyArray<(DefId, (EIIDecl, Vec<(DefId, EIIImpl)>))> { + empty_proc_macro!(self); + let externally_implementable_items = self.tcx.externally_implementable_items(LOCAL_CRATE); + + self.lazy_array(externally_implementable_items.iter().map(|(decl_did, (decl, impls))| { + (*decl_did, (decl.clone(), impls.iter().map(|(impl_did, i)| (*impl_did, *i)).collect())) + })) + } + fn encode_hygiene(&mut self) -> (SyntaxContextTable, ExpnDataTable, ExpnHashTable) { let mut syntax_contexts: TableBuilder<_, _> = Default::default(); let mut expn_data_table: TableBuilder<_, _> = Default::default(); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index c86cf567283fe..8a26b9911965f 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -8,6 +8,7 @@ use encoder::EncodeContext; pub use encoder::{EncodedMetadata, encode_metadata, rendered_const}; use rustc_abi::{FieldIdx, ReprOptions, VariantIdx}; use rustc_ast::expand::StrippedCfgItem; +use rustc_attr_parsing::{EIIDecl, EIIImpl}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::svh::Svh; use rustc_hir::PreciseCapturingArgKind; @@ -256,10 +257,13 @@ pub(crate) struct CrateRoot { required_panic_strategy: Option, panic_in_drop_strategy: PanicStrategy, edition: Edition, + + // TODO: these booleans can be replaced by the entries in `externally_implementable_items` has_global_allocator: bool, has_alloc_error_handler: bool, has_panic_handler: bool, has_default_lib_allocator: bool, + externally_implementable_items: LazyArray<(DefId, (EIIDecl, Vec<(DefId, EIIImpl)>))>, crate_deps: LazyArray, dylib_dependency_formats: LazyArray>, diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index a0f4597408939..4774c31d0c376 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -118,6 +118,7 @@ macro_rules! arena_types { [decode] specialization_graph: rustc_middle::traits::specialization_graph::Graph, [] crate_inherent_impls: rustc_middle::ty::CrateInherentImpls, [] hir_owner_nodes: rustc_hir::OwnerNodes<'tcx>, + [] get_externally_implementable_item_impls: rustc_data_structures::fx::FxIndexMap, ]); ) } diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 00da1a6aeec7d..f60d72b99a69f 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -108,6 +108,7 @@ bitflags::bitflags! { /// `#[no_mangle]`: an indicator that the function's name should be the same /// as its symbol. const NO_MANGLE = 1 << 5; + // TODO: EIIs can replace this, most likely /// `#[rustc_std_internal_symbol]`: an indicator that this symbol is a /// "weird symbol" for the standard library in that it has slightly /// different linkage, visibility, and reachability rules. @@ -139,12 +140,15 @@ bitflags::bitflags! { const ALLOCATOR_ZEROED = 1 << 18; /// `#[no_builtins]`: indicates that disable implicit builtin knowledge of functions for the function. const NO_BUILTINS = 1 << 19; + /// Usually items in extern blocks aren't mangled, but for EII this is exactly what we want + /// This signals that. + const EII_MANGLE_EXTERN = 1 << 20; } } rustc_data_structures::external_bitflags_debug! { CodegenFnAttrFlags } -impl CodegenFnAttrs { - pub const EMPTY: &'static Self = &Self::new(); +impl<'tcx> CodegenFnAttrs { + pub const EMPTY: &'tcx Self = &Self::new(); pub const fn new() -> CodegenFnAttrs { CodegenFnAttrs { diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index 64a1f2aff15c5..d8be6a56d1536 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -47,6 +47,7 @@ pub enum ExportedSymbol<'tcx> { AsyncDropGlue(DefId, Ty<'tcx>), ThreadLocalShim(DefId), NoDefId(ty::SymbolName<'tcx>), + Alias { original: DefId, alternative_symbol: ty::SymbolName<'tcx> }, } impl<'tcx> ExportedSymbol<'tcx> { @@ -72,6 +73,7 @@ impl<'tcx> ExportedSymbol<'tcx> { args: ty::GenericArgs::empty(), }), ExportedSymbol::NoDefId(symbol_name) => symbol_name, + ExportedSymbol::Alias { original: _, alternative_symbol } => alternative_symbol, } } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index adc100941a39a..ba734a2e7d108 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1700,7 +1700,7 @@ mod size_asserts { // tidy-alphabetical-start static_assert_size!(BasicBlockData<'_>, 128); static_assert_size!(LocalDecl<'_>, 40); - static_assert_size!(SourceScopeData<'_>, 64); + static_assert_size!(SourceScopeData<'_>, 72); static_assert_size!(Statement<'_>, 32); static_assert_size!(Terminator<'_>, 96); static_assert_size!(VarDebugInfo<'_>, 88); diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 7243f87ee6380..399f265707921 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -181,6 +181,12 @@ impl<'tcx> MonoItem<'tcx> { return opt_incr_drop_glue_mode(tcx, ty); } + // eii shims are only generated in the final crate. + // As such, they will be both globally shared and unique. + if let InstanceKind::EiiShim { .. } = instance.def { + return InstantiationMode::GloballyShared { may_conflict: false }; + } + // We need to ensure that we do not decide the InstantiationMode of an exported symbol is // LocalCopy. Since exported symbols are computed based on the output of // cross_crate_inlinable, we are beholden to our previous decisions. @@ -532,7 +538,8 @@ impl<'tcx> CodegenUnit<'tcx> { | InstanceKind::FnPtrAddrShim(..) | InstanceKind::AsyncDropGlue(..) | InstanceKind::FutureDropPollShim(..) - | InstanceKind::AsyncDropGlueCtorShim(..) => None, + | InstanceKind::AsyncDropGlueCtorShim(..) + | InstanceKind::EiiShim { .. } => None, } } MonoItem::Static(def_id) => def_id.as_local().map(Idx::index), diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 1777756174bf9..e0af97acb7468 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -353,7 +353,8 @@ macro_rules! make_mir_visitor { coroutine_closure_def_id: _def_id, receiver_by_ref: _, } - | ty::InstanceKind::DropGlue(_def_id, None) => {} + | ty::InstanceKind::DropGlue(_def_id, None) + | ty::InstanceKind::EiiShim { def_id: _def_id, extern_item: _, chosen_impl: _ } => {} ty::InstanceKind::FnPtrShim(_def_id, ty) | ty::InstanceKind::DropGlue(_def_id, Some(ty)) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b2133fea08cc3..fae0c1cfddc03 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -14,6 +14,7 @@ use std::sync::Arc; use rustc_arena::TypedArena; use rustc_ast::expand::StrippedCfgItem; use rustc_ast::expand::allocator::AllocatorKind; +use rustc_attr_data_structures::{EIIDecl, EIIImpl}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; @@ -1113,6 +1114,10 @@ rustc_queries! { desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) } } + query get_externally_implementable_item_impls(_: ()) -> &'tcx rustc_data_structures::fx::FxIndexMap { + desc { "check externally implementable items" } + } + query check_mod_naked_functions(key: LocalModDefId) { desc { |tcx| "checking naked functions in {}", describe_as_module(key, tcx) } } @@ -1907,6 +1912,13 @@ rustc_queries! { separate_provide_extern } + /// Returns a list of all `externally implementable items` crate. + query externally_implementable_items(_: CrateNum) -> &'tcx FxIndexMap)> { + arena_cache + desc { "looking up the externally implementable items of a crate" } + separate_provide_extern + } + /// Lint against `extern fn` declarations having incompatible types. query clashing_extern_declarations(_: ()) { desc { "checking `extern fn` declarations are compatible" } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 0d99a1b51499a..f9664d396fe79 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -183,6 +183,11 @@ pub enum InstanceKind<'tcx> { /// async_drop_in_place poll function implementation (for generated coroutine). /// `Ty` here is `async_drop_in_place::{closure}` coroutine type, not just `T` AsyncDropGlue(DefId, Ty<'tcx>), + + /// Generated by externally implementable items. This function adds indirection so we can choose + /// in the final crate whether to call an explicit implementation or, if none are given, call the + /// default. + EiiShim { def_id: DefId, extern_item: DefId, chosen_impl: DefId }, } impl<'tcx> Instance<'tcx> { @@ -261,7 +266,8 @@ impl<'tcx> InstanceKind<'tcx> { | InstanceKind::FnPtrAddrShim(def_id, _) | InstanceKind::FutureDropPollShim(def_id, _, _) | InstanceKind::AsyncDropGlue(def_id, _) - | InstanceKind::AsyncDropGlueCtorShim(def_id, _) => def_id, + | InstanceKind::AsyncDropGlueCtorShim(def_id, _) + | InstanceKind::EiiShim { def_id, .. } => def_id, } } @@ -283,7 +289,8 @@ impl<'tcx> InstanceKind<'tcx> { | ty::InstanceKind::ConstructCoroutineInClosureShim { .. } | InstanceKind::DropGlue(..) | InstanceKind::CloneShim(..) - | InstanceKind::FnPtrAddrShim(..) => None, + | InstanceKind::FnPtrAddrShim(..) + | InstanceKind::EiiShim { .. } => None, } } @@ -342,8 +349,9 @@ impl<'tcx> InstanceKind<'tcx> { | InstanceKind::FnPtrShim(..) | InstanceKind::DropGlue(_, Some(_)) | InstanceKind::FutureDropPollShim(..) - | InstanceKind::AsyncDropGlue(_, _) => false, - InstanceKind::AsyncDropGlueCtorShim(_, _) => false, + | InstanceKind::AsyncDropGlue(_, _) + | InstanceKind::AsyncDropGlueCtorShim(_, _) + | InstanceKind::EiiShim { .. } => false, InstanceKind::ClosureOnceShim { .. } | InstanceKind::ConstructCoroutineInClosureShim { .. } | InstanceKind::DropGlue(..) @@ -428,6 +436,9 @@ pub fn fmt_instance( } InstanceKind::AsyncDropGlue(_, ty) => write!(f, " - shim({ty})"), InstanceKind::AsyncDropGlueCtorShim(_, ty) => write!(f, " - shim(Some({ty}))"), + InstanceKind::EiiShim { def_id: _, extern_item, chosen_impl } => { + write!(f, " - shim(eii: {extern_item:?} -> {chosen_impl:?})") + } } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 2d69a1c2b553e..bbc8892c28236 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1731,23 +1731,25 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns the possibly-auto-generated MIR of a [`ty::InstanceKind`]. #[instrument(skip(self), level = "debug")] pub fn instance_mir(self, instance: ty::InstanceKind<'tcx>) -> &'tcx Body<'tcx> { - match instance { - ty::InstanceKind::Item(def) => { - debug!("calling def_kind on def: {:?}", def); - let def_kind = self.def_kind(def); - debug!("returned from def_kind: {:?}", def_kind); - match def_kind { - DefKind::Const - | DefKind::Static { .. } - | DefKind::AssocConst - | DefKind::Ctor(..) - | DefKind::AnonConst - | DefKind::InlineConst => self.mir_for_ctfe(def), - // If the caller wants `mir_for_ctfe` of a function they should not be using - // `instance_mir`, so we'll assume const fn also wants the optimized version. - _ => self.optimized_mir(def), - } + let item_mir = |def| { + debug!("calling def_kind on def: {:?}", def); + let def_kind = self.def_kind(def); + debug!("returned from def_kind: {:?}", def_kind); + match def_kind { + DefKind::Const + | DefKind::Static { .. } + | DefKind::AssocConst + | DefKind::Ctor(..) + | DefKind::AnonConst + | DefKind::InlineConst => self.mir_for_ctfe(def), + // If the caller wants `mir_for_ctfe` of a function they should not be using + // `instance_mir`, so we'll assume const fn also wants the optimized version. + _ => self.optimized_mir(def), } + }; + + match instance { + ty::InstanceKind::Item(def) => item_mir(def), ty::InstanceKind::VTableShim(..) | ty::InstanceKind::ReifyShim(..) | ty::InstanceKind::Intrinsic(..) @@ -1761,7 +1763,8 @@ impl<'tcx> TyCtxt<'tcx> { | ty::InstanceKind::ThreadLocalShim(..) | ty::InstanceKind::FnPtrAddrShim(..) | ty::InstanceKind::AsyncDropGlueCtorShim(..) - | ty::InstanceKind::AsyncDropGlue(..) => self.mir_shims(instance), + | ty::InstanceKind::AsyncDropGlue(..) + | ty::InstanceKind::EiiShim { .. } => self.mir_shims(instance), } } diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index ecd6132b3ef35..d55d057c6d32f 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -27,6 +27,10 @@ impl ParameterizedOverTcx for IndexVe type Value<'tcx> = IndexVec>; } +impl ParameterizedOverTcx for Vec { + type Value<'tcx> = Vec>; +} + impl ParameterizedOverTcx for UnordMap { type Value<'tcx> = UnordMap>; } @@ -87,6 +91,8 @@ trivially_parameterized_over_tcx! { rustc_attr_data_structures::DefaultBodyStability, rustc_attr_data_structures::Deprecation, rustc_attr_data_structures::Stability, + rustc_attr_data_structures::EIIDecl, + rustc_attr_data_structures::EIIImpl, rustc_hir::Constness, rustc_hir::Defaultness, rustc_hir::Safety, diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 9785c039d539b..ea7d5a0fd4afe 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -761,7 +761,8 @@ fn check_mir_is_available<'tcx, I: Inliner<'tcx>>( | InstanceKind::DropGlue(..) | InstanceKind::CloneShim(..) | InstanceKind::ThreadLocalShim(..) - | InstanceKind::FnPtrAddrShim(..) => return Ok(()), + | InstanceKind::FnPtrAddrShim(..) + | InstanceKind::EiiShim { .. } => return Ok(()), } if inliner.tcx().is_constructor(callee_def_id) { diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 292278800f8a2..ff87e891230f8 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -90,6 +90,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( | InstanceKind::ConstructCoroutineInClosureShim { .. } | InstanceKind::ThreadLocalShim { .. } | InstanceKind::CloneShim(..) => {} + InstanceKind::EiiShim { .. } => {} // This shim does not call any other functions, thus there can be no recursion. InstanceKind::FnPtrAddrShim(..) => { diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 9688ac8ed2e27..cdb429c8306d7 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -114,6 +114,57 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body< receiver_by_ref, } => build_construct_coroutine_by_move_shim(tcx, coroutine_closure_def_id, receiver_by_ref), + e @ ty::InstanceKind::EiiShim { def_id: _, extern_item: _, chosen_impl } => { + let source = MirSource::from_instance(e); + + let fn_sig = tcx.fn_sig(chosen_impl).instantiate_identity().skip_binder(); + let func_ty = Ty::new_fn_def(tcx, chosen_impl, GenericArgs::empty()); + + let span = tcx.def_span(chosen_impl); + let source_info = SourceInfo::outermost(span); + + let func = Operand::Constant(Box::new(ConstOperand { + span, + user_ty: None, + const_: Const::zero_sized(func_ty), + })); + + let locals = local_decls_for_sig(&fn_sig, span); + let mut blocks = IndexVec::new(); + + let return_block = BasicBlock::new(1); + blocks.push(BasicBlockData { + statements: vec![], + terminator: Some(Terminator { + source_info, + kind: TerminatorKind::Call { + func, + args: locals + .iter_enumerated() + .map(|i| i.0) + .skip(1) + .map(|local| Spanned { node: Operand::Move(Place::from(local)), span }) + .collect::>() + .into_boxed_slice(), + fn_span: span, + destination: Place::return_place(), + target: Some(return_block), + unwind: UnwindAction::Continue, + call_source: CallSource::Misc, + }, + }), + is_cleanup: false, + }); + + blocks.push(BasicBlockData { + statements: vec![], + terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }), + is_cleanup: false, + }); + + new_body(source, blocks, locals, fn_sig.inputs().len(), span) + } + ty::InstanceKind::DropGlue(def_id, ty) => { // FIXME(#91576): Drop shims for coroutines aren't subject to the MIR passes at the end // of this function. Is this intentional? diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index c6a81e60b2b52..620d268de6f49 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -208,7 +208,7 @@ use std::cell::OnceCell; use std::path::PathBuf; -use rustc_attr_parsing::InlineAttr; +use rustc_attr_parsing::{AttributeKind, EIIDecl, InlineAttr, find_attr}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::{MTLock, par_for_each_in}; use rustc_data_structures::unord::{UnordMap, UnordSet}; @@ -964,7 +964,8 @@ fn visit_instance_use<'tcx>( | ty::InstanceKind::Item(..) | ty::InstanceKind::FnPtrShim(..) | ty::InstanceKind::CloneShim(..) - | ty::InstanceKind::FnPtrAddrShim(..) => { + | ty::InstanceKind::FnPtrAddrShim(..) + | ty::InstanceKind::EiiShim { .. } => { output.push(create_fn_mono_item(tcx, instance, source)); } } @@ -1406,6 +1407,7 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionStrategy) -> Vec RootCollector<'_, 'v> { !matches!(self.tcx.codegen_fn_attrs(def_id).inline, InlineAttr::Force { .. }) } MonoItemCollectionStrategy::Lazy => { + let cfa = self.tcx.codegen_fn_attrs(def_id); + self.entry_fn.and_then(|(id, _)| id.as_local()) == Some(def_id) || self.tcx.is_reachable_non_generic(def_id) - || self - .tcx - .codegen_fn_attrs(def_id) + // TODO: EII might remove this: + || cfa .flags .contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) } @@ -1606,6 +1609,33 @@ impl<'v> RootCollector<'_, 'v> { self.output.push(create_fn_mono_item(self.tcx, start_instance, DUMMY_SP)); } + + /// For each externally implementable item, we should generate an alias MonoItem that + /// determines what implementation is called. This could be a default implementation. + fn push_extra_eii_roots(&mut self) { + for (decl, (chosen_impl, shim_did)) in self.tcx.get_externally_implementable_item_impls(()) + { + let Some((eii_extern_item, span)) = find_attr!( + self.tcx.get_all_attrs(*decl), + AttributeKind::EiiMacroFor(EIIDecl { eii_extern_item, span, .. }) => (*eii_extern_item, *span) + ) else { + bug!("missing attr on EII macro"); + }; + + self.output.push(create_fn_mono_item( + self.tcx, + ty::Instance { + def: ty::InstanceKind::EiiShim { + def_id: (*shim_did).into(), + extern_item: eii_extern_item, + chosen_impl: *chosen_impl, + }, + args: ty::GenericArgs::empty(), + }, + span, + )); + } + } } #[instrument(level = "debug", skip(tcx, output))] diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 6948dceddf904..6bf783fa7ecab 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -633,6 +633,9 @@ fn characteristic_def_id_of_mono_item<'tcx>( MonoItem::Fn(instance) => { let def_id = match instance.def { ty::InstanceKind::Item(def) => def, + // EII shims have a characteristic defid. + // But it's not their own, its the one of the extern item it is implementing. + ty::InstanceKind::EiiShim { def_id: _, extern_item, chosen_impl: _ } => extern_item, ty::InstanceKind::VTableShim(..) | ty::InstanceKind::ReifyShim(..) | ty::InstanceKind::FnPtrShim(..) @@ -802,6 +805,14 @@ fn mono_item_visibility<'tcx>( | InstanceKind::AsyncDropGlue(def_id, _) | InstanceKind::AsyncDropGlueCtorShim(def_id, _) => def_id, + InstanceKind::EiiShim { .. } => { + // Out of the three visibilities, only Default makes symbols visible outside the current + // DSO. For EIIs this is explicitly the intended visibilty. If another DSO is refering + // to an extern item, the implementation may be generated downstream. That symbol does + // have to be visible to the linker! + return Visibility::Default; + } + // We match the visibility of statics here InstanceKind::ThreadLocalShim(def_id) => { return static_visibility(tcx, can_be_internalized, def_id); @@ -920,6 +931,7 @@ fn mono_item_visibility<'tcx>( // LLVM internalize them as this decision is left up to the linker to // omit them, so prevent them from being internalized. let attrs = tcx.codegen_fn_attrs(def_id); + // TODO: EII might replace this if attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) { *can_be_internalized = false; } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 994348272b2c1..1c79802db7d81 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -278,6 +278,17 @@ passes_duplicate_diagnostic_item_in_crate = duplicate diagnostic item in crate `{$crate_name}`: `{$name}` .note = the diagnostic item is first defined in crate `{$orig_crate_name}` +passes_duplicate_eii_impls = + multiple implementations of `#[{$name}]` + .first = first implemented here in crate `{$first_crate}` + .second = also implemented here in crate `{$second_crate}` + .note = in addition to these two, { $num_additional_crates -> + [one] another implementation was found in crate {$additional_crate_names} + *[other] more implementations were also found in the following crates: {$additional_crate_names} + } + + .help = an "externally implementable item" can only have a single implementation in the final artifact. When multiple implementations are found, also in different crates, they conflict. + passes_duplicate_feature_err = the feature `{$feature}` has already been enabled @@ -317,6 +328,11 @@ passes_eii_impl_not_function = passes_eii_impl_requires_unsafe = `#[{$name}]` is unsafe to implement passes_eii_impl_requires_unsafe_suggestion = wrap the attribute in `unsafe(...)` + +passes_eii_without_impl = + couldn't find an implementation for `#[{$name}]` + .label = an implementation was expected by this declaration + .help = expected at least one implementation in crate `{$current_crate_name}` or any of its dependencies passes_export_name = attribute should be applied to a free function, impl method or static .label = not a free function, impl method or static diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 3a89e94ab43d4..5abdb68b63ff7 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -10,7 +10,7 @@ use std::collections::hash_map::Entry; use rustc_abi::{Align, ExternAbi, Size}; use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast}; -use rustc_attr_parsing::{AttributeKind, EIIImpl, ReprAttr, find_attr}; +use rustc_attr_parsing::{AttributeKind, EIIDecl, EIIImpl, ReprAttr, find_attr}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; @@ -130,6 +130,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::EiiMacroFor { .. }) => { // no checks needed } + Attribute::Parsed(AttributeKind::EiiMangleExtern { .. }) => { + // TODO: checks? + } Attribute::Parsed(AttributeKind::AllowInternalUnstable(syms)) => self .check_allow_internal_unstable( hir_id, @@ -496,7 +499,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - if find_attr!(self.tcx.get_all_attrs(*eii_macro), AttributeKind::EiiMacroFor { impl_unsafe, .. } if *impl_unsafe) + if find_attr!(self.tcx.get_all_attrs(*eii_macro), AttributeKind::EiiMacroFor(EIIDecl { impl_unsafe, .. }) if *impl_unsafe) && !impl_marked_unsafe { self.dcx().emit_err(errors::EIIImplRequiresUnsafe { diff --git a/compiler/rustc_passes/src/eii.rs b/compiler/rustc_passes/src/eii.rs new file mode 100644 index 0000000000000..55214367bd79f --- /dev/null +++ b/compiler/rustc_passes/src/eii.rs @@ -0,0 +1,135 @@ +//! Validity checking for weak lang items + +use std::iter; + +use rustc_attr_parsing::EIIImpl; +use rustc_data_structures::fx::FxIndexMap; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, LocalDefId}; +use rustc_hir::definitions::DisambiguatorState; +use rustc_middle::ty::TyCtxt; +use rustc_session::config::CrateType; +use rustc_span::Symbol; + +use crate::errors::{DuplicateEiiImpls, EiiWithoutImpl}; + +/// Checks all EIIs in the crate graph, and returns for each declaration which implementation is +/// chosen. This could be a default implementation if no explicit implementation is found. +/// +/// The returned map maps the defid of declaration macros to the defid of implementations. +pub(crate) fn get_eii_impls<'tcx>( + tcx: TyCtxt<'tcx>, + (): (), +) -> &'tcx FxIndexMap { + // We only need to check whether there are duplicate or missing EIIs if we're + // emitting something that's not an rlib. + let needs_check = tcx.crate_types().iter().any(|kind| match *kind { + CrateType::Dylib + | CrateType::ProcMacro + | CrateType::Cdylib + | CrateType::Executable + | CrateType::Staticlib + | CrateType::Sdylib => true, + CrateType::Rlib => false, + }); + if !needs_check { + // In this case we could only have called it when checking, + // and not when we were actually codegenning functions so we don't need to return any real data + return &*tcx.arena.alloc(FxIndexMap::default()); + } + + let mut eiis = FxIndexMap::<_, (_, FxIndexMap)>::default(); + + // println!("current crate: {}", tcx.crate_name(LOCAL_CRATE)); + + // collect all the EII declarations, and possibly implementations from all descendent crates + for &cnum in tcx.crates(()).iter().chain(iter::once(&LOCAL_CRATE)) { + // println!("visiting crate: {}", tcx.crate_name(cnum)); + // get the eiis for the crate we're currently looking at + let crate_eiis = tcx.externally_implementable_items(cnum); + + // update or insert the corresponding entries + for (did, (decl, impls)) in crate_eiis { + eiis.entry(did) + .or_insert_with(|| (decl, Default::default())) + .1 + .extend(impls.into_iter().map(|(did, i)| (*did, (*i, cnum)))); + } + } + + let mut final_impls = FxIndexMap::default(); + + // now we have all eiis! For each of them, choose one we want to actually generate. + + for (decl_did, (decl, impls)) in eiis { + // println!("for decl: {decl_did:?}: {decl:?}"); + let mut default_impls = Vec::new(); + let mut explicit_impls = Vec::new(); + + for (impl_did, (impl_metadata, cnum)) in impls { + if impl_metadata.is_default { + // println!("found default impl in {}", tcx.crate_name(cnum)); + default_impls.push((impl_did, cnum)); + } else { + // println!("found impl in {}", tcx.crate_name(cnum)); + explicit_impls.push((impl_did, cnum)); + } + } + + if explicit_impls.len() > 1 { + tcx.dcx().emit_err(DuplicateEiiImpls { + name: tcx.item_name(*decl_did), + first_span: tcx.def_span(explicit_impls[0].0), + first_crate: tcx.crate_name(explicit_impls[0].1), + second_span: tcx.def_span(explicit_impls[1].0), + second_crate: tcx.crate_name(explicit_impls[1].1), + + help: (), + + additional_crates: (explicit_impls.len() > 2).then_some(()), + num_additional_crates: explicit_impls.len() - 2, + additional_crate_names: explicit_impls[2..] + .iter() + .map(|i| format!("`{}`", tcx.crate_name(i.1))) + .collect::>() + .join(", "), + }); + } + + if default_impls.len() > 1 { + panic!("multiple not supported right now, but this is easily possible"); + } + + // println!("impls: {explicit_impls:?}"); + // println!("default impls: {default_impls:?}"); + + if let Some((chosen_impl, _)) = explicit_impls.first().or(default_impls.first()) { + let feed = tcx.create_def( + CRATE_DEF_ID, + Some(Symbol::intern(&format!("EII shim for {decl_did:?}"))), + DefKind::Fn, + None, + &mut DisambiguatorState::new(), + ); + feed.generics_of(tcx.generics_of(*chosen_impl).clone()); + feed.type_of(tcx.type_of(*chosen_impl).clone()); + feed.def_span(tcx.def_span(*chosen_impl)); + feed.feed_hir(); + + let shim_did = feed.def_id(); + + // println!("shim: {shim_did:?}"); + + final_impls.insert(*decl_did, (*chosen_impl, shim_did)); + } else { + tcx.dcx().emit_err(EiiWithoutImpl { + current_crate_name: tcx.crate_name(LOCAL_CRATE), + name: tcx.item_name(*decl_did), + span: decl.span, + help: (), + }); + } + } + + tcx.arena.alloc(final_impls) +} diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 49f18a25ac8d3..b95d8798e1496 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1974,6 +1974,7 @@ pub(crate) enum UnexportableItem<'a> { }, } +#[derive(Diagnostic)] #[diag(passes_eii_impl_not_function)] pub(crate) struct EIIImplNotFunction { #[primary_span] @@ -2001,3 +2002,40 @@ pub(crate) struct EIIImplRequiresUnsafeSuggestion { #[suggestion_part(code = ")")] pub right: Span, } + +#[derive(Diagnostic)] +#[diag(passes_eii_without_impl)] +pub(crate) struct EiiWithoutImpl { + #[primary_span] + #[label] + pub span: Span, + pub name: Symbol, + + pub current_crate_name: Symbol, + #[help] + pub help: (), +} + +#[derive(Diagnostic)] +#[diag(passes_duplicate_eii_impls)] +pub(crate) struct DuplicateEiiImpls { + pub name: Symbol, + + #[primary_span] + #[label(passes_first)] + pub first_span: Span, + pub first_crate: Symbol, + + #[label(passes_second)] + pub second_span: Span, + pub second_crate: Symbol, + + #[note] + pub additional_crates: Option<()>, + + pub num_additional_crates: usize, + pub additional_crate_names: String, + + #[help] + pub help: (), +} diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 001725e28827d..58383005de1b4 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -23,6 +23,7 @@ mod check_export; pub mod dead; mod debugger_visualizer; mod diagnostic_items; +mod eii; pub mod entry; mod errors; #[cfg(debug_assertions)] @@ -56,4 +57,5 @@ pub fn provide(providers: &mut Providers) { stability::provide(providers); upvars::provide(providers); check_export::provide(providers); + providers.get_externally_implementable_item_impls = eii::get_eii_impls; } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 554568acd8273..e338780e6885e 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -23,6 +23,7 @@ //! considering here as at that point, everything is monomorphic. use hir::def_id::LocalDefIdSet; +use rustc_attr_parsing::{AttributeKind, find_attr}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::Node; @@ -184,7 +185,14 @@ impl<'tcx> ReachableContext<'tcx> { CodegenFnAttrs::EMPTY }; let is_extern = codegen_attrs.contains_extern_indicator(); - if is_extern { + + // Keep all implementation bodies for EIIs. Sometimes we can only decide in the final + // crate whether we do or don't need to codegen them so it'd be a shame if they got + // filtered out here already. + let eii_impl = + find_attr!(self.tcx.get_all_attrs(search_item), AttributeKind::EiiImpl(_)); + + if is_extern || eii_impl { self.reachable_symbols.insert(search_item); } } else { @@ -488,6 +496,15 @@ fn reachable_set(tcx: TyCtxt<'_>, (): ()) -> LocalDefIdSet { reachable_context.worklist.push(id.owner_id.def_id); } } + + // TODO: make a query for getting EIIs, this is probably expensive while we can do easily + // add the (relatively few) EIIs to a separate list and make a query for them in another pass somewhere + for id in crate_items.definitions() { + // if something implements an EII, it's automatically reachable + if find_attr!(tcx.get_all_attrs(id), AttributeKind::EiiImpl(..)) { + reachable_context.worklist.push(id); + } + } } // Step 2: Mark all symbols that the symbols on the worklist touch. diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 7873d367c51f3..ab2982103e9d5 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2850,7 +2850,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.parent_scope.macro_rules = self.r.macro_rules_scopes[&def_id]; } - if let Some(EIIMacroFor { extern_item_path, impl_unsafe: _ }) = + if let Some(EIIMacroFor { extern_item_path, impl_unsafe: _, span: _ }) = ¯o_def.eii_macro_for { self.smart_resolve_path( diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 8bcac4c4678e4..62e5485cde37f 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -816,6 +816,7 @@ impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> { | ty::InstanceKind::FnPtrShim(..) | ty::InstanceKind::FutureDropPollShim(..) | ty::InstanceKind::AsyncDropGlue(..) + | ty::InstanceKind::EiiShim { .. } | ty::InstanceKind::AsyncDropGlueCtorShim(..) => { stable_mir::mir::mono::InstanceKind::Shim } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 247ebc219fd3a..068d737b6ec3a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -880,6 +880,7 @@ symbols! { eii_internals, eii_macro, eii_macro_for, + eii_mangle_extern, emit, emit_enum, emit_enum_variant, diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index a51d7da878a29..0b695e7efa986 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -240,6 +240,7 @@ fn compute_symbol_name<'tcx>( if tcx.is_foreign_item(def_id) && (!tcx.sess.target.is_like_wasm || !tcx.wasm_import_module_map(def_id.krate).contains_key(&def_id)) + && !attrs.flags.contains(CodegenFnAttrFlags::EII_MANGLE_EXTERN) { if let Some(name) = attrs.link_name { return name.to_string(); @@ -257,6 +258,18 @@ fn compute_symbol_name<'tcx>( return tcx.item_name(def_id).to_string(); } + // if this is an EII shim, it has a kind of fake defid. It has one because it has to have one, + // but when we generate a symbol for it the name must actually match the name of the extern + // generated as part of the declaration of the EII. So, we use an instance of `extern_item` as + // the instance used for ocmputing the symbol name. + let instance = if let ty::InstanceKind::EiiShim { def_id: _, extern_item, chosen_impl: _ } = + instance.def + { + Instance::mono(tcx, extern_item) + } else { + instance + }; + // If we're dealing with an instance of a function that's inlined from // another crate but we're marking it as globally shared to our // compilation (aka we're not making an internal copy in each of our From c5e9f1229da06d17c01da82a977a18e0d55727d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 31 Mar 2025 18:06:34 +0200 Subject: [PATCH 25/41] test codegen of eii --- tests/ui/eii/auxiliary/codegen1.rs | 18 +++++++++ tests/ui/eii/auxiliary/codegen2.rs | 7 ++++ tests/ui/eii/auxiliary/codegen3.rs | 22 ++++++++++ .../auxiliary/cross_crate_eii_declaration.rs | 2 + tests/ui/eii/codegen_cross_crate.rs | 20 ++++++++++ tests/ui/eii/codegen_cross_crate.run.stdout | 2 + tests/ui/eii/codegen_single_crate.rs | 19 +++++++++ tests/ui/eii/codegen_single_crate.run.stdout | 2 + tests/ui/eii/cross_crate_wrong_ty.stderr | 2 +- .../default/auxiliary/decl_with_default.rs | 9 +++++ tests/ui/eii/default/auxiliary/impl1.rs | 12 ++++++ tests/ui/eii/default/call_default.rs | 11 +++++ tests/ui/eii/default/call_default.run.stdout | 1 + tests/ui/eii/default/call_impl.rs | 13 ++++++ tests/ui/eii/default/call_impl.run.stdout | 1 + tests/ui/eii/default/local_crate.rs | 12 ++++++ tests/ui/eii/default/local_crate.run.stdout | 1 + tests/ui/eii/default/local_crate_explicit.rs | 17 ++++++++ .../default/local_crate_explicit.run.stdout | 1 + tests/ui/eii/duplicate/auxiliary/decl.rs | 7 ++++ tests/ui/eii/duplicate/auxiliary/impl1.rs | 12 ++++++ tests/ui/eii/duplicate/auxiliary/impl2.rs | 12 ++++++ tests/ui/eii/duplicate/auxiliary/impl3.rs | 12 ++++++ tests/ui/eii/duplicate/auxiliary/impl4.rs | 12 ++++++ tests/ui/eii/duplicate/duplicate1.rs | 9 +++++ tests/ui/eii/duplicate/duplicate1.stderr | 15 +++++++ tests/ui/eii/duplicate/duplicate2.rs | 11 +++++ tests/ui/eii/duplicate/duplicate2.stderr | 16 ++++++++ tests/ui/eii/duplicate/duplicate3.rs | 13 ++++++ tests/ui/eii/duplicate/duplicate3.stderr | 16 ++++++++ tests/ui/eii/privacy1.rs | 30 ++++++++++++++ tests/ui/eii/privacy1.run.stdout | 4 ++ tests/ui/eii/privacy2.rs | 22 ++++++++++ tests/ui/eii/privacy2.stderr | 40 +++++++++++++++++++ 34 files changed, 402 insertions(+), 1 deletion(-) create mode 100644 tests/ui/eii/auxiliary/codegen1.rs create mode 100644 tests/ui/eii/auxiliary/codegen2.rs create mode 100644 tests/ui/eii/auxiliary/codegen3.rs create mode 100644 tests/ui/eii/codegen_cross_crate.rs create mode 100644 tests/ui/eii/codegen_cross_crate.run.stdout create mode 100644 tests/ui/eii/codegen_single_crate.rs create mode 100644 tests/ui/eii/codegen_single_crate.run.stdout create mode 100644 tests/ui/eii/default/auxiliary/decl_with_default.rs create mode 100644 tests/ui/eii/default/auxiliary/impl1.rs create mode 100644 tests/ui/eii/default/call_default.rs create mode 100644 tests/ui/eii/default/call_default.run.stdout create mode 100644 tests/ui/eii/default/call_impl.rs create mode 100644 tests/ui/eii/default/call_impl.run.stdout create mode 100644 tests/ui/eii/default/local_crate.rs create mode 100644 tests/ui/eii/default/local_crate.run.stdout create mode 100644 tests/ui/eii/default/local_crate_explicit.rs create mode 100644 tests/ui/eii/default/local_crate_explicit.run.stdout create mode 100644 tests/ui/eii/duplicate/auxiliary/decl.rs create mode 100644 tests/ui/eii/duplicate/auxiliary/impl1.rs create mode 100644 tests/ui/eii/duplicate/auxiliary/impl2.rs create mode 100644 tests/ui/eii/duplicate/auxiliary/impl3.rs create mode 100644 tests/ui/eii/duplicate/auxiliary/impl4.rs create mode 100644 tests/ui/eii/duplicate/duplicate1.rs create mode 100644 tests/ui/eii/duplicate/duplicate1.stderr create mode 100644 tests/ui/eii/duplicate/duplicate2.rs create mode 100644 tests/ui/eii/duplicate/duplicate2.stderr create mode 100644 tests/ui/eii/duplicate/duplicate3.rs create mode 100644 tests/ui/eii/duplicate/duplicate3.stderr create mode 100644 tests/ui/eii/privacy1.rs create mode 100644 tests/ui/eii/privacy1.run.stdout create mode 100644 tests/ui/eii/privacy2.rs create mode 100644 tests/ui/eii/privacy2.stderr diff --git a/tests/ui/eii/auxiliary/codegen1.rs b/tests/ui/eii/auxiliary/codegen1.rs new file mode 100644 index 0000000000000..93c5df2d41c02 --- /dev/null +++ b/tests/ui/eii/auxiliary/codegen1.rs @@ -0,0 +1,18 @@ +//@ no-prefer-dynamic +#![crate_type = "rlib"] +#![feature(eii)] + +#[eii(eii1)] +fn decl1(x: u64); + +mod private { + #[eii(eii2)] + pub fn decl2(x: u64); +} + +pub use private::eii2 as eii3; +pub use private::decl2 as decl3; + +pub fn local_call_decl1(x: u64) { + decl1(x) +} diff --git a/tests/ui/eii/auxiliary/codegen2.rs b/tests/ui/eii/auxiliary/codegen2.rs new file mode 100644 index 0000000000000..ef7b885b39a86 --- /dev/null +++ b/tests/ui/eii/auxiliary/codegen2.rs @@ -0,0 +1,7 @@ +//@ no-prefer-dynamic +#![crate_type = "rlib"] +#![feature(eii)] + +#[eii(eii1)] +pub fn decl1(x: u64); + diff --git a/tests/ui/eii/auxiliary/codegen3.rs b/tests/ui/eii/auxiliary/codegen3.rs new file mode 100644 index 0000000000000..5001df6e6f986 --- /dev/null +++ b/tests/ui/eii/auxiliary/codegen3.rs @@ -0,0 +1,22 @@ +//@ no-prefer-dynamic +#![crate_type = "rlib"] +#![feature(eii)] + +// does have an impl but can't be called +#[eii(eii1)] +fn decl1(x: u64); + +#[eii(eii2)] //~ ERROR couldn't find an implementation for `#[eii2]` +pub fn decl2(x: u64); + +mod private { + #[eii(eii3)] //~ ERROR couldn't find an implementation for `#[eii3]` + pub fn decl3(x: u64); +} + +pub use private::eii3 as eii4; +pub use private::decl3 as decl4; + +pub fn local_call_decl1(x: u64) { + decl1(x) +} diff --git a/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs b/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs index f077e54b52d19..36a42ad199b0f 100644 --- a/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs +++ b/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs @@ -1,3 +1,5 @@ +//@ no-prefer-dynamic +#![crate_type = "rlib"] #![feature(eii)] #![feature(decl_macro)] #![feature(rustc_attrs)] diff --git a/tests/ui/eii/codegen_cross_crate.rs b/tests/ui/eii/codegen_cross_crate.rs new file mode 100644 index 0000000000000..1d8e72b5a5c50 --- /dev/null +++ b/tests/ui/eii/codegen_cross_crate.rs @@ -0,0 +1,20 @@ +//@ run-pass +//@ check-run-results +//@ aux-build: codegen2.rs +//@ compile-flags: -O +#![feature(eii)] + +extern crate codegen2 as codegen; + +#[codegen::eii1] +fn eii1_impl(x: u64) { + println!("{x:?}") +} + +// what you would write: +fn main() { + // directly + eii1_impl(21); + // through the alias + codegen::decl1(42); +} diff --git a/tests/ui/eii/codegen_cross_crate.run.stdout b/tests/ui/eii/codegen_cross_crate.run.stdout new file mode 100644 index 0000000000000..960b546721002 --- /dev/null +++ b/tests/ui/eii/codegen_cross_crate.run.stdout @@ -0,0 +1,2 @@ +21 +42 diff --git a/tests/ui/eii/codegen_single_crate.rs b/tests/ui/eii/codegen_single_crate.rs new file mode 100644 index 0000000000000..a1710e41aa4ef --- /dev/null +++ b/tests/ui/eii/codegen_single_crate.rs @@ -0,0 +1,19 @@ +//@ run-pass +//@ check-run-results +#![feature(eii)] + +#[eii] +fn hello(x: u64); + +#[hello] +fn hello_impl(x: u64) { + println!("{x:?}") +} + +// what you would write: +fn main() { + // directly + hello_impl(21); + // through the alias + hello(42); +} diff --git a/tests/ui/eii/codegen_single_crate.run.stdout b/tests/ui/eii/codegen_single_crate.run.stdout new file mode 100644 index 0000000000000..960b546721002 --- /dev/null +++ b/tests/ui/eii/codegen_single_crate.run.stdout @@ -0,0 +1,2 @@ +21 +42 diff --git a/tests/ui/eii/cross_crate_wrong_ty.stderr b/tests/ui/eii/cross_crate_wrong_ty.stderr index 0e46ee43f7467..f53902875445e 100644 --- a/tests/ui/eii/cross_crate_wrong_ty.stderr +++ b/tests/ui/eii/cross_crate_wrong_ty.stderr @@ -6,7 +6,7 @@ LL | #[unsafe(cross_crate_eii_declaration::foo)] LL | fn other() -> u64 { | ^^^^^^^^^^^^^^^^^ expected 1 parameter, found 0 | - ::: $DIR/auxiliary/cross_crate_eii_declaration.rs:13:5 + ::: $DIR/auxiliary/cross_crate_eii_declaration.rs:15:5 | LL | pub safe fn bar(x: u64) -> u64; | ------------------------------- requires 1 parameter diff --git a/tests/ui/eii/default/auxiliary/decl_with_default.rs b/tests/ui/eii/default/auxiliary/decl_with_default.rs new file mode 100644 index 0000000000000..73327942e4919 --- /dev/null +++ b/tests/ui/eii/default/auxiliary/decl_with_default.rs @@ -0,0 +1,9 @@ +//@ no-prefer-dynamic +#![crate_type = "rlib"] +#![feature(eii)] + +#[eii(eii1)] +pub fn decl1(x: u64) { + println!("default {x}"); +} + diff --git a/tests/ui/eii/default/auxiliary/impl1.rs b/tests/ui/eii/default/auxiliary/impl1.rs new file mode 100644 index 0000000000000..4d627a5f68a64 --- /dev/null +++ b/tests/ui/eii/default/auxiliary/impl1.rs @@ -0,0 +1,12 @@ +//@ no-prefer-dynamic +//@ aux-build: decl_with_default.rs +#![crate_type = "rlib"] +#![feature(eii)] + +extern crate decl_with_default as decl; + + +#[unsafe(decl::eii1)] //~ ERROR multiple implementations of `#[eii1]` +fn other(x: u64) { + println!("1{x}"); +} diff --git a/tests/ui/eii/default/call_default.rs b/tests/ui/eii/default/call_default.rs new file mode 100644 index 0000000000000..ee799c7d38e76 --- /dev/null +++ b/tests/ui/eii/default/call_default.rs @@ -0,0 +1,11 @@ +//@ no-prefer-dynamic +//@ aux-build: decl_with_default.rs +//@ run-pass +//@ check-run-results +#![feature(eii)] + +extern crate decl_with_default; + +fn main() { + decl_with_default::decl1(10); +} diff --git a/tests/ui/eii/default/call_default.run.stdout b/tests/ui/eii/default/call_default.run.stdout new file mode 100644 index 0000000000000..1e49486f6aaf4 --- /dev/null +++ b/tests/ui/eii/default/call_default.run.stdout @@ -0,0 +1 @@ +default 10 diff --git a/tests/ui/eii/default/call_impl.rs b/tests/ui/eii/default/call_impl.rs new file mode 100644 index 0000000000000..56a26f8b819f5 --- /dev/null +++ b/tests/ui/eii/default/call_impl.rs @@ -0,0 +1,13 @@ +//@ no-prefer-dynamic +//@ aux-build: decl_with_default.rs +//@ aux-build: impl1.rs +//@ run-pass +//@ check-run-results +#![feature(eii)] + +extern crate decl_with_default; +extern crate impl1; + +fn main() { + decl_with_default::decl1(10); +} diff --git a/tests/ui/eii/default/call_impl.run.stdout b/tests/ui/eii/default/call_impl.run.stdout new file mode 100644 index 0000000000000..bc6298e80ad4b --- /dev/null +++ b/tests/ui/eii/default/call_impl.run.stdout @@ -0,0 +1 @@ +110 diff --git a/tests/ui/eii/default/local_crate.rs b/tests/ui/eii/default/local_crate.rs new file mode 100644 index 0000000000000..d35d2a919070e --- /dev/null +++ b/tests/ui/eii/default/local_crate.rs @@ -0,0 +1,12 @@ +//@ run-pass +//@ check-run-results +#![feature(eii)] + +#[eii(eii1)] +pub fn decl1(x: u64) { + println!("default {x}"); +} + +fn main() { + decl1(4); +} diff --git a/tests/ui/eii/default/local_crate.run.stdout b/tests/ui/eii/default/local_crate.run.stdout new file mode 100644 index 0000000000000..032082d92b722 --- /dev/null +++ b/tests/ui/eii/default/local_crate.run.stdout @@ -0,0 +1 @@ +default 4 diff --git a/tests/ui/eii/default/local_crate_explicit.rs b/tests/ui/eii/default/local_crate_explicit.rs new file mode 100644 index 0000000000000..3387df67df8d4 --- /dev/null +++ b/tests/ui/eii/default/local_crate_explicit.rs @@ -0,0 +1,17 @@ +//@ run-pass +//@ check-run-results +#![feature(eii)] + +#[eii(eii1)] +pub fn decl1(x: u64) { + println!("default {x}"); +} + +#[eii1] +pub fn decl2(x: u64) { + println!("explicit {x}"); +} + +fn main() { + decl1(4); +} diff --git a/tests/ui/eii/default/local_crate_explicit.run.stdout b/tests/ui/eii/default/local_crate_explicit.run.stdout new file mode 100644 index 0000000000000..d7ce3a9fb8bab --- /dev/null +++ b/tests/ui/eii/default/local_crate_explicit.run.stdout @@ -0,0 +1 @@ +explicit 4 diff --git a/tests/ui/eii/duplicate/auxiliary/decl.rs b/tests/ui/eii/duplicate/auxiliary/decl.rs new file mode 100644 index 0000000000000..0ee45d6675e2d --- /dev/null +++ b/tests/ui/eii/duplicate/auxiliary/decl.rs @@ -0,0 +1,7 @@ +//@ no-prefer-dynamic +#![crate_type = "rlib"] +#![feature(eii)] + +#[eii(eii1)] +fn decl1(x: u64); + diff --git a/tests/ui/eii/duplicate/auxiliary/impl1.rs b/tests/ui/eii/duplicate/auxiliary/impl1.rs new file mode 100644 index 0000000000000..655fdb1acf0d5 --- /dev/null +++ b/tests/ui/eii/duplicate/auxiliary/impl1.rs @@ -0,0 +1,12 @@ +//@ no-prefer-dynamic +//@ aux-build: decl.rs +#![crate_type = "rlib"] +#![feature(eii)] + +extern crate decl; + + +#[unsafe(decl::eii1)] //~ ERROR multiple implementations of `#[eii1]` +fn other(x: u64) { + println!("1{x}"); +} diff --git a/tests/ui/eii/duplicate/auxiliary/impl2.rs b/tests/ui/eii/duplicate/auxiliary/impl2.rs new file mode 100644 index 0000000000000..bce6f11b89c48 --- /dev/null +++ b/tests/ui/eii/duplicate/auxiliary/impl2.rs @@ -0,0 +1,12 @@ +//@ no-prefer-dynamic +//@ aux-build: decl.rs +#![crate_type = "rlib"] +#![feature(eii)] + +extern crate decl; + + +#[unsafe(decl::eii1)] +fn other(x: u64) { + println!("2{x}"); +} diff --git a/tests/ui/eii/duplicate/auxiliary/impl3.rs b/tests/ui/eii/duplicate/auxiliary/impl3.rs new file mode 100644 index 0000000000000..82ba5af098635 --- /dev/null +++ b/tests/ui/eii/duplicate/auxiliary/impl3.rs @@ -0,0 +1,12 @@ +//@ no-prefer-dynamic +//@ aux-build: decl.rs +#![crate_type = "rlib"] +#![feature(eii)] + +extern crate decl; + + +#[unsafe(decl::eii1)] +fn other(x: u64) { + println!("3{x}"); +} diff --git a/tests/ui/eii/duplicate/auxiliary/impl4.rs b/tests/ui/eii/duplicate/auxiliary/impl4.rs new file mode 100644 index 0000000000000..5275da1b14333 --- /dev/null +++ b/tests/ui/eii/duplicate/auxiliary/impl4.rs @@ -0,0 +1,12 @@ +//@ no-prefer-dynamic +//@ aux-build: decl.rs +#![crate_type = "rlib"] +#![feature(eii)] + +extern crate decl; + + +#[unsafe(decl::eii1)] +fn other(x: u64) { + println!("4{x}"); +} diff --git a/tests/ui/eii/duplicate/duplicate1.rs b/tests/ui/eii/duplicate/duplicate1.rs new file mode 100644 index 0000000000000..3c0def08bf1bc --- /dev/null +++ b/tests/ui/eii/duplicate/duplicate1.rs @@ -0,0 +1,9 @@ +//@ no-prefer-dynamic +//@ aux-build: impl1.rs +//@ aux-build: impl2.rs +#![feature(eii)] + +extern crate impl1; +extern crate impl2; + +fn main() {} diff --git a/tests/ui/eii/duplicate/duplicate1.stderr b/tests/ui/eii/duplicate/duplicate1.stderr new file mode 100644 index 0000000000000..fd468cab2ecfd --- /dev/null +++ b/tests/ui/eii/duplicate/duplicate1.stderr @@ -0,0 +1,15 @@ +error: multiple implementations of `#[eii1]` + --> $DIR/auxiliary/impl1.rs:10:1 + | +LL | fn other(x: u64) { + | ^^^^^^^^^^^^^^^^ first implemented here in crate `impl1` + | + ::: $DIR/auxiliary/impl2.rs:10:1 + | +LL | fn other(x: u64) { + | ---------------- also implemented here in crate `impl2` + | + = help: an "externally implementable item" can only have a single implementation in the final artifact. When multiple implementations are found, also in different crates, they conflict. + +error: aborting due to 1 previous error + diff --git a/tests/ui/eii/duplicate/duplicate2.rs b/tests/ui/eii/duplicate/duplicate2.rs new file mode 100644 index 0000000000000..545ba6ef8f111 --- /dev/null +++ b/tests/ui/eii/duplicate/duplicate2.rs @@ -0,0 +1,11 @@ +//@ no-prefer-dynamic +//@ aux-build: impl1.rs +//@ aux-build: impl2.rs +//@ aux-build: impl3.rs +#![feature(eii)] + +extern crate impl1; +extern crate impl2; +extern crate impl3; + +fn main() {} diff --git a/tests/ui/eii/duplicate/duplicate2.stderr b/tests/ui/eii/duplicate/duplicate2.stderr new file mode 100644 index 0000000000000..c15dcdc6e246b --- /dev/null +++ b/tests/ui/eii/duplicate/duplicate2.stderr @@ -0,0 +1,16 @@ +error: multiple implementations of `#[eii1]` + --> $DIR/auxiliary/impl1.rs:10:1 + | +LL | fn other(x: u64) { + | ^^^^^^^^^^^^^^^^ first implemented here in crate `impl1` + | + ::: $DIR/auxiliary/impl2.rs:10:1 + | +LL | fn other(x: u64) { + | ---------------- also implemented here in crate `impl2` + | + = note: in addition to these two, another implementation was found in crate `impl3` + = help: an "externally implementable item" can only have a single implementation in the final artifact. When multiple implementations are found, also in different crates, they conflict. + +error: aborting due to 1 previous error + diff --git a/tests/ui/eii/duplicate/duplicate3.rs b/tests/ui/eii/duplicate/duplicate3.rs new file mode 100644 index 0000000000000..a87cf3354df7e --- /dev/null +++ b/tests/ui/eii/duplicate/duplicate3.rs @@ -0,0 +1,13 @@ +//@ no-prefer-dynamic +//@ aux-build: impl1.rs +//@ aux-build: impl2.rs +//@ aux-build: impl3.rs +//@ aux-build: impl4.rs +#![feature(eii)] + +extern crate impl1; +extern crate impl2; +extern crate impl3; +extern crate impl4; + +fn main() {} diff --git a/tests/ui/eii/duplicate/duplicate3.stderr b/tests/ui/eii/duplicate/duplicate3.stderr new file mode 100644 index 0000000000000..4512bd708d548 --- /dev/null +++ b/tests/ui/eii/duplicate/duplicate3.stderr @@ -0,0 +1,16 @@ +error: multiple implementations of `#[eii1]` + --> $DIR/auxiliary/impl1.rs:10:1 + | +LL | fn other(x: u64) { + | ^^^^^^^^^^^^^^^^ first implemented here in crate `impl1` + | + ::: $DIR/auxiliary/impl2.rs:10:1 + | +LL | fn other(x: u64) { + | ---------------- also implemented here in crate `impl2` + | + = note: in addition to these two, more implementations were also found in the following crates: `impl3`, `impl4` + = help: an "externally implementable item" can only have a single implementation in the final artifact. When multiple implementations are found, also in different crates, they conflict. + +error: aborting due to 1 previous error + diff --git a/tests/ui/eii/privacy1.rs b/tests/ui/eii/privacy1.rs new file mode 100644 index 0000000000000..b6414e9c28f43 --- /dev/null +++ b/tests/ui/eii/privacy1.rs @@ -0,0 +1,30 @@ +//@ run-pass +//@ check-run-results +//@ aux-build: codegen1.rs +#![feature(eii)] + +extern crate codegen1 as codegen; + +#[codegen::eii1] +fn eii1_impl(x: u64) { + println!("{x:?}") +} + + +#[codegen::eii3] +fn eii3_impl(x: u64) { + println!("{x:?}") +} + +// what you would write: +fn main() { + // directly + eii1_impl(21); + // through the alias + codegen::local_call_decl1(42); + + // directly + eii3_impl(12); + // through the alias + codegen::decl3(24); +} diff --git a/tests/ui/eii/privacy1.run.stdout b/tests/ui/eii/privacy1.run.stdout new file mode 100644 index 0000000000000..c762399185638 --- /dev/null +++ b/tests/ui/eii/privacy1.run.stdout @@ -0,0 +1,4 @@ +21 +42 +12 +24 diff --git a/tests/ui/eii/privacy2.rs b/tests/ui/eii/privacy2.rs new file mode 100644 index 0000000000000..61431b71cec32 --- /dev/null +++ b/tests/ui/eii/privacy2.rs @@ -0,0 +1,22 @@ +//@ aux-build:codegen3.rs +#![feature(eii)] + +extern crate codegen3 as codegen; + +#[codegen::eii1] +fn eii1_impl(x: u64) { + println!("{x:?}") +} + +#[codegen::eii3] //~ ERROR failed to resolve: could not find `eii3` in `codegen` +fn eii3_impl(x: u64) { + println!("{x:?}") +} + +// what you would write: +fn main() { + // directly + eii1_impl(21); + // through the alias + codegen::decl1(42); //~ ERROR function `decl1` is private +} diff --git a/tests/ui/eii/privacy2.stderr b/tests/ui/eii/privacy2.stderr new file mode 100644 index 0000000000000..71616d311e837 --- /dev/null +++ b/tests/ui/eii/privacy2.stderr @@ -0,0 +1,40 @@ +error[E0433]: failed to resolve: could not find `eii3` in `codegen` + --> $DIR/privacy2.rs:11:12 + | +LL | #[codegen::eii3] + | ^^^^ could not find `eii3` in `codegen` + +error[E0603]: function `decl1` is private + --> $DIR/privacy2.rs:21:14 + | +LL | codegen::decl1(42); + | ^^^^^ private function + | +note: the function `decl1` is defined here + --> $DIR/auxiliary/codegen3.rs:7:1 + | +LL | fn decl1(x: u64); + | ^^^^^^^^^^^^^^^^^ + +error: couldn't find an implementation for `#[eii2]` + --> $DIR/auxiliary/codegen3.rs:9:1 + | +LL | #[eii(eii2)] + | ^^^^^^^^^^^^ an implementation was expected by this declaration + | + = help: expected at least one implementation in crate `privacy2` or any of its dependencies + = note: this error originates in the attribute macro `eii` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: couldn't find an implementation for `#[eii3]` + --> $DIR/auxiliary/codegen3.rs:13:5 + | +LL | #[eii(eii3)] + | ^^^^^^^^^^^^ an implementation was expected by this declaration + | + = help: expected at least one implementation in crate `privacy2` or any of its dependencies + = note: this error originates in the attribute macro `eii` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0433, E0603. +For more information about an error, try `rustc --explain E0433`. From 06da48a0c1dbb20eb8260a435d29c8a010bd4305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 31 Mar 2025 18:50:26 +0200 Subject: [PATCH 26/41] tidy --- compiler/rustc_builtin_macros/messages.ftl | 2 +- compiler/rustc_feature/src/unstable.rs | 4 ++-- compiler/rustc_passes/messages.ftl | 2 +- library/core/src/macros/mod.rs | 4 ++-- library/core/src/prelude/v1.rs | 2 +- library/std/src/prelude/v1.rs | 2 +- tests/ui/eii/auxiliary/codegen2.rs | 1 - tests/ui/eii/default/auxiliary/decl_with_default.rs | 1 - tests/ui/eii/duplicate/auxiliary/decl.rs | 1 - 9 files changed, 8 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 852360ea8df58..19190f1e267e0 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -154,7 +154,7 @@ builtin_macros_eii_macro_expected_function = `#[{$name}]` is only valid on funct builtin_macros_eii_macro_for_expected_list = `#[eii_macro_for(...)]` expects a list of one or two elements builtin_macros_eii_macro_for_expected_macro = `#[eii_macro_for(...)]` is only valid on macros builtin_macros_eii_macro_for_expected_max_one_argument = `#[{$name}]` expected no arguments or a single argument: `#[{$name}(default)]` -builtin_macros_eii_macro_for_expected_unsafe = expected this argument to be "unsafe". +builtin_macros_eii_macro_for_expected_unsafe = expected this argument to be "unsafe" .note = the second argument is optional builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index c59b60efe8c70..84755fd5047af 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -480,6 +480,8 @@ declare_features! ( (unstable, doc_masked, "1.21.0", Some(44027)), /// Allows `dyn* Trait` objects. (incomplete, dyn_star, "1.65.0", Some(102425)), + /// Externally implementatble items + (unstable, eii, "CURRENT_RUSTC_VERSION", Some(125418)), /// Allows the .use postfix syntax `x.use` and use closures `use |x| { ... }` (incomplete, ergonomic_clones, "1.87.0", Some(132290)), /// Allows exhaustive pattern matching on types that contain uninhabited types. @@ -497,8 +499,6 @@ declare_features! ( (unstable, extern_system_varargs, "1.86.0", Some(136946)), /// Allows defining `extern type`s. (unstable, extern_types, "1.23.0", Some(43467)), - /// Externally implementatble items - (unstable, eii, "CURRENT_RUSTC_VERSION", Some(125418)), /// Allow using 128-bit (quad precision) floating point numbers. (unstable, f128, "1.78.0", Some(116909)), /// Allow using 16-bit (half precision) floating point numbers. diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 1c79802db7d81..e1a190484528d 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -287,7 +287,7 @@ passes_duplicate_eii_impls = *[other] more implementations were also found in the following crates: {$additional_crate_names} } - .help = an "externally implementable item" can only have a single implementation in the final artifact. When multiple implementations are found, also in different crates, they conflict. + .help = an "externally implementable item" can only have a single implementation in the final artifact. When multiple implementations are found, also in different crates, they conflict passes_duplicate_feature_err = the feature `{$feature}` has already been enabled diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 27962cdf0c531..8e7036379ea13 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1787,7 +1787,7 @@ pub(crate) mod builtin { /// Externally Implementable Item: Defines an attribute macro that can override the item /// this is applied to. #[cfg(not(bootstrap))] - #[unstable(feature = "eii", issue = "none")] + #[unstable(feature = "eii", issue = "125418")] #[rustc_builtin_macro] #[allow_internal_unstable(eii_internals, decl_macro, rustc_attrs)] pub macro eii($item:item) { @@ -1797,7 +1797,7 @@ pub(crate) mod builtin { /// Unsafely Externally Implementable Item: Defines an unsafe attribute macro that can override /// the item this is applied to. #[cfg(not(bootstrap))] - #[unstable(feature = "eii", issue = "none")] + #[unstable(feature = "eii", issue = "125418")] #[rustc_builtin_macro] #[allow_internal_unstable(eii_internals, decl_macro, rustc_attrs)] pub macro unsafe_eii($item:item) { diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index 4d2d8b5103410..dad7d16eb562d 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -120,7 +120,7 @@ pub use crate::macros::builtin::deref; )] pub use crate::macros::builtin::define_opaque; -#[unstable(feature = "eii", issue = "none")] +#[unstable(feature = "eii", issue = "125418")] #[cfg(not(bootstrap))] pub use crate::macros::builtin::{eii, unsafe_eii}; diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 17f0767eea044..ca45a70919327 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -112,7 +112,7 @@ pub use core::prelude::v1::deref; )] pub use core::prelude::v1::define_opaque; -#[unstable(feature = "eii", issue = "none")] +#[unstable(feature = "eii", issue = "125418")] #[cfg(not(bootstrap))] pub use core::prelude::v1::{eii, unsafe_eii}; diff --git a/tests/ui/eii/auxiliary/codegen2.rs b/tests/ui/eii/auxiliary/codegen2.rs index ef7b885b39a86..9545ad007c57a 100644 --- a/tests/ui/eii/auxiliary/codegen2.rs +++ b/tests/ui/eii/auxiliary/codegen2.rs @@ -4,4 +4,3 @@ #[eii(eii1)] pub fn decl1(x: u64); - diff --git a/tests/ui/eii/default/auxiliary/decl_with_default.rs b/tests/ui/eii/default/auxiliary/decl_with_default.rs index 73327942e4919..b1811b07eb17e 100644 --- a/tests/ui/eii/default/auxiliary/decl_with_default.rs +++ b/tests/ui/eii/default/auxiliary/decl_with_default.rs @@ -6,4 +6,3 @@ pub fn decl1(x: u64) { println!("default {x}"); } - diff --git a/tests/ui/eii/duplicate/auxiliary/decl.rs b/tests/ui/eii/duplicate/auxiliary/decl.rs index 0ee45d6675e2d..81557fa6891b8 100644 --- a/tests/ui/eii/duplicate/auxiliary/decl.rs +++ b/tests/ui/eii/duplicate/auxiliary/decl.rs @@ -4,4 +4,3 @@ #[eii(eii1)] fn decl1(x: u64); - From d988d70959fe461fd7d13ce96a39f0bc444a1ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 2 Apr 2025 17:06:29 +0200 Subject: [PATCH 27/41] broken tests after rebase? --- tests/ui/eii/auxiliary/codegen3.rs | 4 ++-- tests/ui/eii/duplicate/auxiliary/impl1.rs | 2 +- tests/ui/eii/duplicate/duplicate1.rs | 3 +++ tests/ui/eii/duplicate/duplicate1.stderr | 2 +- tests/ui/eii/duplicate/duplicate2.rs | 3 +++ tests/ui/eii/duplicate/duplicate2.stderr | 2 +- tests/ui/eii/duplicate/duplicate3.rs | 3 +++ tests/ui/eii/duplicate/duplicate3.stderr | 2 +- tests/ui/eii/errors.stderr | 2 +- tests/ui/eii/privacy2.rs | 4 ++++ tests/ui/eii/privacy2.stderr | 6 ++---- 11 files changed, 22 insertions(+), 11 deletions(-) diff --git a/tests/ui/eii/auxiliary/codegen3.rs b/tests/ui/eii/auxiliary/codegen3.rs index 5001df6e6f986..2b882c48d829a 100644 --- a/tests/ui/eii/auxiliary/codegen3.rs +++ b/tests/ui/eii/auxiliary/codegen3.rs @@ -6,11 +6,11 @@ #[eii(eii1)] fn decl1(x: u64); -#[eii(eii2)] //~ ERROR couldn't find an implementation for `#[eii2]` +#[eii(eii2)] pub fn decl2(x: u64); mod private { - #[eii(eii3)] //~ ERROR couldn't find an implementation for `#[eii3]` + #[eii(eii3)] pub fn decl3(x: u64); } diff --git a/tests/ui/eii/duplicate/auxiliary/impl1.rs b/tests/ui/eii/duplicate/auxiliary/impl1.rs index 655fdb1acf0d5..d7c27f4dfde92 100644 --- a/tests/ui/eii/duplicate/auxiliary/impl1.rs +++ b/tests/ui/eii/duplicate/auxiliary/impl1.rs @@ -6,7 +6,7 @@ extern crate decl; -#[unsafe(decl::eii1)] //~ ERROR multiple implementations of `#[eii1]` +#[unsafe(decl::eii1)] fn other(x: u64) { println!("1{x}"); } diff --git a/tests/ui/eii/duplicate/duplicate1.rs b/tests/ui/eii/duplicate/duplicate1.rs index 3c0def08bf1bc..c6336c1166e75 100644 --- a/tests/ui/eii/duplicate/duplicate1.rs +++ b/tests/ui/eii/duplicate/duplicate1.rs @@ -3,6 +3,9 @@ //@ aux-build: impl2.rs #![feature(eii)] +// has a span but in the other crate +//~? ERROR multiple implementations of `#[eii1]` + extern crate impl1; extern crate impl2; diff --git a/tests/ui/eii/duplicate/duplicate1.stderr b/tests/ui/eii/duplicate/duplicate1.stderr index fd468cab2ecfd..54cc141f88694 100644 --- a/tests/ui/eii/duplicate/duplicate1.stderr +++ b/tests/ui/eii/duplicate/duplicate1.stderr @@ -9,7 +9,7 @@ LL | fn other(x: u64) { LL | fn other(x: u64) { | ---------------- also implemented here in crate `impl2` | - = help: an "externally implementable item" can only have a single implementation in the final artifact. When multiple implementations are found, also in different crates, they conflict. + = help: an "externally implementable item" can only have a single implementation in the final artifact. When multiple implementations are found, also in different crates, they conflict error: aborting due to 1 previous error diff --git a/tests/ui/eii/duplicate/duplicate2.rs b/tests/ui/eii/duplicate/duplicate2.rs index 545ba6ef8f111..e2b0acdbf30e8 100644 --- a/tests/ui/eii/duplicate/duplicate2.rs +++ b/tests/ui/eii/duplicate/duplicate2.rs @@ -4,6 +4,9 @@ //@ aux-build: impl3.rs #![feature(eii)] +// has a span but in the other crate +//~? ERROR multiple implementations of `#[eii1]` + extern crate impl1; extern crate impl2; extern crate impl3; diff --git a/tests/ui/eii/duplicate/duplicate2.stderr b/tests/ui/eii/duplicate/duplicate2.stderr index c15dcdc6e246b..033e43c8b2fbd 100644 --- a/tests/ui/eii/duplicate/duplicate2.stderr +++ b/tests/ui/eii/duplicate/duplicate2.stderr @@ -10,7 +10,7 @@ LL | fn other(x: u64) { | ---------------- also implemented here in crate `impl2` | = note: in addition to these two, another implementation was found in crate `impl3` - = help: an "externally implementable item" can only have a single implementation in the final artifact. When multiple implementations are found, also in different crates, they conflict. + = help: an "externally implementable item" can only have a single implementation in the final artifact. When multiple implementations are found, also in different crates, they conflict error: aborting due to 1 previous error diff --git a/tests/ui/eii/duplicate/duplicate3.rs b/tests/ui/eii/duplicate/duplicate3.rs index a87cf3354df7e..87e6c409b10e8 100644 --- a/tests/ui/eii/duplicate/duplicate3.rs +++ b/tests/ui/eii/duplicate/duplicate3.rs @@ -5,6 +5,9 @@ //@ aux-build: impl4.rs #![feature(eii)] +// has a span but in the other crate +//~? ERROR multiple implementations of `#[eii1]` + extern crate impl1; extern crate impl2; extern crate impl3; diff --git a/tests/ui/eii/duplicate/duplicate3.stderr b/tests/ui/eii/duplicate/duplicate3.stderr index 4512bd708d548..801d40e69c552 100644 --- a/tests/ui/eii/duplicate/duplicate3.stderr +++ b/tests/ui/eii/duplicate/duplicate3.stderr @@ -10,7 +10,7 @@ LL | fn other(x: u64) { | ---------------- also implemented here in crate `impl2` | = note: in addition to these two, more implementations were also found in the following crates: `impl3`, `impl4` - = help: an "externally implementable item" can only have a single implementation in the final artifact. When multiple implementations are found, also in different crates, they conflict. + = help: an "externally implementable item" can only have a single implementation in the final artifact. When multiple implementations are found, also in different crates, they conflict error: aborting due to 1 previous error diff --git a/tests/ui/eii/errors.stderr b/tests/ui/eii/errors.stderr index b5eba839a1491..b978125c502b8 100644 --- a/tests/ui/eii/errors.stderr +++ b/tests/ui/eii/errors.stderr @@ -22,7 +22,7 @@ error: `#[eii_macro_for(...)]` expects a list of one or two elements LL | #[eii_macro_for()] | ^^^^^^^^^^^^^^^^^^ -error: expected this argument to be "unsafe". +error: expected this argument to be "unsafe" --> $DIR/errors.rs:15:22 | LL | #[eii_macro_for(bar, hello)] diff --git a/tests/ui/eii/privacy2.rs b/tests/ui/eii/privacy2.rs index 61431b71cec32..88d174a48f6d4 100644 --- a/tests/ui/eii/privacy2.rs +++ b/tests/ui/eii/privacy2.rs @@ -3,6 +3,10 @@ extern crate codegen3 as codegen; +// has a span but in the other crate +//~? ERROR couldn't find an implementation for `#[eii2]` +//~? ERROR couldn't find an implementation for `#[eii3]` + #[codegen::eii1] fn eii1_impl(x: u64) { println!("{x:?}") diff --git a/tests/ui/eii/privacy2.stderr b/tests/ui/eii/privacy2.stderr index 71616d311e837..ac4a5dca749b2 100644 --- a/tests/ui/eii/privacy2.stderr +++ b/tests/ui/eii/privacy2.stderr @@ -1,11 +1,11 @@ error[E0433]: failed to resolve: could not find `eii3` in `codegen` - --> $DIR/privacy2.rs:11:12 + --> $DIR/privacy2.rs:15:12 | LL | #[codegen::eii3] | ^^^^ could not find `eii3` in `codegen` error[E0603]: function `decl1` is private - --> $DIR/privacy2.rs:21:14 + --> $DIR/privacy2.rs:25:14 | LL | codegen::decl1(42); | ^^^^^ private function @@ -23,7 +23,6 @@ LL | #[eii(eii2)] | ^^^^^^^^^^^^ an implementation was expected by this declaration | = help: expected at least one implementation in crate `privacy2` or any of its dependencies - = note: this error originates in the attribute macro `eii` (in Nightly builds, run with -Z macro-backtrace for more info) error: couldn't find an implementation for `#[eii3]` --> $DIR/auxiliary/codegen3.rs:13:5 @@ -32,7 +31,6 @@ LL | #[eii(eii3)] | ^^^^^^^^^^^^ an implementation was expected by this declaration | = help: expected at least one implementation in crate `privacy2` or any of its dependencies - = note: this error originates in the attribute macro `eii` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors From 1e8100b796425c4065b704e561a7c0daae5255dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 18 Apr 2025 08:13:42 +0200 Subject: [PATCH 28/41] fix bug with resolving EIIs in hir lowering --- compiler/rustc_ast_lowering/src/item.rs | 46 ++++++++++++++----------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index e6520d2f7268b..8def3301ddced 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -158,7 +158,7 @@ impl<'hir> LoweringContext<'_, 'hir> { vec![hir::Attribute::Parsed(AttributeKind::EiiImpl( eii_impl .iter() - .map( + .flat_map( |EIIImpl { node_id, eii_macro_path, @@ -167,16 +167,17 @@ impl<'hir> LoweringContext<'_, 'hir> { inner_span, is_default, }| { - let did = self.lower_path_simple_eii(*node_id, eii_macro_path); - rustc_attr_parsing::EIIImpl { - eii_macro: did, - span: self.lower_span(*span), - inner_span: self.lower_span(*inner_span), - impl_marked_unsafe: self - .lower_safety(*impl_safety, hir::Safety::Safe) - .is_unsafe(), - is_default: *is_default, - } + self.lower_path_simple_eii(*node_id, eii_macro_path).map(|did| { + rustc_attr_parsing::EIIImpl { + eii_macro: did, + span: self.lower_span(*span), + inner_span: self.lower_span(*inner_span), + impl_marked_unsafe: self + .lower_safety(*impl_safety, hir::Safety::Safe) + .is_unsafe(), + is_default: *is_default, + } + }) }, ) .collect(), @@ -188,13 +189,16 @@ impl<'hir> LoweringContext<'_, 'hir> { eii_macro_for: Some(EIIMacroFor { extern_item_path, impl_unsafe, span }), .. }, - ) => { - vec![hir::Attribute::Parsed(AttributeKind::EiiMacroFor(EIIDecl { - eii_extern_item: self.lower_path_simple_eii(id, extern_item_path), - impl_unsafe: *impl_unsafe, - span: self.lower_span(*span), - }))] - } + ) => self + .lower_path_simple_eii(id, extern_item_path) + .map(|did| { + vec![hir::Attribute::Parsed(AttributeKind::EiiMacroFor(EIIDecl { + eii_extern_item: did, + impl_unsafe: *impl_unsafe, + span: self.lower_span(*span), + }))] + }) + .unwrap_or_default(), ItemKind::ExternCrate(..) | ItemKind::Use(..) | ItemKind::Static(..) @@ -571,14 +575,14 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn lower_path_simple_eii(&mut self, id: NodeId, path: &Path) -> DefId { + fn lower_path_simple_eii(&mut self, id: NodeId, path: &Path) -> Option { let res = self.resolver.get_partial_res(id).unwrap(); let Some(did) = res.expect_full_res().opt_def_id() else { self.dcx().span_delayed_bug(path.span, "should have errored in resolve"); - todo!() + return None; }; - did + Some(did) } fn lower_const_item( From b3016cb8afbcb18aab72fd1a5915e56f442880f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 18 Apr 2025 08:15:19 +0200 Subject: [PATCH 29/41] forward attributes on EII implementation functions --- compiler/rustc_builtin_macros/src/eii.rs | 53 +++++++++++++----------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index 4efecdc6eb808..b45f344c02653 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -209,7 +209,7 @@ fn eii_( safety: ast::Safety::Unsafe(span), abi, items: From::from([P(ast::ForeignItem { - attrs, + attrs: attrs.clone(), id: ast::DUMMY_NODE_ID, span: item_span, vis, @@ -220,31 +220,34 @@ fn eii_( tokens: None, })); - let macro_def = Annotatable::Item(P(ast::Item { - attrs: ast::AttrVec::from_iter([ - // #[builtin_macro(eii_macro)] - ast::Attribute { - kind: ast::AttrKind::Normal(P(ast::NormalAttr { - item: ast::AttrItem { - unsafety: ast::Safety::Default, - path: ast::Path::from_ident(Ident::new(sym::rustc_builtin_macro, span)), - args: ast::AttrArgs::Delimited(ast::DelimArgs { - dspan: DelimSpan::from_single(span), - delim: Delimiter::Parenthesis, - tokens: TokenStream::new(vec![tokenstream::TokenTree::token_alone( - token::TokenKind::Ident(sym::eii_macro, token::IdentIsRaw::No), - span, - )]), - }), - tokens: None, - }, + let mut macro_attrs = attrs.clone(); + macro_attrs.push( + // #[builtin_macro(eii_macro)] + ast::Attribute { + kind: ast::AttrKind::Normal(P(ast::NormalAttr { + item: ast::AttrItem { + unsafety: ast::Safety::Default, + path: ast::Path::from_ident(Ident::new(sym::rustc_builtin_macro, span)), + args: ast::AttrArgs::Delimited(ast::DelimArgs { + dspan: DelimSpan::from_single(span), + delim: Delimiter::Parenthesis, + tokens: TokenStream::new(vec![tokenstream::TokenTree::token_alone( + token::TokenKind::Ident(sym::eii_macro, token::IdentIsRaw::No), + span, + )]), + }), tokens: None, - })), - id: ecx.sess.psess.attr_id_generator.mk_attr_id(), - style: ast::AttrStyle::Outer, - span, - }, - ]), + }, + tokens: None, + })), + id: ecx.sess.psess.attr_id_generator.mk_attr_id(), + style: ast::AttrStyle::Outer, + span, + }, + ); + + let macro_def = Annotatable::Item(P(ast::Item { + attrs: macro_attrs, id: ast::DUMMY_NODE_ID, span, // pub From b45f96a49c43fc5ced715f5d5074c646c20b1688 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 18 Apr 2025 08:26:15 +0200 Subject: [PATCH 30/41] remove again defkind EIIShim --- compiler/rustc_hir_typeck/src/check.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 99103f14d6823..8d1d432ffd957 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -1,8 +1,8 @@ use std::cell::RefCell; use rustc_abi::ExternAbi; -use rustc_hir as hir; use rustc_hir::def::DefKind; +use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_hir_analysis::check::check_function_signature; use rustc_infer::infer::RegionVariableOrigin; From f41c8da0f04c96339358f9fff061a8fd5389efda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 18 Apr 2025 08:31:37 +0200 Subject: [PATCH 31/41] fix various bugs in EII (todo: absorb) --- .../src/back/symbol_export.rs | 13 ++++ .../src/const_eval/fn_queries.rs | 2 + compiler/rustc_hir_analysis/messages.ftl | 8 ++- .../src/check/compare_eii.rs | 32 ++++++++- compiler/rustc_hir_analysis/src/collect.rs | 11 ++++ compiler/rustc_hir_analysis/src/errors.rs | 10 +++ compiler/rustc_middle/src/arena.rs | 2 +- compiler/rustc_middle/src/hir/map.rs | 11 +++- compiler/rustc_middle/src/hir/mod.rs | 5 ++ compiler/rustc_middle/src/middle/eii.rs | 12 ++++ compiler/rustc_middle/src/middle/mod.rs | 1 + compiler/rustc_middle/src/mir/mono.rs | 7 +- compiler/rustc_middle/src/query/mod.rs | 8 +-- compiler/rustc_middle/src/ty/context.rs | 4 -- compiler/rustc_mir_transform/src/shim.rs | 19 ++++-- compiler/rustc_monomorphize/src/collector.rs | 19 ++---- .../rustc_monomorphize/src/partitioning.rs | 17 ++++- compiler/rustc_passes/messages.ftl | 23 +++---- compiler/rustc_passes/src/check_attr.rs | 26 +++++++- compiler/rustc_passes/src/dead.rs | 7 ++ compiler/rustc_passes/src/eii.rs | 66 +++++++++++++------ compiler/rustc_passes/src/errors.rs | 9 +-- compiler/rustc_passes/src/lib.rs | 3 +- compiler/rustc_passes/src/reachable.rs | 61 +++++++++++------ compiler/rustc_symbol_mangling/src/lib.rs | 6 +- 25 files changed, 281 insertions(+), 101 deletions(-) create mode 100644 compiler/rustc_middle/src/middle/eii.rs diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 0eec6318aaa73..5f139ea1ac510 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -59,6 +59,8 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap = tcx .reachable_set(()) .items() @@ -99,6 +101,17 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap, def_id: LocalDefId) -> hir::Constness { // If the function itself is not annotated with `const`, it may still be a `const fn` // if it resides in a const trait impl. parent_impl_or_trait_constness(tcx, def_id) + } else if tcx.get_externally_implementable_item_impls(()).contains_key(&def_id) { + hir::Constness::NotConst } else { tcx.dcx().span_bug( tcx.def_span(def_id), diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 0395f5ee2c2d6..24443c5099440 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -159,6 +159,10 @@ hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twice .label = parameter captured again here +hir_analysis_eii_with_generics = + #[{$eii_name}] cannot have generic parameters other than lifetimes + .label = required by this attribute + hir_analysis_empty_specialization = specialization impl does not specialize any associated items .note = impl is a specialization of this impl @@ -295,10 +299,10 @@ hir_analysis_lifetime_not_captured = `impl Trait` captures lifetime parameter, b .param_label = this lifetime parameter is captured hir_analysis_lifetimes_or_bounds_mismatch_on_eii = - lifetime parameters or bounds `{$ident}` do not match the declaration + lifetime parameters or bounds of `{$ident}` do not match the declaration .label = lifetimes do not match .generics_label = lifetimes in impl do not match this signature - .where_label = this `where` clause might not match the one in the trait + .where_label = this `where` clause might not match the one in the declaration .bounds_label = this bound might be missing in the implementation hir_analysis_lifetimes_or_bounds_mismatch_on_trait = diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index bd782be641fb5..84940c56e36fb 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -16,7 +16,7 @@ use rustc_trait_selection::traits::ObligationCtxt; use tracing::{debug, instrument}; use super::potentially_plural_count; -use crate::errors::LifetimesOrBoundsMismatchOnEII; +use crate::errors::{EiiWithGenerics, LifetimesOrBoundsMismatchOnEII}; /// Checks a bunch of different properties of the impl/trait methods for /// compatibility, such as asyncness, number of argument, self receiver kind, @@ -28,12 +28,31 @@ fn check_is_structurally_compatible<'tcx>( eii_name: Symbol, eii_attr_span: Span, ) -> Result<(), ErrorGuaranteed> { - // FIXME(jdonszelmann): check no generics + check_no_generics(tcx, external_impl, declaration, eii_name, eii_attr_span)?; compare_number_of_method_arguments(tcx, external_impl, declaration, eii_name, eii_attr_span)?; check_region_bounds_on_impl_item(tcx, external_impl, declaration, eii_attr_span)?; Ok(()) } +fn check_no_generics<'tcx>( + tcx: TyCtxt<'tcx>, + external_impl: LocalDefId, + _declaration: DefId, + eii_name: Symbol, + eii_attr_span: Span, +) -> Result<(), ErrorGuaranteed> { + let generics = tcx.generics_of(external_impl); + if generics.own_requires_monomorphization() { + tcx.dcx().emit_err(EiiWithGenerics { + span: tcx.def_span(external_impl), + attr: eii_attr_span, + eii_name, + }); + } + + Ok(()) +} + fn check_region_bounds_on_impl_item<'tcx>( tcx: TyCtxt<'tcx>, external_impl: LocalDefId, @@ -268,6 +287,8 @@ pub(crate) fn compare_eii_function_types<'tcx>( terr, (declaration, declaration_sig), (external_impl, external_impl_sig), + eii_attr_span, + eii_name, ); return Err(emitted); } @@ -299,6 +320,8 @@ fn report_eii_mismatch<'tcx>( terr: TypeError<'tcx>, (declaration_did, declaration_sig): (DefId, ty::FnSig<'tcx>), (external_impl_did, external_impl_sig): (LocalDefId, ty::FnSig<'tcx>), + eii_attr_span: Span, + eii_name: Symbol, ) -> ErrorGuaranteed { let tcx = infcx.tcx; let (impl_err_span, trait_err_span, external_impl_name) = @@ -308,9 +331,12 @@ fn report_eii_mismatch<'tcx>( tcx.dcx(), impl_err_span, E0053, // TODO: new error code - "function `{}` has a type that is incompatible with the declaration", + "function `{}` has a type that is incompatible with the declaration of `#[{eii_name}]`", external_impl_name ); + + diag.span_note(eii_attr_span, "expected this because of this attribute"); + match &terr { TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => { if declaration_sig.inputs().len() == *i { diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index b20adc8c5b8f5..49d90127e5539 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -33,6 +33,7 @@ use rustc_hir::{self as hir, GenericParamKind, HirId, Node, PreciseCapturingArgK use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_middle::hir::nested_filter; +use rustc_middle::middle::eii::EiiMapping; use rustc_middle::query::Providers; use rustc_middle::ty::util::{Discr, IntTypeExt}; use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypingMode, fold_regions}; @@ -1372,6 +1373,16 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn bug!("to get the signature of a closure, use `args.as_closure().sig()` not `fn_sig()`",); } + x @ Synthetic => { + if let Some(EiiMapping { extern_item, .. }) = + tcx.get_externally_implementable_item_impls(()).get(&def_id) + { + return tcx.fn_sig(extern_item); + } else { + bug!("unexpected sort of node in fn_sig(): {:?}", x); + } + } + x => { bug!("unexpected sort of node in fn_sig(): {:?}", x); } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 57e0df61cb074..638ead4a2d520 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -222,6 +222,16 @@ pub(crate) struct LifetimesOrBoundsMismatchOnEII { pub ident: Symbol, } +#[derive(Diagnostic)] +#[diag(hir_analysis_eii_with_generics)] +pub(crate) struct EiiWithGenerics { + #[primary_span] + pub span: Span, + #[label] + pub attr: Span, + pub eii_name: Symbol, +} + #[derive(Diagnostic)] #[diag(hir_analysis_drop_impl_on_wrong_item, code = E0120)] pub(crate) struct DropImplOnWrongItem { diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 4774c31d0c376..3520eb428bc32 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -118,7 +118,7 @@ macro_rules! arena_types { [decode] specialization_graph: rustc_middle::traits::specialization_graph::Graph, [] crate_inherent_impls: rustc_middle::ty::CrateInherentImpls, [] hir_owner_nodes: rustc_hir::OwnerNodes<'tcx>, - [] get_externally_implementable_item_impls: rustc_data_structures::fx::FxIndexMap, + [] get_externally_implementable_item_impls: rustc_middle::middle::eii::EiiMap, ]); ) } diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index fee707f7b4c90..d901e20f1f199 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -19,6 +19,7 @@ use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym, with_metavar_spa use crate::hir::{ModuleItems, nested_filter}; use crate::middle::debugger_visualizer::DebuggerVisualizerFile; +use crate::middle::eii::EiiMapping; use crate::query::LocalCrate; use crate::ty::TyCtxt; @@ -1027,7 +1028,15 @@ impl<'tcx> TyCtxt<'tcx> { Node::Crate(item) => item.spans.inner_span, Node::WherePredicate(pred) => pred.span, Node::PreciseCapturingNonLifetimeArg(param) => param.ident.span, - Node::Synthetic => unreachable!(), + Node::Synthetic => { + if let Some(EiiMapping { chosen_impl, .. }) = + self.tcx.get_externally_implementable_item_impls(()).get(&hir_id.owner.def_id) + { + self.tcx.def_span(chosen_impl) + } else { + unreachable!() + } + } Node::Err(span) => span, } } diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index a28dcb0cb8efd..f563474895f59 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -16,6 +16,7 @@ use rustc_hir::*; use rustc_macros::{Decodable, Encodable, HashStable}; use rustc_span::{ErrorGuaranteed, ExpnId, Span}; +use crate::middle::eii::EiiMapping; use crate::query::Providers; use crate::ty::{EarlyBinder, ImplSubject, TyCtxt}; @@ -223,6 +224,10 @@ pub fn provide(providers: &mut Providers) { }) = tcx.hir_node(tcx.local_def_id_to_hir_id(def_id)) { idents + } else if let Some(EiiMapping { chosen_impl, .. }) = + tcx.get_externally_implementable_item_impls(()).get(&def_id) + { + tcx.fn_arg_names(chosen_impl) } else { span_bug!( tcx.hir_span(tcx.local_def_id_to_hir_id(def_id)), diff --git a/compiler/rustc_middle/src/middle/eii.rs b/compiler/rustc_middle/src/middle/eii.rs new file mode 100644 index 0000000000000..18abcc83e91f8 --- /dev/null +++ b/compiler/rustc_middle/src/middle/eii.rs @@ -0,0 +1,12 @@ +use rustc_data_structures::fx::FxIndexMap; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_macros::{HashStable, TyDecodable, TyEncodable}; + +#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)] +#[derive(TyEncodable, TyDecodable, HashStable)] +pub struct EiiMapping { + pub extern_item: DefId, + pub chosen_impl: DefId, +} + +pub type EiiMap = FxIndexMap; diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs index 4587dcaddc487..707ae98990592 100644 --- a/compiler/rustc_middle/src/middle/mod.rs +++ b/compiler/rustc_middle/src/middle/mod.rs @@ -30,6 +30,7 @@ pub mod lib_features { } } } +pub mod eii; pub mod privacy; pub mod region; pub mod resolve_bound_vars; diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 399f265707921..afd9ad3138747 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -181,8 +181,11 @@ impl<'tcx> MonoItem<'tcx> { return opt_incr_drop_glue_mode(tcx, ty); } - // eii shims are only generated in the final crate. - // As such, they will be both globally shared and unique. + // Eii shims are only generated in the final crate because we need to resolve defaults. + // Specifically, only when making the final crate we know whether there was an explicit + // implementation given *somewhere* and if not we then have to decide whether there is + // a default which we need to insert. That default needs to be shared between all + // dependencies; hence globally shared. if let InstanceKind::EiiShim { .. } = instance.def { return InstantiationMode::GloballyShared { may_conflict: false }; } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index fae0c1cfddc03..53f5114f1fefb 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -52,6 +52,7 @@ use crate::lint::LintExpectation; use crate::metadata::ModChild; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; use crate::middle::debugger_visualizer::DebuggerVisualizerFile; +use crate::middle::eii::EiiMap; use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use crate::middle::lib_features::LibFeatures; use crate::middle::privacy::EffectiveVisibilities; @@ -1114,7 +1115,7 @@ rustc_queries! { desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) } } - query get_externally_implementable_item_impls(_: ()) -> &'tcx rustc_data_structures::fx::FxIndexMap { + query get_externally_implementable_item_impls(_: ()) -> &'tcx EiiMap { desc { "check externally implementable items" } } @@ -1736,11 +1737,6 @@ rustc_queries! { desc { "checking if the crate has_alloc_error_handler" } separate_provide_extern } - query has_panic_handler(_: CrateNum) -> bool { - fatal_cycle - desc { "checking if the crate has_panic_handler" } - separate_provide_extern - } query is_profiler_runtime(_: CrateNum) -> bool { fatal_cycle desc { "checking if a crate is `#![profiler_runtime]`" } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0759fa3da428a..8871c7bb0d244 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -3425,10 +3425,6 @@ pub fn provide(providers: &mut Providers) { |tcx, LocalCrate| contains_name(tcx.hir_krate_attrs(), sym::panic_runtime); providers.is_compiler_builtins = |tcx, LocalCrate| contains_name(tcx.hir_krate_attrs(), sym::compiler_builtins); - providers.has_panic_handler = |tcx, LocalCrate| { - // We want to check if the panic handler was defined in this crate - tcx.lang_items().panic_impl().is_some_and(|did| did.is_local()) - }; providers.source_span = |tcx, def_id| tcx.untracked.source_span.get(def_id).unwrap_or(DUMMY_SP); } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index cdb429c8306d7..25e8cc5fbac44 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -114,22 +114,29 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body< receiver_by_ref, } => build_construct_coroutine_by_move_shim(tcx, coroutine_closure_def_id, receiver_by_ref), - e @ ty::InstanceKind::EiiShim { def_id: _, extern_item: _, chosen_impl } => { + e @ ty::InstanceKind::EiiShim { def_id: _, extern_item, chosen_impl } => { let source = MirSource::from_instance(e); - let fn_sig = tcx.fn_sig(chosen_impl).instantiate_identity().skip_binder(); - let func_ty = Ty::new_fn_def(tcx, chosen_impl, GenericArgs::empty()); + // get the signature for the new function this shim is creating + let shim_fn_sig = tcx.fn_sig(extern_item).instantiate_identity(); + let shim_fn_sig = tcx.instantiate_bound_regions_with_erased(shim_fn_sig); let span = tcx.def_span(chosen_impl); let source_info = SourceInfo::outermost(span); + // we want to generate a call to this function + let args = ty::GenericArgs::identity_for_item(tcx, chosen_impl); + let chosen_fn_ty = Ty::new_fn_def(tcx, chosen_impl, args); + let func = Operand::Constant(Box::new(ConstOperand { span, user_ty: None, - const_: Const::zero_sized(func_ty), + const_: Const::zero_sized(chosen_fn_ty), })); - let locals = local_decls_for_sig(&fn_sig, span); + // println!("generating EII shim for extern item {extern_item:?} and impl {chosen_impl:?}"); + + let locals = local_decls_for_sig(&shim_fn_sig, span); let mut blocks = IndexVec::new(); let return_block = BasicBlock::new(1); @@ -162,7 +169,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body< is_cleanup: false, }); - new_body(source, blocks, locals, fn_sig.inputs().len(), span) + new_body(source, blocks, locals, shim_fn_sig.inputs().len(), span) } ty::InstanceKind::DropGlue(def_id, ty) => { diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 620d268de6f49..9aa3819cd871f 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -208,7 +208,7 @@ use std::cell::OnceCell; use std::path::PathBuf; -use rustc_attr_parsing::{AttributeKind, EIIDecl, InlineAttr, find_attr}; +use rustc_attr_parsing::InlineAttr; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::{MTLock, par_for_each_in}; use rustc_data_structures::unord::{UnordMap, UnordSet}; @@ -217,6 +217,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::middle::eii::EiiMapping; use rustc_middle::mir::interpret::{AllocId, ErrorHandled, GlobalAlloc, Scalar}; use rustc_middle::mir::mono::{CollectionMode, InstantiationMode, MonoItem}; use rustc_middle::mir::visit::Visitor as MirVisitor; @@ -1613,26 +1614,20 @@ impl<'v> RootCollector<'_, 'v> { /// For each externally implementable item, we should generate an alias MonoItem that /// determines what implementation is called. This could be a default implementation. fn push_extra_eii_roots(&mut self) { - for (decl, (chosen_impl, shim_did)) in self.tcx.get_externally_implementable_item_impls(()) + for (shim_did, &EiiMapping { extern_item, chosen_impl, .. }) in + self.tcx.get_externally_implementable_item_impls(()) { - let Some((eii_extern_item, span)) = find_attr!( - self.tcx.get_all_attrs(*decl), - AttributeKind::EiiMacroFor(EIIDecl { eii_extern_item, span, .. }) => (*eii_extern_item, *span) - ) else { - bug!("missing attr on EII macro"); - }; - self.output.push(create_fn_mono_item( self.tcx, ty::Instance { def: ty::InstanceKind::EiiShim { def_id: (*shim_did).into(), - extern_item: eii_extern_item, - chosen_impl: *chosen_impl, + extern_item, + chosen_impl, }, args: ty::GenericArgs::empty(), }, - span, + DUMMY_SP, )); } } diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 6bf783fa7ecab..e5bba35008d65 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -115,7 +115,7 @@ use rustc_middle::mir::mono::{ MonoItemPartitions, Visibility, }; use rustc_middle::ty::print::{characteristic_def_id_of_type, with_no_trimmed_paths}; -use rustc_middle::ty::{self, InstanceKind, TyCtxt}; +use rustc_middle::ty::{self, Instance, InstanceKind, TyCtxt}; use rustc_middle::util::Providers; use rustc_session::CodegenUnits; use rustc_session::config::{DumpMonoStatsFormat, SwitchWithOptPath}; @@ -755,6 +755,7 @@ fn mono_item_linkage_and_visibility<'tcx>( if let Some(explicit_linkage) = mono_item.explicit_linkage(tcx) { return (explicit_linkage, Visibility::Default); } + let vis = mono_item_visibility( tcx, mono_item, @@ -762,7 +763,18 @@ fn mono_item_linkage_and_visibility<'tcx>( can_export_generics, always_export_generics, ); - (Linkage::External, vis) + + // The check for EII implementations and their defaults is also done in shared and static + // libraries. And shared libraries may later be linked together, both implementing the EII. + // This conflicting implementations may show up. We want to ignore this and just link em + // together anyway. LLVM ensures the last one is the one that's chosen + // TODO: this isn't the problem if they both decided to choose either the default or the + // same explicit impl but if their view on it differs it is a problem! + if let MonoItem::Fn(Instance { def: InstanceKind::EiiShim { .. }, .. }) = mono_item { + (Linkage::WeakAny, vis) + } else { + (Linkage::External, vis) + } } type CguNameCache = UnordMap<(DefId, bool), Symbol>; @@ -806,6 +818,7 @@ fn mono_item_visibility<'tcx>( | InstanceKind::AsyncDropGlueCtorShim(def_id, _) => def_id, InstanceKind::EiiShim { .. } => { + *can_be_internalized = false; // Out of the three visibilities, only Default makes symbols visible outside the current // DSO. For EIIs this is explicitly the intended visibilty. If another DSO is refering // to an extern item, the implementation may be generated downstream. That symbol does diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index e1a190484528d..1607387196119 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -322,6 +322,14 @@ passes_duplicate_lang_item_crate_depends = .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} .second_definition_path = second definition in `{$crate_name}` loaded from {$path} +passes_eii_fn_with_target_feature = + `#[{$name}]` is not allowed to have `#[target_feature]` + .label = `#[{$name}]` is not allowed to have `#[target_feature]` + +passes_eii_fn_with_track_caller = + `#[{$name}]` is not allowed to have `#[track_caller]` + .label = `#[{$name}]` is not allowed to have `#[track_caller]` + passes_eii_impl_not_function = `eii_macro_for` is only valid on functions @@ -330,8 +338,8 @@ passes_eii_impl_requires_unsafe = passes_eii_impl_requires_unsafe_suggestion = wrap the attribute in `unsafe(...)` passes_eii_without_impl = - couldn't find an implementation for `#[{$name}]` - .label = an implementation was expected by this declaration + `#[{$name}]` required, but not found + .label = expected because `#[{$name}]` was declared here in crate `{$decl_crate_name}` .help = expected at least one implementation in crate `{$current_crate_name}` or any of its dependencies passes_export_name = attribute should be applied to a free function, impl method or static @@ -437,14 +445,6 @@ passes_lang_item_fn = {$name -> *[other] `{$name}` lang item } function -passes_lang_item_fn_with_target_feature = - {passes_lang_item_fn} is not allowed to have `#[target_feature]` - .label = {passes_lang_item_fn} is not allowed to have `#[target_feature]` - -passes_lang_item_fn_with_track_caller = - {passes_lang_item_fn} is not allowed to have `#[track_caller]` - .label = {passes_lang_item_fn} is not allowed to have `#[track_caller]` - passes_lang_item_on_incorrect_target = `{$name}` lang item must be applied to a {$expected_target} .label = attribute should be applied to a {$expected_target}, not a {$actual_target} @@ -513,9 +513,6 @@ passes_missing_lang_item = .note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library .help = you may be able to compile for a target that doesn't need `{$name}`, specify a target with `--target` or in `.cargo/config` -passes_missing_panic_handler = - `#[panic_handler]` function required, but not found - passes_missing_stability_attr = {$descr} has missing stability attribute diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 5abdb68b63ff7..ee4870e1c9c93 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -803,12 +803,23 @@ impl<'tcx> CheckAttrVisitor<'tcx> { { let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap(); - self.dcx().emit_err(errors::LangItemWithTrackCaller { + self.dcx().emit_err(errors::EiiWithTrackCaller { attr_span, name: lang_item, sig_span: sig.span, }); } + + if let Some(impls) = find_attr!(attrs, AttributeKind::EiiImpl(impls) => impls) { + let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap(); + for i in impls { + self.dcx().emit_err(errors::EiiWithTrackCaller { + attr_span, + name: self.tcx.item_name(i.eii_macro), + sig_span: sig.span, + }); + } + } } Target::Method(..) | Target::ForeignFn | Target::Closure => {} // FIXME(#80564): We permit struct fields, match arms and macro defs to have an @@ -912,12 +923,23 @@ impl<'tcx> CheckAttrVisitor<'tcx> { { let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap(); - self.dcx().emit_err(errors::LangItemWithTargetFeature { + self.dcx().emit_err(errors::EiiWithTargetFeature { attr_span: attr.span(), name: lang_item, sig_span: sig.span, }); } + + if let Some(impls) = find_attr!(attrs, AttributeKind::EiiImpl(impls) => impls) { + let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap(); + for i in impls { + self.dcx().emit_err(errors::EiiWithTargetFeature { + attr_span: attr.span(), + name: self.tcx.item_name(i.eii_macro), + sig_span: sig.span, + }); + } + } } // FIXME: #[target_feature] was previously erroneously allowed on statements and some // crates used this, so only emit a warning. diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 0060e726a8e05..b28a168903f52 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -8,6 +8,7 @@ use std::mem; use hir::ItemKind; use hir::def_id::{LocalDefIdMap, LocalDefIdSet}; use rustc_abi::FieldIdx; +use rustc_attr_parsing::{AttributeKind, find_attr}; use rustc_data_structures::unord::UnordSet; use rustc_errors::MultiSpan; use rustc_hir::def::{CtorOf, DefKind, Res}; @@ -814,6 +815,12 @@ fn check_item<'tcx>( // global_asm! is always live. worklist.push((id.owner_id.def_id, ComesFromAllowExpect::No)); } + DefKind::Fn => { + // Implementations of EII are always considered live. + if find_attr!(tcx.get_all_attrs(id.owner_id.def_id), AttributeKind::EiiImpl(_)) { + worklist.push((id.owner_id.def_id, ComesFromAllowExpect::No)); + } + } _ => {} } } diff --git a/compiler/rustc_passes/src/eii.rs b/compiler/rustc_passes/src/eii.rs index 55214367bd79f..89cff3405b868 100644 --- a/compiler/rustc_passes/src/eii.rs +++ b/compiler/rustc_passes/src/eii.rs @@ -2,11 +2,12 @@ use std::iter; -use rustc_attr_parsing::EIIImpl; +use rustc_attr_parsing::{EIIDecl, EIIImpl}; use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::definitions::DisambiguatorState; +use rustc_middle::middle::eii::EiiMapping; use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; use rustc_span::Symbol; @@ -17,19 +18,33 @@ use crate::errors::{DuplicateEiiImpls, EiiWithoutImpl}; /// chosen. This could be a default implementation if no explicit implementation is found. /// /// The returned map maps the defid of declaration macros to the defid of implementations. -pub(crate) fn get_eii_impls<'tcx>( +pub(crate) fn get_externally_implementable_item_impls<'tcx>( tcx: TyCtxt<'tcx>, (): (), -) -> &'tcx FxIndexMap { +) -> &'tcx FxIndexMap { // We only need to check whether there are duplicate or missing EIIs if we're // emitting something that's not an rlib. let needs_check = tcx.crate_types().iter().any(|kind| match *kind { - CrateType::Dylib - | CrateType::ProcMacro - | CrateType::Cdylib - | CrateType::Executable - | CrateType::Staticlib - | CrateType::Sdylib => true, + // Executables are leafs of the crate graph and need all EIIs to be satisfied, + // either with defaults or explicit implementations. So they check their crate + // graph to make sure this is the case. + CrateType::Executable => true, + // Proc macros are leafs of their crate graph and will be run, + // and so need to check the EIIs of their dependencies. + CrateType::ProcMacro => true, + + // These are a litte difficult. We don't know whether things depending on these + // will perform checks to see if EIIs are implemented, or duplicated, or any other + // of the checks performed in this function. So we must do the checks. However, + // this can later lead to duplicate symbols when linking them together. + // For this reason, we later mark EII symbols as "globally shared" and "may conflict". + // In other words, if two shared libraries both provide an implementation for an EII, + // that's fine! Just choose one... And because their mangled symbol names are the same + // (that's exactly the conflict we're having) we hopefully have the same exact implementation. + CrateType::Dylib | CrateType::Cdylib | CrateType::Staticlib | CrateType::Sdylib => true, + + // Rlibs are just a step in the crate graph. + // Later on we'll link it together into an executable and over there we can check for EIIs CrateType::Rlib => false, }); if !needs_check { @@ -38,7 +53,8 @@ pub(crate) fn get_eii_impls<'tcx>( return &*tcx.arena.alloc(FxIndexMap::default()); } - let mut eiis = FxIndexMap::<_, (_, FxIndexMap)>::default(); + let mut eiis = + FxIndexMap::)>::default(); // println!("current crate: {}", tcx.crate_name(LOCAL_CRATE)); @@ -50,9 +66,9 @@ pub(crate) fn get_eii_impls<'tcx>( // update or insert the corresponding entries for (did, (decl, impls)) in crate_eiis { - eiis.entry(did) - .or_insert_with(|| (decl, Default::default())) - .1 + eiis.entry(*did) + .or_insert_with(|| (*decl, cnum, Default::default())) + .2 .extend(impls.into_iter().map(|(did, i)| (*did, (*i, cnum)))); } } @@ -61,7 +77,7 @@ pub(crate) fn get_eii_impls<'tcx>( // now we have all eiis! For each of them, choose one we want to actually generate. - for (decl_did, (decl, impls)) in eiis { + for (decl_did, (decl, decl_crate, impls)) in eiis { // println!("for decl: {decl_did:?}: {decl:?}"); let mut default_impls = Vec::new(); let mut explicit_impls = Vec::new(); @@ -78,7 +94,7 @@ pub(crate) fn get_eii_impls<'tcx>( if explicit_impls.len() > 1 { tcx.dcx().emit_err(DuplicateEiiImpls { - name: tcx.item_name(*decl_did), + name: tcx.item_name(decl_did), first_span: tcx.def_span(explicit_impls[0].0), first_crate: tcx.crate_name(explicit_impls[0].1), second_span: tcx.def_span(explicit_impls[1].0), @@ -111,20 +127,30 @@ pub(crate) fn get_eii_impls<'tcx>( None, &mut DisambiguatorState::new(), ); - feed.generics_of(tcx.generics_of(*chosen_impl).clone()); - feed.type_of(tcx.type_of(*chosen_impl).clone()); - feed.def_span(tcx.def_span(*chosen_impl)); + + let extern_item_did = decl.eii_extern_item; + + feed.generics_of(tcx.generics_of(extern_item_did).clone()); + feed.type_of(tcx.type_of(extern_item_did).clone()); + feed.def_span(tcx.def_span(chosen_impl)); + feed.visibility(tcx.visibility(chosen_impl)); feed.feed_hir(); + // println!("generating {extern_item_did:?} for impl {chosen_impl:?} in crate {} with did {decl_did:?}", tcx.crate_name(LOCAL_CRATE)); + let shim_did = feed.def_id(); // println!("shim: {shim_did:?}"); - final_impls.insert(*decl_did, (*chosen_impl, shim_did)); + final_impls.insert( + shim_did, + EiiMapping { extern_item: extern_item_did, chosen_impl: *chosen_impl }, + ); } else { tcx.dcx().emit_err(EiiWithoutImpl { current_crate_name: tcx.crate_name(LOCAL_CRATE), - name: tcx.item_name(*decl_did), + decl_crate_name: tcx.crate_name(decl_crate), + name: tcx.item_name(decl_did), span: decl.span, help: (), }); diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index b95d8798e1496..5ec63d3871c6f 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -881,8 +881,8 @@ pub(crate) struct MissingLangItem { } #[derive(Diagnostic)] -#[diag(passes_lang_item_fn_with_track_caller)] -pub(crate) struct LangItemWithTrackCaller { +#[diag(passes_eii_fn_with_track_caller)] +pub(crate) struct EiiWithTrackCaller { #[primary_span] pub attr_span: Span, pub name: Symbol, @@ -891,8 +891,8 @@ pub(crate) struct LangItemWithTrackCaller { } #[derive(Diagnostic)] -#[diag(passes_lang_item_fn_with_target_feature)] -pub(crate) struct LangItemWithTargetFeature { +#[diag(passes_eii_fn_with_target_feature)] +pub(crate) struct EiiWithTargetFeature { #[primary_span] pub attr_span: Span, pub name: Symbol, @@ -2012,6 +2012,7 @@ pub(crate) struct EiiWithoutImpl { pub name: Symbol, pub current_crate_name: Symbol, + pub decl_crate_name: Symbol, #[help] pub help: (), } diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 58383005de1b4..d03d28d2cd2c4 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -57,5 +57,6 @@ pub fn provide(providers: &mut Providers) { stability::provide(providers); upvars::provide(providers); check_export::provide(providers); - providers.get_externally_implementable_item_impls = eii::get_eii_impls; + providers.get_externally_implementable_item_impls = + eii::get_externally_implementable_item_impls; } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index e338780e6885e..2bdf679047fbc 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -179,7 +179,9 @@ impl<'tcx> ReachableContext<'tcx> { if !self.any_library { // If we are building an executable, only explicitly extern // types need to be exported. - let codegen_attrs = if self.tcx.def_kind(search_item).has_codegen_attrs() { + let def_kind = self.tcx.def_kind(search_item); + + let codegen_attrs = if def_kind.has_codegen_attrs() { self.tcx.codegen_fn_attrs(search_item) } else { CodegenFnAttrs::EMPTY @@ -190,7 +192,11 @@ impl<'tcx> ReachableContext<'tcx> { // crate whether we do or don't need to codegen them so it'd be a shame if they got // filtered out here already. let eii_impl = - find_attr!(self.tcx.get_all_attrs(search_item), AttributeKind::EiiImpl(_)); + find_attr!(self.tcx.get_all_attrs(search_item), AttributeKind::EiiImpl(_)) + || self + .tcx + .get_externally_implementable_item_impls(()) + .contains_key(&search_item); if is_extern || eii_impl { self.reachable_symbols.insert(search_item); @@ -389,20 +395,12 @@ impl<'tcx> DefIdVisitor<'tcx> for ReachableContext<'tcx> { } } -fn check_item<'tcx>( +fn check_trait_item<'tcx>( tcx: TyCtxt<'tcx>, id: hir::ItemId, worklist: &mut Vec, effective_visibilities: &privacy::EffectiveVisibilities, ) { - if has_custom_linkage(tcx, id.owner_id.def_id) { - worklist.push(id.owner_id.def_id); - } - - if !matches!(tcx.def_kind(id.owner_id), DefKind::Impl { of_trait: true }) { - return; - } - // We need only trait impls here, not inherent impls, and only non-exported ones if effective_visibilities.is_reachable(id.owner_id.def_id) { return; @@ -423,6 +421,29 @@ fn check_item<'tcx>( .extend(tcx.provided_trait_methods(trait_def_id).map(|assoc| assoc.def_id.expect_local())); } +fn check_item<'tcx>( + tcx: TyCtxt<'tcx>, + id: hir::ItemId, + worklist: &mut Vec, + effective_visibilities: &privacy::EffectiveVisibilities, +) { + if has_custom_linkage(tcx, id.owner_id.def_id) { + worklist.push(id.owner_id.def_id); + } + + match tcx.def_kind(id.owner_id) { + DefKind::Impl { of_trait: true } => { + check_trait_item(tcx, id, worklist, effective_visibilities) + } + DefKind::Fn => { + if find_attr!(tcx.get_all_attrs(id.owner_id.def_id), AttributeKind::EiiImpl(_)) { + worklist.push(id.owner_id.def_id); + } + } + _ => {} + } +} + fn has_custom_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { // Anything which has custom linkage gets thrown on the worklist no // matter where it is in the crate, along with "special std symbols" @@ -474,6 +495,12 @@ fn reachable_set(tcx: TyCtxt<'_>, (): ()) -> LocalDefIdSet { reachable_context.worklist.push(def_id); } } + + // make sure eii shims are also kept + for shim_did in tcx.get_externally_implementable_item_impls(()).keys() { + reachable_context.worklist.push(*shim_did); + } + { // As explained above, we have to mark all functions called from reachable // `item_might_be_inlined` items as reachable. The issue is, when those functions are @@ -485,6 +512,9 @@ fn reachable_set(tcx: TyCtxt<'_>, (): ()) -> LocalDefIdSet { // trait is a lang item. // (But if you implement this, don't forget to take into account that vtables can also // make trait methods reachable!) + // + // Pretty much the same logic holds for EII implementations. We don't know what crate might + // call them so we must mark them all as used. let crate_items = tcx.hir_crate_items(()); for id in crate_items.free_items() { @@ -496,15 +526,6 @@ fn reachable_set(tcx: TyCtxt<'_>, (): ()) -> LocalDefIdSet { reachable_context.worklist.push(id.owner_id.def_id); } } - - // TODO: make a query for getting EIIs, this is probably expensive while we can do easily - // add the (relatively few) EIIs to a separate list and make a query for them in another pass somewhere - for id in crate_items.definitions() { - // if something implements an EII, it's automatically reachable - if find_attr!(tcx.get_all_attrs(id), AttributeKind::EiiImpl(..)) { - reachable_context.worklist.push(id); - } - } } // Step 2: Mark all symbols that the symbols on the worklist touch. diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 0b695e7efa986..d0418a49eb3f4 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -99,6 +99,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; +use rustc_middle::middle::eii::EiiMapping; use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, Instance, TyCtxt}; @@ -262,8 +263,9 @@ fn compute_symbol_name<'tcx>( // but when we generate a symbol for it the name must actually match the name of the extern // generated as part of the declaration of the EII. So, we use an instance of `extern_item` as // the instance used for ocmputing the symbol name. - let instance = if let ty::InstanceKind::EiiShim { def_id: _, extern_item, chosen_impl: _ } = - instance.def + let eii_map = tcx.get_externally_implementable_item_impls(()); + let instance = if let Some(EiiMapping { extern_item, .. }) = + instance.def_id().as_local().and_then(|x| eii_map.get(&x)).copied() { Instance::mono(tcx, extern_item) } else { From 7f09bd9266bbe35ede2f8598090f62f724f4a1f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 18 Apr 2025 08:11:32 +0200 Subject: [PATCH 32/41] fix tests --- compiler/rustc_hir_typeck/src/check.rs | 1 - compiler/rustc_metadata/src/rmeta/decoder.rs | 3 +-- .../src/rmeta/decoder/cstore_impl.rs | 1 - compiler/rustc_metadata/src/rmeta/encoder.rs | 1 - compiler/rustc_metadata/src/rmeta/mod.rs | 1 - compiler/rustc_middle/src/hir/map.rs | 4 ++-- compiler/rustc_middle/src/hir/mod.rs | 2 +- compiler/rustc_passes/src/errors.rs | 4 ---- compiler/rustc_passes/src/weak_lang_items.rs | 8 ++----- compiler/rustc_resolve/src/check_unused.rs | 1 - tests/ui/cfg/cfg_false_no_std-2.rs | 5 +++- tests/ui/eii/privacy2.rs | 4 ++-- tests/ui/eii/privacy2.stderr | 8 +++---- tests/ui/eii/subtype_1.rs | 3 +-- tests/ui/eii/subtype_1.stderr | 4 ++-- tests/ui/eii/subtype_2.rs | 2 +- tests/ui/eii/subtype_2.stderr | 2 +- tests/ui/eii/wrong_ret_ty.stderr | 7 +++++- tests/ui/eii/wrong_ty.stderr | 7 +++++- .../error-codes/E0152-duplicate-lang-items.rs | 9 ++++---- .../E0152-duplicate-lang-items.stderr | 8 +++---- tests/ui/extern-flag/empty-extern-arg.stderr | 9 ++++++-- tests/ui/extern-flag/no-force-extern.rs | 2 +- .../start_lang_item_with_target_feature.rs | 2 +- ...start_lang_item_with_target_feature.stderr | 4 ++-- tests/ui/macros/macro-comma-behavior.rs | 2 +- .../panic-handler-bad-signature-1.rs | 2 +- .../panic-handler-bad-signature-1.stderr | 16 ++++++++++--- .../panic-handler-bad-signature-2.rs | 2 +- .../panic-handler-bad-signature-2.stderr | 4 ++-- .../panic-handler-bad-signature-3.rs | 2 +- .../panic-handler-bad-signature-3.stderr | 12 ++++++---- .../panic-handler-bad-signature-4.rs | 2 +- .../panic-handler-bad-signature-4.stderr | 4 +++- .../panic-handler-bad-signature-5.rs | 2 +- .../panic-handler-bad-signature-5.stderr | 4 ++-- .../panic-handler/panic-handler-duplicate.rs | 17 -------------- .../panic-handler-duplicate.stderr | 19 --------------- .../ui/panic-handler/panic-handler-missing.rs | 3 +-- .../panic-handler-requires-panic-info.rs | 2 +- .../panic-handler-requires-panic-info.stderr | 8 +++---- tests/ui/panic-handler/panic-handler-std.rs | 2 +- .../ui/panic-handler/panic-handler-std.stderr | 2 +- tests/ui/panic-handler/panic-handler-twice.rs | 3 ++- .../panic-handler-with-target-feature.rs | 3 ++- .../panic-handler-with-target-feature.stderr | 23 ++++++++++++++++--- .../panic-handler-with-track-caller.rs | 2 +- .../panic-handler-with-track-caller.stderr | 4 ++-- .../panic-handler-wrong-location.rs | 5 ++-- .../panic-handler-wrong-location.stderr | 12 ++++++---- tests/ui/panic-handler/weak-lang-item.rs | 2 +- tests/ui/panic-handler/weak-lang-item.stderr | 9 ++++++-- .../auxiliary/panic-runtime-lang-items.rs | 2 +- .../issue-59191-replace-root-with-fn.rs | 2 +- .../issue-59191-replace-root-with-fn.stderr | 9 ++++++-- tests/ui/recursion_limit/zero-overflow.rs | 4 +++- tests/ui/recursion_limit/zero-overflow.stderr | 7 +++++- 57 files changed, 157 insertions(+), 137 deletions(-) delete mode 100644 tests/ui/panic-handler/panic-handler-duplicate.rs delete mode 100644 tests/ui/panic-handler/panic-handler-duplicate.stderr diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 8d1d432ffd957..b0c6a993e5efb 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -1,7 +1,6 @@ use std::cell::RefCell; use rustc_abi::ExternAbi; -use rustc_hir::def::DefKind; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_hir_analysis::check::check_function_signature; diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 432599cc88aba..36ad4fea3a7a2 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -782,10 +782,9 @@ impl MetadataBlob { )?; writeln!( out, - "has_global_allocator {} has_alloc_error_handler {} has_panic_handler {} has_default_lib_allocator {}", + "has_global_allocator {} has_alloc_error_handler {} has_default_lib_allocator {}", root.has_global_allocator, root.has_alloc_error_handler, - root.has_panic_handler, root.has_default_lib_allocator )?; writeln!( diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 4aadc3e2df6f4..79e18fe790ffd 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -348,7 +348,6 @@ provide! { tcx, def_id, other, cdata, is_compiler_builtins => { cdata.root.compiler_builtins } has_global_allocator => { cdata.root.has_global_allocator } has_alloc_error_handler => { cdata.root.has_alloc_error_handler } - has_panic_handler => { cdata.root.has_panic_handler } is_profiler_runtime => { cdata.root.profiler_runtime } required_panic_strategy => { cdata.root.required_panic_strategy } panic_in_drop_strategy => { cdata.root.panic_in_drop_strategy } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 9ad6cf1d9ac0a..f2aa9cd1a8940 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -716,7 +716,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { edition: tcx.sess.edition(), has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE), has_alloc_error_handler: tcx.has_alloc_error_handler(LOCAL_CRATE), - has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE), externally_implementable_items, has_default_lib_allocator: ast::attr::contains_name( diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 8a26b9911965f..af37f811a60c6 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -261,7 +261,6 @@ pub(crate) struct CrateRoot { // TODO: these booleans can be replaced by the entries in `externally_implementable_items` has_global_allocator: bool, has_alloc_error_handler: bool, - has_panic_handler: bool, has_default_lib_allocator: bool, externally_implementable_items: LazyArray<(DefId, (EIIDecl, Vec<(DefId, EIIImpl)>))>, diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index d901e20f1f199..400f272772cd2 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -1030,9 +1030,9 @@ impl<'tcx> TyCtxt<'tcx> { Node::PreciseCapturingNonLifetimeArg(param) => param.ident.span, Node::Synthetic => { if let Some(EiiMapping { chosen_impl, .. }) = - self.tcx.get_externally_implementable_item_impls(()).get(&hir_id.owner.def_id) + self.get_externally_implementable_item_impls(()).get(&hir_id.owner.def_id) { - self.tcx.def_span(chosen_impl) + self.def_span(chosen_impl) } else { unreachable!() } diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index f563474895f59..044c2d8b6b169 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -227,7 +227,7 @@ pub fn provide(providers: &mut Providers) { } else if let Some(EiiMapping { chosen_impl, .. }) = tcx.get_externally_implementable_item_impls(()).get(&def_id) { - tcx.fn_arg_names(chosen_impl) + tcx.fn_arg_idents(chosen_impl) } else { span_bug!( tcx.hir_span(tcx.local_def_id_to_hir_id(def_id)), diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 5ec63d3871c6f..b71697538b701 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -862,10 +862,6 @@ pub(crate) struct UnknownExternLangItem { pub lang_item: Symbol, } -#[derive(Diagnostic)] -#[diag(passes_missing_panic_handler)] -pub(crate) struct MissingPanicHandler; - #[derive(Diagnostic)] #[diag(passes_panic_unwind_without_std)] #[help] diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 93d164e7d01f8..9534d7103c9c7 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -9,9 +9,7 @@ use rustc_middle::middle::lang_items::required; use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; -use crate::errors::{ - MissingLangItem, MissingPanicHandler, PanicUnwindWithoutStd, UnknownExternLangItem, -}; +use crate::errors::{MissingLangItem, PanicUnwindWithoutStd, UnknownExternLangItem}; /// Checks the crate for usage of weak lang items, returning a vector of all the /// lang items required by this crate, but not defined yet. @@ -84,9 +82,7 @@ fn verify(tcx: TyCtxt<'_>, items: &lang_items::LanguageItems) { for &item in WEAK_LANG_ITEMS.iter() { if missing.contains(&item) && required(tcx, item) && items.get(item).is_none() { - if item == LangItem::PanicImpl { - tcx.dcx().emit_err(MissingPanicHandler); - } else if item == LangItem::EhPersonality { + if item == LangItem::EhPersonality { tcx.dcx().emit_err(PanicUnwindWithoutStd); } else { tcx.dcx().emit_err(MissingLangItem { name: item.name() }); diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index e97233e97ce55..a005be3eb380c 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -402,7 +402,6 @@ impl Resolver<'_, '_> { !tcx.is_compiler_builtins(cnum) && !tcx.is_panic_runtime(cnum) && !tcx.has_global_allocator(cnum) - && !tcx.has_panic_handler(cnum) }) { maybe_unused_extern_crates.insert(id, import.span); } diff --git a/tests/ui/cfg/cfg_false_no_std-2.rs b/tests/ui/cfg/cfg_false_no_std-2.rs index 666c90deaf0f4..efba9b0879424 100644 --- a/tests/ui/cfg/cfg_false_no_std-2.rs +++ b/tests/ui/cfg/cfg_false_no_std-2.rs @@ -14,4 +14,7 @@ extern crate cfg_false_lib_no_std_before as _; fn main() {} -//~? ERROR `#[panic_handler]` function required, but not found +//~? ERROR `#[panic_handler]` required, but not found +// FIXME: This error is target-dependent, could be served by some "optional error" annotation +// instead of `dont-require-annotations`. +//FIXME~? ERROR unwinding panics are not supported without std diff --git a/tests/ui/eii/privacy2.rs b/tests/ui/eii/privacy2.rs index 88d174a48f6d4..ec6405c11d2a4 100644 --- a/tests/ui/eii/privacy2.rs +++ b/tests/ui/eii/privacy2.rs @@ -4,8 +4,8 @@ extern crate codegen3 as codegen; // has a span but in the other crate -//~? ERROR couldn't find an implementation for `#[eii2]` -//~? ERROR couldn't find an implementation for `#[eii3]` +//~? ERROR `#[eii2]` required, but not found +//~? ERROR `#[eii3]` required, but not found #[codegen::eii1] fn eii1_impl(x: u64) { diff --git a/tests/ui/eii/privacy2.stderr b/tests/ui/eii/privacy2.stderr index ac4a5dca749b2..a2e0977542a40 100644 --- a/tests/ui/eii/privacy2.stderr +++ b/tests/ui/eii/privacy2.stderr @@ -16,19 +16,19 @@ note: the function `decl1` is defined here LL | fn decl1(x: u64); | ^^^^^^^^^^^^^^^^^ -error: couldn't find an implementation for `#[eii2]` +error: `#[eii2]` required, but not found --> $DIR/auxiliary/codegen3.rs:9:1 | LL | #[eii(eii2)] - | ^^^^^^^^^^^^ an implementation was expected by this declaration + | ^^^^^^^^^^^^ expected because `#[eii2]` was declared here in crate `codegen3` | = help: expected at least one implementation in crate `privacy2` or any of its dependencies -error: couldn't find an implementation for `#[eii3]` +error: `#[eii3]` required, but not found --> $DIR/auxiliary/codegen3.rs:13:5 | LL | #[eii(eii3)] - | ^^^^^^^^^^^^ an implementation was expected by this declaration + | ^^^^^^^^^^^^ expected because `#[eii3]` was declared here in crate `codegen3` | = help: expected at least one implementation in crate `privacy2` or any of its dependencies diff --git a/tests/ui/eii/subtype_1.rs b/tests/ui/eii/subtype_1.rs index 67f0923cabd25..f50c87887fe8a 100644 --- a/tests/ui/eii/subtype_1.rs +++ b/tests/ui/eii/subtype_1.rs @@ -1,5 +1,4 @@ //@ compile-flags: --crate-type rlib -//FIXME: known ICE #![feature(eii)] #![feature(decl_macro)] #![feature(rustc_attrs)] @@ -17,7 +16,7 @@ unsafe extern "Rust" { #[foo] fn other<'a, 'b>(x: &'b u64) -> &'b u64 { -//~^ ERROR lifetime parameters or bounds `other` do not match the declaration +//~^ ERROR lifetime parameters or bounds of `other` do not match the declaration &0 } diff --git a/tests/ui/eii/subtype_1.stderr b/tests/ui/eii/subtype_1.stderr index cf20150b74f7b..6a4ef6e16f9db 100644 --- a/tests/ui/eii/subtype_1.stderr +++ b/tests/ui/eii/subtype_1.stderr @@ -1,5 +1,5 @@ -error: lifetime parameters or bounds `other` do not match the declaration - --> $DIR/subtype_1.rs:19:9 +error: lifetime parameters or bounds of `other` do not match the declaration + --> $DIR/subtype_1.rs:18:9 | LL | safe fn bar<'a, 'b>(x: &'b u64) -> &'a u64; | -------- lifetimes in impl do not match this signature diff --git a/tests/ui/eii/subtype_2.rs b/tests/ui/eii/subtype_2.rs index be6482c9cd8d7..e771fb7182552 100644 --- a/tests/ui/eii/subtype_2.rs +++ b/tests/ui/eii/subtype_2.rs @@ -16,7 +16,7 @@ unsafe extern "Rust" { #[foo] fn other<'a>(x: &'a u64) -> &'static u64 { -//~^ ERROR lifetime parameters or bounds `other` do not match the declaration +//~^ ERROR lifetime parameters or bounds of `other` do not match the declaration &0 } diff --git a/tests/ui/eii/subtype_2.stderr b/tests/ui/eii/subtype_2.stderr index f10d786776ad9..5c925ca380e01 100644 --- a/tests/ui/eii/subtype_2.stderr +++ b/tests/ui/eii/subtype_2.stderr @@ -1,4 +1,4 @@ -error: lifetime parameters or bounds `other` do not match the declaration +error: lifetime parameters or bounds of `other` do not match the declaration --> $DIR/subtype_2.rs:18:9 | LL | safe fn bar<'a>(x: &'static u64) -> &'a u64; diff --git a/tests/ui/eii/wrong_ret_ty.stderr b/tests/ui/eii/wrong_ret_ty.stderr index c84de5e6e11ed..2cdd69bbdbdf0 100644 --- a/tests/ui/eii/wrong_ret_ty.stderr +++ b/tests/ui/eii/wrong_ret_ty.stderr @@ -1,9 +1,14 @@ -error[E0053]: function `other` has a type that is incompatible with the declaration +error[E0053]: function `other` has a type that is incompatible with the declaration of `#[foo]` --> $DIR/wrong_ret_ty.rs:18:18 | LL | fn other(_x: u64) { | ^ expected `u64`, found `()` | +note: expected this because of this attribute + --> $DIR/wrong_ret_ty.rs:17:1 + | +LL | #[foo] + | ^^^^^^ note: type in declaration --> $DIR/wrong_ret_ty.rs:14:28 | diff --git a/tests/ui/eii/wrong_ty.stderr b/tests/ui/eii/wrong_ty.stderr index e64d4756d0cae..fae713a35aa96 100644 --- a/tests/ui/eii/wrong_ty.stderr +++ b/tests/ui/eii/wrong_ty.stderr @@ -1,9 +1,14 @@ -error[E0053]: function `other` has a type that is incompatible with the declaration +error[E0053]: function `other` has a type that is incompatible with the declaration of `#[foo]` --> $DIR/wrong_ty.rs:18:13 | LL | fn other(x: usize) -> u64 { | ^^^^^ expected `u64`, found `usize` | +note: expected this because of this attribute + --> $DIR/wrong_ty.rs:17:1 + | +LL | #[foo] + | ^^^^^^ note: type in declaration --> $DIR/wrong_ty.rs:14:20 | diff --git a/tests/ui/error-codes/E0152-duplicate-lang-items.rs b/tests/ui/error-codes/E0152-duplicate-lang-items.rs index f707b72f9b2b5..1faa8d6f4f919 100644 --- a/tests/ui/error-codes/E0152-duplicate-lang-items.rs +++ b/tests/ui/error-codes/E0152-duplicate-lang-items.rs @@ -3,19 +3,18 @@ //! //! Issue: -//@ normalize-stderr: "loaded from .*libstd-.*.rlib" -> "loaded from SYSROOT/libstd-*.rlib" +//@ normalize-stderr: "loaded from .*libcore-.*.rlib" -> "loaded from SYSROOT/libcore-*.rlib" //@ dont-require-annotations: NOTE - #![feature(lang_items)] extern crate core; use core::panic::PanicInfo; -#[lang = "panic_impl"] +#[lang = "panic_cannot_unwind"] fn panic_impl(info: &PanicInfo) -> ! { - //~^ ERROR: found duplicate lang item `panic_impl` - //~| NOTE first defined in crate `std` + //~^ ERROR: found duplicate lang item `panic_cannot_unwind` [E0152] + //~| NOTE first defined in crate `core` loop {} } diff --git a/tests/ui/error-codes/E0152-duplicate-lang-items.stderr b/tests/ui/error-codes/E0152-duplicate-lang-items.stderr index 2fe0d18fc2f47..c620cfc77be3d 100644 --- a/tests/ui/error-codes/E0152-duplicate-lang-items.stderr +++ b/tests/ui/error-codes/E0152-duplicate-lang-items.stderr @@ -1,5 +1,5 @@ -error[E0152]: found duplicate lang item `panic_impl` - --> $DIR/E0152-duplicate-lang-items.rs:16:1 +error[E0152]: found duplicate lang item `panic_cannot_unwind` + --> $DIR/E0152-duplicate-lang-items.rs:15:1 | LL | / fn panic_impl(info: &PanicInfo) -> ! { LL | | @@ -8,8 +8,8 @@ LL | | loop {} LL | | } | |_^ | - = note: the lang item is first defined in crate `std` (which `E0152_duplicate_lang_items` depends on) - = note: first definition in `std` loaded from SYSROOT/libstd-*.rlib + = note: the lang item is first defined in crate `core` (which `E0152_duplicate_lang_items` depends on) + = note: first definition in `core` loaded from SYSROOT/libcore-*.rlib = note: second definition in the local crate (`E0152_duplicate_lang_items`) error: aborting due to 1 previous error diff --git a/tests/ui/extern-flag/empty-extern-arg.stderr b/tests/ui/extern-flag/empty-extern-arg.stderr index 79efcc5d8b041..4726f74ca10f4 100644 --- a/tests/ui/extern-flag/empty-extern-arg.stderr +++ b/tests/ui/extern-flag/empty-extern-arg.stderr @@ -1,11 +1,16 @@ error: extern location for std does not exist: -error: `#[panic_handler]` function required, but not found - error: unwinding panics are not supported without std | = help: using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding = note: since the core library is usually precompiled with panic="unwind", rebuilding your crate with panic="abort" may not be enough to fix the problem +error: `#[panic_handler]` required, but not found + --> $SRC_DIR/core/src/panic.rs:LL:COL + | + = note: expected because `#[panic_handler]` was declared here in crate `core` + | + = help: expected at least one implementation in crate `empty_extern_arg` or any of its dependencies + error: aborting due to 3 previous errors diff --git a/tests/ui/extern-flag/no-force-extern.rs b/tests/ui/extern-flag/no-force-extern.rs index c9317abe292ca..2aeb734d4784c 100644 --- a/tests/ui/extern-flag/no-force-extern.rs +++ b/tests/ui/extern-flag/no-force-extern.rs @@ -8,5 +8,5 @@ fn foo() {} //~ ERROR `main` function not found in crate `no_force_extern` -//~? ERROR `#[panic_handler]` function required, but not found +//~? ERROR `#[panic_handler]` required, but not found //~? ERROR unwinding panics are not supported without std diff --git a/tests/ui/lang-items/start_lang_item_with_target_feature.rs b/tests/ui/lang-items/start_lang_item_with_target_feature.rs index 18cd4c9704056..9f6e5af41b358 100644 --- a/tests/ui/lang-items/start_lang_item_with_target_feature.rs +++ b/tests/ui/lang-items/start_lang_item_with_target_feature.rs @@ -11,7 +11,7 @@ pub trait Sized {} #[lang = "start"] #[target_feature(enable = "avx2")] -//~^ ERROR `start` lang item function is not allowed to have `#[target_feature]` +//~^ ERROR `#[start]` is not allowed to have `#[target_feature]` fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { 0 } diff --git a/tests/ui/lang-items/start_lang_item_with_target_feature.stderr b/tests/ui/lang-items/start_lang_item_with_target_feature.stderr index 6214e3f8bc79a..45b3b39ee7a9a 100644 --- a/tests/ui/lang-items/start_lang_item_with_target_feature.stderr +++ b/tests/ui/lang-items/start_lang_item_with_target_feature.stderr @@ -1,11 +1,11 @@ -error: `start` lang item function is not allowed to have `#[target_feature]` +error: `#[start]` is not allowed to have `#[target_feature]` --> $DIR/start_lang_item_with_target_feature.rs:13:1 | LL | #[target_feature(enable = "avx2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { - | ------------------------------------------------------------------------------------------- `start` lang item function is not allowed to have `#[target_feature]` + | ------------------------------------------------------------------------------------------- `#[start]` is not allowed to have `#[target_feature]` error: aborting due to 1 previous error diff --git a/tests/ui/macros/macro-comma-behavior.rs b/tests/ui/macros/macro-comma-behavior.rs index f00d4d3e85842..cb3676e0009a9 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)] #[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-bad-signature-1.rs b/tests/ui/panic-handler/panic-handler-bad-signature-1.rs index 71911afaa8430..f118bbcc2a4cb 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-1.rs +++ b/tests/ui/panic-handler/panic-handler-bad-signature-1.rs @@ -7,4 +7,4 @@ use core::panic::PanicInfo; #[panic_handler] fn panic(info: PanicInfo) -> () {} -//~^ ERROR `#[panic_handler]` function has wrong type [E0308] +//~^ ERROR function `panic` has a type that is incompatible with the declaration of `#[panic_handler]` diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr index 4fea52fec6e11..ca702a6c77dc1 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr +++ b/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr @@ -1,12 +1,22 @@ -error[E0308]: `#[panic_handler]` function has wrong type +error[E0053]: function `panic` has a type that is incompatible with the declaration of `#[panic_handler]` --> $DIR/panic-handler-bad-signature-1.rs:9:16 | LL | fn panic(info: PanicInfo) -> () {} | ^^^^^^^^^ expected `&PanicInfo<'_>`, found `PanicInfo<'_>` | +note: expected this because of this attribute + --> $DIR/panic-handler-bad-signature-1.rs:8:1 + | +LL | #[panic_handler] + | ^^^^^^^^^^^^^^^^ = note: expected signature `for<'a, 'b> fn(&'a PanicInfo<'b>) -> !` - found signature `for<'a> fn(PanicInfo<'a>) -> ()` + found signature `fn(PanicInfo<'_>) -> ()` +help: change the parameter type to match the declaration + | +LL - fn panic(info: PanicInfo) -> () {} +LL + fn panic(info: &PanicInfo<'_>) -> () {} + | error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-2.rs b/tests/ui/panic-handler/panic-handler-bad-signature-2.rs index 9c0130eff21f7..1c9cd2ebffffc 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-2.rs +++ b/tests/ui/panic-handler/panic-handler-bad-signature-2.rs @@ -7,7 +7,7 @@ use core::panic::PanicInfo; #[panic_handler] fn panic(info: &'static PanicInfo) -> ! -//~^ ERROR #[panic_handler]` function has wrong type [E0308] +//~^ ERROR mismatched types { loop {} } diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr index 736a4c7094c5d..86e17d83a7cab 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr +++ b/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr @@ -1,11 +1,11 @@ -error[E0308]: `#[panic_handler]` function has wrong type +error[E0308]: mismatched types --> $DIR/panic-handler-bad-signature-2.rs:9:1 | LL | fn panic(info: &'static PanicInfo) -> ! | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | = note: expected signature `for<'a, 'b> fn(&'a PanicInfo<'b>) -> _` - found signature `for<'a> fn(&'static PanicInfo<'a>) -> _` + found signature `fn(&'static PanicInfo<'_>) -> _` error: aborting due to 1 previous error diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-3.rs b/tests/ui/panic-handler/panic-handler-bad-signature-3.rs index 14c8c7c63b70c..86cfbe5696326 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-3.rs +++ b/tests/ui/panic-handler/panic-handler-bad-signature-3.rs @@ -6,6 +6,6 @@ use core::panic::PanicInfo; #[panic_handler] -fn panic() -> ! { //~ ERROR #[panic_handler]` function has wrong type [E0308] +fn panic() -> ! { //~ ERROR `panic` has 0 parameters but #[panic_handler] requires it to have 1 loop {} } diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-3.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-3.stderr index 6cd072c639625..30c277d0498f1 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-3.stderr +++ b/tests/ui/panic-handler/panic-handler-bad-signature-3.stderr @@ -1,12 +1,14 @@ -error[E0308]: `#[panic_handler]` function has wrong type +error[E0050]: `panic` has 0 parameters but #[panic_handler] requires it to have 1 --> $DIR/panic-handler-bad-signature-3.rs:9:1 | +LL | #[panic_handler] + | ---------------- required because of this attribute LL | fn panic() -> ! { - | ^^^^^^^^^^^^^^^ incorrect number of function parameters + | ^^^^^^^^^^^^^^^ expected 1 parameter, found 0 + --> $SRC_DIR/core/src/panic.rs:LL:COL | - = note: expected signature `for<'a, 'b> fn(&'a PanicInfo<'b>) -> _` - found signature `fn() -> _` + = note: requires 1 parameter error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0050`. diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-4.rs b/tests/ui/panic-handler/panic-handler-bad-signature-4.rs index 8fc5b3240140f..a2af4d829cc82 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-4.rs +++ b/tests/ui/panic-handler/panic-handler-bad-signature-4.rs @@ -7,6 +7,6 @@ use core::panic::PanicInfo; #[panic_handler] fn panic(pi: &PanicInfo) -> ! { - //~^ ERROR should have no type parameters + //~^ ERROR #[panic_handler] cannot have generic parameters other than lifetimes loop {} } diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-4.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-4.stderr index 41a12e8dddf68..f054f8b2d358a 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-4.stderr +++ b/tests/ui/panic-handler/panic-handler-bad-signature-4.stderr @@ -1,6 +1,8 @@ -error: should have no type parameters +error: #[panic_handler] cannot have generic parameters other than lifetimes --> $DIR/panic-handler-bad-signature-4.rs:9:1 | +LL | #[panic_handler] + | ---------------- required by this attribute LL | fn panic(pi: &PanicInfo) -> ! { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-5.rs b/tests/ui/panic-handler/panic-handler-bad-signature-5.rs index a2a0e46ec6829..fb3c9980a4152 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-5.rs +++ b/tests/ui/panic-handler/panic-handler-bad-signature-5.rs @@ -7,7 +7,7 @@ use core::panic::PanicInfo; #[panic_handler] fn panic(info: &PanicInfo<'static>) -> ! -//~^ ERROR #[panic_handler]` function has wrong type [E0308] +//~^ ERROR mismatched types { loop {} } diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-5.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-5.stderr index 3dcd253d3086e..ad89f966e9df2 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-5.stderr +++ b/tests/ui/panic-handler/panic-handler-bad-signature-5.stderr @@ -1,11 +1,11 @@ -error[E0308]: `#[panic_handler]` function has wrong type +error[E0308]: mismatched types --> $DIR/panic-handler-bad-signature-5.rs:9:1 | LL | fn panic(info: &PanicInfo<'static>) -> ! | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | = note: expected signature `for<'a, 'b> fn(&'a PanicInfo<'b>) -> _` - found signature `for<'a> fn(&'a PanicInfo<'static>) -> _` + found signature `fn(&PanicInfo<'static>) -> _` error: aborting due to 1 previous error diff --git a/tests/ui/panic-handler/panic-handler-duplicate.rs b/tests/ui/panic-handler/panic-handler-duplicate.rs deleted file mode 100644 index c0a7d6aa6d723..0000000000000 --- a/tests/ui/panic-handler/panic-handler-duplicate.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ compile-flags:-C panic=abort - -#![feature(lang_items)] -#![no_std] -#![no_main] - -use core::panic::PanicInfo; - -#[panic_handler] -fn panic(info: &PanicInfo) -> ! { - loop {} -} - -#[lang = "panic_impl"] -fn panic2(info: &PanicInfo) -> ! { //~ ERROR found duplicate lang item `panic_impl` - loop {} -} diff --git a/tests/ui/panic-handler/panic-handler-duplicate.stderr b/tests/ui/panic-handler/panic-handler-duplicate.stderr deleted file mode 100644 index 299847474cd58..0000000000000 --- a/tests/ui/panic-handler/panic-handler-duplicate.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0152]: found duplicate lang item `panic_impl` - --> $DIR/panic-handler-duplicate.rs:15:1 - | -LL | / fn panic2(info: &PanicInfo) -> ! { -LL | | loop {} -LL | | } - | |_^ - | -note: the lang item is first defined here - --> $DIR/panic-handler-duplicate.rs:10:1 - | -LL | / fn panic(info: &PanicInfo) -> ! { -LL | | loop {} -LL | | } - | |_^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0152`. diff --git a/tests/ui/panic-handler/panic-handler-missing.rs b/tests/ui/panic-handler/panic-handler-missing.rs index ab617f93a9919..ddff087081df8 100644 --- a/tests/ui/panic-handler/panic-handler-missing.rs +++ b/tests/ui/panic-handler/panic-handler-missing.rs @@ -1,5 +1,4 @@ //@ dont-check-compiler-stderr - #![feature(lang_items)] #![no_main] #![no_std] @@ -7,4 +6,4 @@ #[lang = "eh_personality"] fn eh() {} -//~? ERROR `#[panic_handler]` function required, but not found +//~? ERROR `#[panic_handler]` required, but not found diff --git a/tests/ui/panic-handler/panic-handler-requires-panic-info.rs b/tests/ui/panic-handler/panic-handler-requires-panic-info.rs index 0b8308ba753aa..719483adf7429 100644 --- a/tests/ui/panic-handler/panic-handler-requires-panic-info.rs +++ b/tests/ui/panic-handler/panic-handler-requires-panic-info.rs @@ -6,8 +6,8 @@ #![no_main] #[panic_handler] +//~^ ERROR cannot find attribute `panic_handler` in this scope fn panic() -> ! { - //~^ ERROR requires `panic_info` lang_item loop {} } diff --git a/tests/ui/panic-handler/panic-handler-requires-panic-info.stderr b/tests/ui/panic-handler/panic-handler-requires-panic-info.stderr index 873f61a51632b..214376a26e330 100644 --- a/tests/ui/panic-handler/panic-handler-requires-panic-info.stderr +++ b/tests/ui/panic-handler/panic-handler-requires-panic-info.stderr @@ -1,8 +1,8 @@ -error: requires `panic_info` lang_item - --> $DIR/panic-handler-requires-panic-info.rs:9:1 +error: cannot find attribute `panic_handler` in this scope + --> $DIR/panic-handler-requires-panic-info.rs:8:3 | -LL | fn panic() -> ! { - | ^^^^^^^^^^^^^^^ +LL | #[panic_handler] + | ^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/panic-handler/panic-handler-std.rs b/tests/ui/panic-handler/panic-handler-std.rs index f6a4b60461cee..e1193d03302b0 100644 --- a/tests/ui/panic-handler/panic-handler-std.rs +++ b/tests/ui/panic-handler/panic-handler-std.rs @@ -1,4 +1,4 @@ -//@ normalize-stderr: "loaded from .*libstd-.*.rlib" -> "loaded from SYSROOT/libstd-*.rlib" +//@ normalize-stderr: "loaded from .*libcore-.*.rlib" -> "loaded from SYSROOT/libcore-*.rlib" extern crate core; diff --git a/tests/ui/panic-handler/panic-handler-std.stderr b/tests/ui/panic-handler/panic-handler-std.stderr index 48c216ce27ec4..2f4622b51b05f 100644 --- a/tests/ui/panic-handler/panic-handler-std.stderr +++ b/tests/ui/panic-handler/panic-handler-std.stderr @@ -7,7 +7,7 @@ LL | | } | |_^ | = note: the lang item is first defined in crate `std` (which `panic_handler_std` depends on) - = note: first definition in `std` loaded from SYSROOT/libstd-*.rlib + = note: first definition in `std` loaded from $BUILD_DIR/x86_64-unknown-linux-gnu/stage1/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-d7cc1867e59baf27.rlib = note: second definition in the local crate (`panic_handler_std`) error: aborting due to 1 previous error diff --git a/tests/ui/panic-handler/panic-handler-twice.rs b/tests/ui/panic-handler/panic-handler-twice.rs index 2d95a5028bf6b..64375d750e41b 100644 --- a/tests/ui/panic-handler/panic-handler-twice.rs +++ b/tests/ui/panic-handler/panic-handler-twice.rs @@ -1,5 +1,6 @@ //@ dont-check-compiler-stderr //@ aux-build:some-panic-impl.rs +//~? ERROR multiple implementations of `#[panic_handler]` #![feature(lang_items)] #![no_std] @@ -8,10 +9,10 @@ extern crate some_panic_impl; use core::panic::PanicInfo; +use core::panic_handler; #[panic_handler] fn panic(info: &PanicInfo) -> ! { - //~^ ERROR found duplicate lang item `panic_impl` loop {} } diff --git a/tests/ui/panic-handler/panic-handler-with-target-feature.rs b/tests/ui/panic-handler/panic-handler-with-target-feature.rs index aec00c637bedb..a5ae59cc74896 100644 --- a/tests/ui/panic-handler/panic-handler-with-target-feature.rs +++ b/tests/ui/panic-handler/panic-handler-with-target-feature.rs @@ -8,7 +8,8 @@ use core::panic::PanicInfo; #[panic_handler] #[target_feature(enable = "avx2")] -//~^ ERROR `#[panic_handler]` function is not allowed to have `#[target_feature]` +//~^ ERROR `#[panic_handler]` is not allowed to have `#[target_feature]` fn panic(info: &PanicInfo) -> ! { +//~^ ERROR function `panic` has a type that is incompatible with the declaration of `#[panic_handler]` unimplemented!(); } diff --git a/tests/ui/panic-handler/panic-handler-with-target-feature.stderr b/tests/ui/panic-handler/panic-handler-with-target-feature.stderr index ddf0ae77a0a1a..4a3207a7e297d 100644 --- a/tests/ui/panic-handler/panic-handler-with-target-feature.stderr +++ b/tests/ui/panic-handler/panic-handler-with-target-feature.stderr @@ -1,11 +1,28 @@ -error: `#[panic_handler]` function is not allowed to have `#[target_feature]` +error: `#[panic_handler]` is not allowed to have `#[target_feature]` --> $DIR/panic-handler-with-target-feature.rs:10:1 | LL | #[target_feature(enable = "avx2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | fn panic(info: &PanicInfo) -> ! { - | ------------------------------- `#[panic_handler]` function is not allowed to have `#[target_feature]` + | ------------------------------- `#[panic_handler]` is not allowed to have `#[target_feature]` -error: aborting due to 1 previous error +error[E0053]: function `panic` has a type that is incompatible with the declaration of `#[panic_handler]` + --> $DIR/panic-handler-with-target-feature.rs:12:1 + | +LL | fn panic(info: &PanicInfo) -> ! { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected safe fn, found unsafe fn + | +note: expected this because of this attribute + --> $DIR/panic-handler-with-target-feature.rs:9:1 + | +LL | #[panic_handler] + | ^^^^^^^^^^^^^^^^ +note: type in declaration + --> $SRC_DIR/core/src/panic.rs:LL:COL + = note: expected signature `for<'a, 'b> fn(&'a PanicInfo<'b>) -> _` + found signature `unsafe fn(&PanicInfo<'_>) -> _` + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/panic-handler/panic-handler-with-track-caller.rs b/tests/ui/panic-handler/panic-handler-with-track-caller.rs index 09c94139e1697..c78f5eeb926fb 100644 --- a/tests/ui/panic-handler/panic-handler-with-track-caller.rs +++ b/tests/ui/panic-handler/panic-handler-with-track-caller.rs @@ -8,7 +8,7 @@ use core::panic::PanicInfo; #[panic_handler] #[track_caller] -//~^ ERROR `#[panic_handler]` function is not allowed to have `#[track_caller]` +//~^ ERROR `#[panic_handler]` is not allowed to have `#[track_caller]` fn panic(info: &PanicInfo) -> ! { unimplemented!(); } diff --git a/tests/ui/panic-handler/panic-handler-with-track-caller.stderr b/tests/ui/panic-handler/panic-handler-with-track-caller.stderr index 605567acdb58b..9fbed1118df96 100644 --- a/tests/ui/panic-handler/panic-handler-with-track-caller.stderr +++ b/tests/ui/panic-handler/panic-handler-with-track-caller.stderr @@ -1,11 +1,11 @@ -error: `#[panic_handler]` function is not allowed to have `#[track_caller]` +error: `#[panic_handler]` is not allowed to have `#[track_caller]` --> $DIR/panic-handler-with-track-caller.rs:10:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ LL | LL | fn panic(info: &PanicInfo) -> ! { - | ------------------------------- `#[panic_handler]` function is not allowed to have `#[track_caller]` + | ------------------------------- `#[panic_handler]` is not allowed to have `#[track_caller]` error: aborting due to 1 previous error diff --git a/tests/ui/panic-handler/panic-handler-wrong-location.rs b/tests/ui/panic-handler/panic-handler-wrong-location.rs index 8fff7067136e2..52ab71609876e 100644 --- a/tests/ui/panic-handler/panic-handler-wrong-location.rs +++ b/tests/ui/panic-handler/panic-handler-wrong-location.rs @@ -3,7 +3,8 @@ #![no_std] #![no_main] -#[panic_handler] //~ ERROR `panic_impl` lang item must be applied to a function +#[panic_handler] //~ ERROR `#[panic_handler]` is only valid on function +#[no_mangle] static X: u32 = 42; -//~? ERROR `#[panic_handler]` function required, but not found +//~? ERROR `#[panic_handler]` required, but not found diff --git a/tests/ui/panic-handler/panic-handler-wrong-location.stderr b/tests/ui/panic-handler/panic-handler-wrong-location.stderr index 66ee91aa4c199..de26af8873db2 100644 --- a/tests/ui/panic-handler/panic-handler-wrong-location.stderr +++ b/tests/ui/panic-handler/panic-handler-wrong-location.stderr @@ -1,11 +1,15 @@ -error[E0718]: `panic_impl` lang item must be applied to a function +error: `#[panic_handler]` is only valid on functions --> $DIR/panic-handler-wrong-location.rs:6:1 | LL | #[panic_handler] - | ^^^^^^^^^^^^^^^^ attribute should be applied to a function, not a static item + | ^^^^^^^^^^^^^^^^ -error: `#[panic_handler]` function required, but not found +error: `#[panic_handler]` required, but not found + --> $SRC_DIR/core/src/panic.rs:LL:COL + | + = note: expected because `#[panic_handler]` was declared here in crate `core` + | + = help: expected at least one implementation in crate `panic_handler_wrong_location` or any of its dependencies error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0718`. diff --git a/tests/ui/panic-handler/weak-lang-item.rs b/tests/ui/panic-handler/weak-lang-item.rs index cc5ccb75104be..17d5bef81ead5 100644 --- a/tests/ui/panic-handler/weak-lang-item.rs +++ b/tests/ui/panic-handler/weak-lang-item.rs @@ -9,5 +9,5 @@ extern crate weak_lang_items; fn main() {} -//~? ERROR `#[panic_handler]` function required, but not found +//~? ERROR `#[panic_handler]` required, but not found //~? ERROR unwinding panics are not supported without std diff --git a/tests/ui/panic-handler/weak-lang-item.stderr b/tests/ui/panic-handler/weak-lang-item.stderr index 5acd3e3187051..9799f7ce6e16f 100644 --- a/tests/ui/panic-handler/weak-lang-item.stderr +++ b/tests/ui/panic-handler/weak-lang-item.stderr @@ -10,13 +10,18 @@ help: you can use `as` to change the binding name of the import LL | extern crate core as other_core; | +++++++++++++ -error: `#[panic_handler]` function required, but not found - error: unwinding panics are not supported without std | = help: using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding = note: since the core library is usually precompiled with panic="unwind", rebuilding your crate with panic="abort" may not be enough to fix the problem +error: `#[panic_handler]` required, but not found + --> $SRC_DIR/core/src/panic.rs:LL:COL + | + = note: expected because `#[panic_handler]` was declared here in crate `core` + | + = help: expected at least one implementation in crate `weak_lang_item` or any of its dependencies + error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0259`. 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..70b773e92968d 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"] +#[core::panic_handler] fn panic_impl(info: &PanicInfo) -> ! { loop {} } #[lang = "eh_personality"] fn eh_personality() {} diff --git a/tests/ui/proc-macro/issue-59191-replace-root-with-fn.rs b/tests/ui/proc-macro/issue-59191-replace-root-with-fn.rs index df236cce6d2a8..662b57b733ab1 100644 --- a/tests/ui/proc-macro/issue-59191-replace-root-with-fn.rs +++ b/tests/ui/proc-macro/issue-59191-replace-root-with-fn.rs @@ -9,5 +9,5 @@ #![issue_59191::no_main] #![issue_59191::no_main] -//~? ERROR `#[panic_handler]` function required, but not found +//~? ERROR `#[panic_handler]` required, but not found //~? ERROR unwinding panics are not supported without std diff --git a/tests/ui/proc-macro/issue-59191-replace-root-with-fn.stderr b/tests/ui/proc-macro/issue-59191-replace-root-with-fn.stderr index 3cd98d9c72b82..aa8b63a2d239b 100644 --- a/tests/ui/proc-macro/issue-59191-replace-root-with-fn.stderr +++ b/tests/ui/proc-macro/issue-59191-replace-root-with-fn.stderr @@ -1,9 +1,14 @@ -error: `#[panic_handler]` function required, but not found - error: unwinding panics are not supported without std | = help: using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding = note: since the core library is usually precompiled with panic="unwind", rebuilding your crate with panic="abort" may not be enough to fix the problem +error: `#[panic_handler]` required, but not found + --> $SRC_DIR/core/src/panic.rs:LL:COL + | + = note: expected because `#[panic_handler]` was declared here in crate `core` + | + = help: expected at least one implementation in crate `issue_59191_replace_root_with_fn` or any of its dependencies + error: aborting due to 2 previous errors diff --git a/tests/ui/recursion_limit/zero-overflow.rs b/tests/ui/recursion_limit/zero-overflow.rs index 3887972a51623..2c31ceeda64d9 100644 --- a/tests/ui/recursion_limit/zero-overflow.rs +++ b/tests/ui/recursion_limit/zero-overflow.rs @@ -1,5 +1,7 @@ //~ ERROR overflow evaluating the requirement `&mut Self: DispatchFromDyn<&mut RustaceansAreAwesome> -//~| HELP consider increasing the recursion limit +//~| HELP consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`zero_overflow`) +//~^^ ERROR queries overflow the depth limit! +//~| HELP consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`zero_overflow`) //@ build-fail #![recursion_limit = "0"] diff --git a/tests/ui/recursion_limit/zero-overflow.stderr b/tests/ui/recursion_limit/zero-overflow.stderr index fc03cc5b604b7..a8f141af52661 100644 --- a/tests/ui/recursion_limit/zero-overflow.stderr +++ b/tests/ui/recursion_limit/zero-overflow.stderr @@ -2,6 +2,11 @@ error[E0275]: overflow evaluating the requirement `&mut Self: DispatchFromDyn<&m | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`zero_overflow`) -error: aborting due to 1 previous error +error: queries overflow the depth limit! + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`zero_overflow`) + = note: query depth increased by 2 when computing layout of `core::panic::panic_info::PanicInfo<'_>` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0275`. From 6da9baa0230bca5b0590343ffeddd5f42102d9c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 18 Apr 2025 08:33:10 +0200 Subject: [PATCH 33/41] remove panic handler from compiler --- compiler/rustc_feature/src/builtin_attrs.rs | 1 - compiler/rustc_hir/src/lang_items.rs | 2 - compiler/rustc_hir/src/weak_lang_items.rs | 1 - compiler/rustc_hir_typeck/src/check.rs | 59 -------------- compiler/rustc_passes/src/check_attr.rs | 1 - compiler/rustc_passes/src/dead.rs | 2 - compiler/rustc_resolve/src/check_unused.rs | 1 + compiler/rustc_trait_selection/messages.ftl | 5 +- library/core/src/lib.rs | 4 + library/core/src/panic.rs | 7 ++ library/core/src/panicking.rs | 89 ++++++++++++++------- 11 files changed, 72 insertions(+), 100 deletions(-) diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 30aa39024b264..a657022068ff4 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -494,7 +494,6 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ template!(NameValueStr: "windows|console"), FutureWarnFollowing, EncodeCrossCrate::No ), - ungated!(panic_handler, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes), // RFC 2070 // Code generation: ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing, EncodeCrossCrate::No), diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 21d36ed54cdf4..77dbe55ba227f 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -151,12 +151,10 @@ impl HashStable for LangItem { } /// Extracts the first `lang = "$name"` out of a list of attributes. -/// The `#[panic_handler]` attribute is also extracted out when found. pub fn extract(attrs: &[impl AttributeExt]) -> Option<(Symbol, Span)> { attrs.iter().find_map(|attr| { Some(match attr { _ if attr.has_name(sym::lang) => (attr.value_str()?, attr.span()), - _ if attr.has_name(sym::panic_handler) => (sym::panic_impl, attr.span()), _ => return None, }) }) diff --git a/compiler/rustc_hir/src/weak_lang_items.rs b/compiler/rustc_hir/src/weak_lang_items.rs index b4e548effd46d..66458500a5caa 100644 --- a/compiler/rustc_hir/src/weak_lang_items.rs +++ b/compiler/rustc_hir/src/weak_lang_items.rs @@ -24,7 +24,6 @@ macro_rules! weak_lang_items { } weak_lang_items! { - PanicImpl, rust_begin_unwind; EhPersonality, rust_eh_personality; EhCatchTypeinfo, rust_eh_catch_typeinfo; } diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index b0c6a993e5efb..e9e380a1541f4 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -149,11 +149,6 @@ pub(super) fn check_fn<'a, 'tcx>( // we have a recursive call site and do the sadly stabilized fallback to `()`. fcx.demand_suptype(span, ret_ty, actual_return_ty); - // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !` - if tcx.is_lang_item(fn_def_id.to_def_id(), LangItem::PanicImpl) { - check_panic_info_fn(tcx, fn_def_id, fn_sig); - } - if tcx.is_lang_item(fn_def_id.to_def_id(), LangItem::Start) { check_lang_start_fn(tcx, fn_sig, fn_def_id); } @@ -161,60 +156,6 @@ pub(super) fn check_fn<'a, 'tcx>( fcx.coroutine_types } -fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_>) { - let span = tcx.def_span(fn_id); - - let DefKind::Fn = tcx.def_kind(fn_id) else { - tcx.dcx().span_err(span, "should be a function"); - return; - }; - - let generic_counts = tcx.generics_of(fn_id).own_counts(); - if generic_counts.types != 0 { - tcx.dcx().span_err(span, "should have no type parameters"); - } - if generic_counts.consts != 0 { - tcx.dcx().span_err(span, "should have no const parameters"); - } - - let panic_info_did = tcx.require_lang_item(hir::LangItem::PanicInfo, Some(span)); - - // build type `for<'a, 'b> fn(&'a PanicInfo<'b>) -> !` - let panic_info_ty = tcx.type_of(panic_info_did).instantiate( - tcx, - &[ty::GenericArg::from(ty::Region::new_bound( - tcx, - ty::INNERMOST, - ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BoundRegionKind::Anon }, - ))], - ); - let panic_info_ref_ty = Ty::new_imm_ref( - tcx, - ty::Region::new_bound( - tcx, - ty::INNERMOST, - ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::Anon }, - ), - panic_info_ty, - ); - - let bounds = tcx.mk_bound_variable_kinds(&[ - ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon), - ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon), - ]); - let expected_sig = ty::Binder::bind_with_vars( - tcx.mk_fn_sig([panic_info_ref_ty], tcx.types.never, false, fn_sig.safety, ExternAbi::Rust), - bounds, - ); - - let _ = check_function_signature( - tcx, - ObligationCause::new(span, fn_id, ObligationCauseCode::LangFunctionType(sym::panic_impl)), - fn_id.into(), - expected_sig, - ); -} - fn check_lang_start_fn<'tcx>(tcx: TyCtxt<'tcx>, fn_sig: ty::FnSig<'tcx>, def_id: LocalDefId) { // build type `fn(main: fn() -> T, argc: isize, argv: *const *const u8, sigpipe: u8)` diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ee4870e1c9c93..d0cbab51d1c45 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -299,7 +299,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::deprecated_safe // FIXME(deprecated_safe) // internal | sym::prelude_import - | sym::panic_handler | sym::allow_internal_unsafe | sym::fundamental | sym::lang diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index b28a168903f52..2d4a9f1fd1903 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -691,8 +691,6 @@ fn has_allow_dead_code_or_lang_attr( ) -> Option { fn has_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { tcx.has_attr(def_id, sym::lang) - // Stable attribute for #[lang = "panic_impl"] - || tcx.has_attr(def_id, sym::panic_handler) } fn has_allow_expect_dead_code(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index a005be3eb380c..b29878bda1e3c 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -402,6 +402,7 @@ impl Resolver<'_, '_> { !tcx.is_compiler_builtins(cnum) && !tcx.is_panic_runtime(cnum) && !tcx.has_global_allocator(cnum) + // TODO: test for EII in the crate }) { maybe_unused_extern_crates.insert(id, import.span); } diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index cf6dd40718b3d..762dddcaaf59e 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -238,10 +238,7 @@ trait_selection_oc_cant_coerce_force_inline = trait_selection_oc_cant_coerce_intrinsic = cannot coerce intrinsics to function pointers trait_selection_oc_closure_selfref = closure/coroutine type that references itself trait_selection_oc_const_compat = const not compatible with trait -trait_selection_oc_fn_lang_correct_type = {$lang_item_name -> - [panic_impl] `#[panic_handler]` - *[lang_item_name] lang item `{$lang_item_name}` - } function has wrong type +trait_selection_oc_fn_lang_correct_type = lang item `{$lang_item_name}` function has wrong type trait_selection_oc_fn_main_correct_type = `main` function has wrong type trait_selection_oc_generic = mismatched types diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 64a7ec8906b6b..41dcf43c725da 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -95,6 +95,7 @@ // // Library features: // tidy-alphabetical-start +#![cfg_attr(not(bootstrap), feature(eii))] #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] #![feature(bigint_helper_methods)] @@ -237,6 +238,9 @@ pub mod contracts; #[unstable(feature = "cfg_match", issue = "115585")] pub use crate::macros::cfg_match; +#[cfg(not(bootstrap))] +#[stable(feature = "panic_hooks", since = "1.10.0")] +pub use crate::panic::panic_handler; #[macro_use] mod internal_macros; diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index 5fa340a6147f6..e3ac690df81d5 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -16,6 +16,13 @@ pub use self::panic_info::PanicMessage; pub use self::unwind_safe::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe}; use crate::any::Any; +/// Core expects some crate to provide a function annotated with `#[panic_handler]` with this +/// signature. This annotated function will be called when a panic occurs. +#[stable(feature = "panic_hooks", since = "1.10.0")] +#[cfg(not(bootstrap))] +#[eii(panic_handler)] +pub(crate) fn panic_impl(info: &PanicInfo<'_>) -> !; + #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] #[allow_internal_unstable(panic_internals, const_format_args)] diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 83a45436b3050..52c6b0d957748 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -56,23 +56,36 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { if cfg!(feature = "panic_immediate_abort") { super::intrinsics::abort() } + #[cfg(bootstrap)] + { + // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call + // that gets resolved to the `#[panic_handler]` function. + unsafe extern "Rust" { + #[lang = "panic_impl"] + fn panic_impl(pi: &PanicInfo<'_>) -> !; + } - // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call - // that gets resolved to the `#[panic_handler]` function. - unsafe extern "Rust" { - #[lang = "panic_impl"] - fn panic_impl(pi: &PanicInfo<'_>) -> !; - } + let pi = PanicInfo::new( + &fmt, + Location::caller(), + /* can_unwind */ true, + /* force_no_backtrace */ false, + ); - let pi = PanicInfo::new( - &fmt, - Location::caller(), - /* can_unwind */ true, - /* force_no_backtrace */ false, - ); - - // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call. - unsafe { panic_impl(&pi) } + // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call. + unsafe { panic_impl(&pi) } + } + #[cfg(not(bootstrap))] + { + let pi = PanicInfo::new( + &fmt, + Location::caller(), + /* can_unwind */ true, + /* force_no_backtrace */ false, + ); + + crate::panic::panic_impl(&pi) + } } /// Like `panic_fmt`, but for non-unwinding panics. @@ -98,23 +111,39 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo super::intrinsics::abort() } - // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call - // that gets resolved to the `#[panic_handler]` function. - unsafe extern "Rust" { - #[lang = "panic_impl"] - fn panic_impl(pi: &PanicInfo<'_>) -> !; + #[cfg(bootstrap)] + { + // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call + // that gets resolved to the `#[panic_handler]` function. + unsafe extern "Rust" { + #[lang = "panic_impl"] + fn panic_impl(pi: &PanicInfo<'_>) -> !; + } + + // PanicInfo with the `can_unwind` flag set to false forces an abort. + let pi = PanicInfo::new( + &fmt, + Location::caller(), + /* can_unwind */ false, + force_no_backtrace, + ); + + // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call. + unsafe { panic_impl(&pi) } } - // PanicInfo with the `can_unwind` flag set to false forces an abort. - let pi = PanicInfo::new( - &fmt, - Location::caller(), - /* can_unwind */ false, - force_no_backtrace, - ); - - // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call. - unsafe { panic_impl(&pi) } + #[cfg(not(bootstrap))] + { + // PanicInfo with the `can_unwind` flag set to false forces an abort. + let pi = PanicInfo::new( + &fmt, + Location::caller(), + /* can_unwind */ false, + force_no_backtrace, + ); + + crate::panic::panic_impl(&pi) + } } ) } From fefe20da1e36b44b58f3a96da82999849e9fe9e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 18 Apr 2025 09:00:38 +0200 Subject: [PATCH 34/41] add feature gates for eii(-internals) --- .../ui/feature-gates/feature-gate-eii-internals.rs | 13 +++++++++++++ .../feature-gates/feature-gate-eii-internals.stderr | 12 ++++++++++++ tests/ui/feature-gates/feature-gate-eii.rs | 9 +++++++++ tests/ui/feature-gates/feature-gate-eii.stderr | 13 +++++++++++++ 4 files changed, 47 insertions(+) create mode 100644 tests/ui/feature-gates/feature-gate-eii-internals.rs create mode 100644 tests/ui/feature-gates/feature-gate-eii-internals.stderr create mode 100644 tests/ui/feature-gates/feature-gate-eii.rs create mode 100644 tests/ui/feature-gates/feature-gate-eii.stderr diff --git a/tests/ui/feature-gates/feature-gate-eii-internals.rs b/tests/ui/feature-gates/feature-gate-eii-internals.rs new file mode 100644 index 0000000000000..9ca5dc158cffe --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-eii-internals.rs @@ -0,0 +1,13 @@ +#![crate_type = "rlib"] +#![feature(decl_macro)] +#![feature(rustc_attrs)] + +#[eii_macro_for(bar)] //~ ERROR use of unstable library feature `eii_internals` +#[rustc_builtin_macro(eii_macro)] +macro foo() { + +} + +unsafe extern "Rust" { + safe fn bar(x: u64) -> u64; +} diff --git a/tests/ui/feature-gates/feature-gate-eii-internals.stderr b/tests/ui/feature-gates/feature-gate-eii-internals.stderr new file mode 100644 index 0000000000000..78cfe0d1d8289 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-eii-internals.stderr @@ -0,0 +1,12 @@ +error[E0658]: use of unstable library feature `eii_internals` + --> $DIR/feature-gate-eii-internals.rs:5:3 + | +LL | #[eii_macro_for(bar)] + | ^^^^^^^^^^^^^ + | + = help: add `#![feature(eii_internals)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-eii.rs b/tests/ui/feature-gates/feature-gate-eii.rs new file mode 100644 index 0000000000000..3a51c3dd2eaeb --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-eii.rs @@ -0,0 +1,9 @@ +#![crate_type = "rlib"] + +#[eii] //~ ERROR use of unstable library feature `eii` +fn hello(x: u64); + +#[hello] +fn hello_impl(x: u64) { + println!("{x:?}") +} diff --git a/tests/ui/feature-gates/feature-gate-eii.stderr b/tests/ui/feature-gates/feature-gate-eii.stderr new file mode 100644 index 0000000000000..6ec231257ba78 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-eii.stderr @@ -0,0 +1,13 @@ +error[E0658]: use of unstable library feature `eii` + --> $DIR/feature-gate-eii.rs:3:3 + | +LL | #[eii] + | ^^^ + | + = note: see issue #125418 for more information + = help: add `#![feature(eii)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. From 08ca134e12d501d917ca0b6b53293f9fdb800066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 18 Apr 2025 15:15:17 +0200 Subject: [PATCH 35/41] make linkage be external more often --- .../src/error_codes/E0264.md | 2 + compiler/rustc_hir/src/lang_items.rs | 4 + compiler/rustc_middle/src/middle/eii.rs | 1 + compiler/rustc_middle/src/mir/mono.rs | 2 +- compiler/rustc_middle/src/mir/terminator.rs | 6 + compiler/rustc_middle/src/mir/visit.rs | 2 +- compiler/rustc_middle/src/ty/instance.rs | 7 +- compiler/rustc_mir_transform/src/shim.rs | 2 +- compiler/rustc_monomorphize/src/collector.rs | 3 +- .../rustc_monomorphize/src/partitioning.rs | 13 +- compiler/rustc_passes/messages.ftl | 3 + compiler/rustc_passes/src/eii.rs | 196 +++++++++++------- compiler/rustc_passes/src/errors.rs | 8 - compiler/rustc_passes/src/lang_items.rs | 4 + compiler/rustc_passes/src/weak_lang_items.rs | 11 +- library/core/src/panic.rs | 1 + tests/run-make/bin-emit-no-symbols/rmake.rs | 1 - tests/ui/error-codes/E0264.rs | 8 - tests/ui/error-codes/E0264.stderr | 9 - 19 files changed, 171 insertions(+), 112 deletions(-) delete mode 100644 tests/ui/error-codes/E0264.rs delete mode 100644 tests/ui/error-codes/E0264.stderr diff --git a/compiler/rustc_error_codes/src/error_codes/E0264.md b/compiler/rustc_error_codes/src/error_codes/E0264.md index 33ddf3405acca..e17b72061582d 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0264.md +++ b/compiler/rustc_error_codes/src/error_codes/E0264.md @@ -1,3 +1,5 @@ +#### this error code is no longer emitted by the compiler. + An unknown external lang item was used. Erroneous code example: diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 77dbe55ba227f..6db9fb6543408 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -285,6 +285,10 @@ language_item_table! { PanicMisalignedPointerDereference, sym::panic_misaligned_pointer_dereference, panic_misaligned_pointer_dereference_fn, Target::Fn, GenericRequirement::Exact(0); PanicInfo, sym::panic_info, panic_info, Target::Struct, GenericRequirement::None; PanicLocation, sym::panic_location, panic_location, Target::Struct, GenericRequirement::None; + /// Note: used to mark an extern item but now marks an externally implementable item. This means + /// that the PanicImpl used to be marked to be specially treated in the compiler, while it now + /// is only marked so we can check if it exists. There's no other reason for this lang item + /// anymore. PanicImpl, sym::panic_impl, panic_impl, Target::Fn, GenericRequirement::None; PanicCannotUnwind, sym::panic_cannot_unwind, panic_cannot_unwind, Target::Fn, GenericRequirement::Exact(0); PanicInCleanup, sym::panic_in_cleanup, panic_in_cleanup, Target::Fn, GenericRequirement::Exact(0); diff --git a/compiler/rustc_middle/src/middle/eii.rs b/compiler/rustc_middle/src/middle/eii.rs index 18abcc83e91f8..f8e5724c303ca 100644 --- a/compiler/rustc_middle/src/middle/eii.rs +++ b/compiler/rustc_middle/src/middle/eii.rs @@ -7,6 +7,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable}; pub struct EiiMapping { pub extern_item: DefId, pub chosen_impl: DefId, + pub weak_linkage: bool, } pub type EiiMap = FxIndexMap; diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index afd9ad3138747..5b1926f154eb6 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -383,7 +383,7 @@ pub struct MonoItemData { /// Specifies the linkage type for a `MonoItem`. /// /// See for more details about these variants. -#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)] +#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable, Eq, Hash)] pub enum Linkage { External, AvailableExternally, diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 0834fa8844c00..2ce76d7b7368d 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -225,6 +225,12 @@ impl AssertKind { } } + /// Generally do not use this and use `panic_function` instead. + /// Gives the lang item that is required to exist for this assertion + /// to be emitted. This sometimes causes the assertion not to be emitted + /// if a lang item isn't there. + pub fn required_lang_item(&self) {} + /// Format the message arguments for the `assert(cond, msg..)` terminator in MIR printing. /// /// Needs to be kept in sync with the run-time behavior (which is defined by diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index e0af97acb7468..bdec91e2c57f6 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -354,7 +354,7 @@ macro_rules! make_mir_visitor { receiver_by_ref: _, } | ty::InstanceKind::DropGlue(_def_id, None) - | ty::InstanceKind::EiiShim { def_id: _def_id, extern_item: _, chosen_impl: _ } => {} + | ty::InstanceKind::EiiShim { def_id: _def_id, extern_item: _, chosen_impl: _, weak_linkage: _ } => {} ty::InstanceKind::FnPtrShim(_def_id, ty) | ty::InstanceKind::DropGlue(_def_id, Some(ty)) diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index f9664d396fe79..848a940c0e0ee 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -187,7 +187,7 @@ pub enum InstanceKind<'tcx> { /// Generated by externally implementable items. This function adds indirection so we can choose /// in the final crate whether to call an explicit implementation or, if none are given, call the /// default. - EiiShim { def_id: DefId, extern_item: DefId, chosen_impl: DefId }, + EiiShim { def_id: DefId, extern_item: DefId, chosen_impl: DefId, weak_linkage: bool }, } impl<'tcx> Instance<'tcx> { @@ -436,7 +436,10 @@ pub fn fmt_instance( } InstanceKind::AsyncDropGlue(_, ty) => write!(f, " - shim({ty})"), InstanceKind::AsyncDropGlueCtorShim(_, ty) => write!(f, " - shim(Some({ty}))"), - InstanceKind::EiiShim { def_id: _, extern_item, chosen_impl } => { + InstanceKind::EiiShim { def_id: _, extern_item, chosen_impl, weak_linkage: true } => { + write!(f, " - shim(eii: {extern_item:?} -> {chosen_impl:?} [weak]") + } + InstanceKind::EiiShim { def_id: _, extern_item, chosen_impl, weak_linkage: false } => { write!(f, " - shim(eii: {extern_item:?} -> {chosen_impl:?})") } } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 25e8cc5fbac44..c187e617f851c 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -114,7 +114,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body< receiver_by_ref, } => build_construct_coroutine_by_move_shim(tcx, coroutine_closure_def_id, receiver_by_ref), - e @ ty::InstanceKind::EiiShim { def_id: _, extern_item, chosen_impl } => { + e @ ty::InstanceKind::EiiShim { def_id: _, extern_item, chosen_impl, weak_linkage: _ } => { let source = MirSource::from_instance(e); // get the signature for the new function this shim is creating diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 9aa3819cd871f..935aba4ca5269 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1614,7 +1614,7 @@ impl<'v> RootCollector<'_, 'v> { /// For each externally implementable item, we should generate an alias MonoItem that /// determines what implementation is called. This could be a default implementation. fn push_extra_eii_roots(&mut self) { - for (shim_did, &EiiMapping { extern_item, chosen_impl, .. }) in + for (shim_did, &EiiMapping { extern_item, chosen_impl, weak_linkage, .. }) in self.tcx.get_externally_implementable_item_impls(()) { self.output.push(create_fn_mono_item( @@ -1624,6 +1624,7 @@ impl<'v> RootCollector<'_, 'v> { def_id: (*shim_did).into(), extern_item, chosen_impl, + weak_linkage, }, args: ty::GenericArgs::empty(), }, diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index e5bba35008d65..bb0349ed44d71 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -635,7 +635,12 @@ fn characteristic_def_id_of_mono_item<'tcx>( ty::InstanceKind::Item(def) => def, // EII shims have a characteristic defid. // But it's not their own, its the one of the extern item it is implementing. - ty::InstanceKind::EiiShim { def_id: _, extern_item, chosen_impl: _ } => extern_item, + ty::InstanceKind::EiiShim { + def_id: _, + extern_item, + chosen_impl: _, + weak_linkage: _, + } => extern_item, ty::InstanceKind::VTableShim(..) | ty::InstanceKind::ReifyShim(..) | ty::InstanceKind::FnPtrShim(..) @@ -770,8 +775,10 @@ fn mono_item_linkage_and_visibility<'tcx>( // together anyway. LLVM ensures the last one is the one that's chosen // TODO: this isn't the problem if they both decided to choose either the default or the // same explicit impl but if their view on it differs it is a problem! - if let MonoItem::Fn(Instance { def: InstanceKind::EiiShim { .. }, .. }) = mono_item { - (Linkage::WeakAny, vis) + if let MonoItem::Fn(Instance { def: InstanceKind::EiiShim { weak_linkage, .. }, .. }) = + mono_item + { + if *weak_linkage { (Linkage::WeakAny, vis) } else { (Linkage::External, vis) } } else { (Linkage::External, vis) } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 1607387196119..766b2ab890321 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -780,6 +780,9 @@ passes_unexportable_type_in_interface = {$desc} with `#[export_stable]` attribut passes_unexportable_type_repr = types with unstable layout are not exportable +passes_undefined_naked_function_abi = + Rust ABI is unsupported in naked functions + passes_unknown_external_lang_item = unknown external lang item: `{$lang_item}` diff --git a/compiler/rustc_passes/src/eii.rs b/compiler/rustc_passes/src/eii.rs index 89cff3405b868..23ea8bf22bfff 100644 --- a/compiler/rustc_passes/src/eii.rs +++ b/compiler/rustc_passes/src/eii.rs @@ -7,6 +7,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::definitions::DisambiguatorState; +use rustc_middle::bug; use rustc_middle::middle::eii::EiiMapping; use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; @@ -22,39 +23,52 @@ pub(crate) fn get_externally_implementable_item_impls<'tcx>( tcx: TyCtxt<'tcx>, (): (), ) -> &'tcx FxIndexMap { - // We only need to check whether there are duplicate or missing EIIs if we're - // emitting something that's not an rlib. - let needs_check = tcx.crate_types().iter().any(|kind| match *kind { - // Executables are leafs of the crate graph and need all EIIs to be satisfied, - // either with defaults or explicit implementations. So they check their crate - // graph to make sure this is the case. - CrateType::Executable => true, - // Proc macros are leafs of their crate graph and will be run, - // and so need to check the EIIs of their dependencies. - CrateType::ProcMacro => true, - - // These are a litte difficult. We don't know whether things depending on these - // will perform checks to see if EIIs are implemented, or duplicated, or any other - // of the checks performed in this function. So we must do the checks. However, - // this can later lead to duplicate symbols when linking them together. - // For this reason, we later mark EII symbols as "globally shared" and "may conflict". - // In other words, if two shared libraries both provide an implementation for an EII, - // that's fine! Just choose one... And because their mangled symbol names are the same - // (that's exactly the conflict we're having) we hopefully have the same exact implementation. - CrateType::Dylib | CrateType::Cdylib | CrateType::Staticlib | CrateType::Sdylib => true, - - // Rlibs are just a step in the crate graph. - // Later on we'll link it together into an executable and over there we can check for EIIs - CrateType::Rlib => false, - }); - if !needs_check { - // In this case we could only have called it when checking, - // and not when we were actually codegenning functions so we don't need to return any real data - return &*tcx.arena.alloc(FxIndexMap::default()); + #[derive(Copy, Clone)] + enum Case { + /// We need to generate all EII shims because we are generating some final target like an + /// executable or library (not rlib) + AlwaysEmit, + /// We need to generate all EII shims because one of our crate types is a final target like + /// an executable. However, we're also generating an rlib. So. If we see explicit + /// definitions of EIIs we can generate them with external linkage. However, if we find + /// defaults, they must also be emitted because some of our crate types are final targets. + /// And unfortunately the rlib will also contain these definitions. However, because rlibs + /// will later be used in final targets, which will use `AlwaysEmit`, these symbols that were + /// spuriously generated in rlibs will be redefined and then flagged by the linker as + /// duplicate definitions. So, we have to emit EII shims which are default impls (not + /// explicit ones) as weak symbols. + EmitMaybeWeak, + /// We don't always need to emit EIIs because we're generating an Rlib. However, if we see + /// an explicit implementation, we can! Because it cannot be overwritten anymore. + EmitExternalIfExplicit, } - let mut eiis = - FxIndexMap::)>::default(); + let has_rlib = tcx.crate_types().iter().any(|i| matches!(i, CrateType::Rlib)); + let has_target = tcx.crate_types().iter().any(|i| !matches!(i, CrateType::Rlib)); + + let case = match (has_rlib, has_target) { + (true, true) => Case::EmitMaybeWeak, + (true, false) => Case::EmitExternalIfExplicit, + (false, true) => Case::AlwaysEmit, + (false, false) => { + bug!("no targets but somehow we are running the compiler") + } + }; + + #[derive(Debug)] + struct FoundImpl { + imp: EIIImpl, + impl_crate: CrateNum, + } + + #[derive(Debug)] + struct FoundEii { + decl: EIIDecl, + decl_crate: CrateNum, + impls: FxIndexMap, + } + + let mut eiis = FxIndexMap::::default(); // println!("current crate: {}", tcx.crate_name(LOCAL_CRATE)); @@ -67,9 +81,17 @@ pub(crate) fn get_externally_implementable_item_impls<'tcx>( // update or insert the corresponding entries for (did, (decl, impls)) in crate_eiis { eiis.entry(*did) - .or_insert_with(|| (*decl, cnum, Default::default())) - .2 - .extend(impls.into_iter().map(|(did, i)| (*did, (*i, cnum)))); + .or_insert_with(|| FoundEii { + decl: *decl, + decl_crate: cnum, + impls: Default::default(), + }) + .impls + .extend( + impls + .into_iter() + .map(|(did, i)| (*did, FoundImpl { imp: *i, impl_crate: cnum })), + ); } } @@ -77,18 +99,18 @@ pub(crate) fn get_externally_implementable_item_impls<'tcx>( // now we have all eiis! For each of them, choose one we want to actually generate. - for (decl_did, (decl, decl_crate, impls)) in eiis { + for (decl_did, FoundEii { decl, decl_crate, impls }) in eiis { // println!("for decl: {decl_did:?}: {decl:?}"); let mut default_impls = Vec::new(); let mut explicit_impls = Vec::new(); - for (impl_did, (impl_metadata, cnum)) in impls { - if impl_metadata.is_default { + for (impl_did, FoundImpl { imp, impl_crate }) in impls { + if imp.is_default { // println!("found default impl in {}", tcx.crate_name(cnum)); - default_impls.push((impl_did, cnum)); + default_impls.push((impl_did, impl_crate)); } else { // println!("found impl in {}", tcx.crate_name(cnum)); - explicit_impls.push((impl_did, cnum)); + explicit_impls.push((impl_did, impl_crate)); } } @@ -116,45 +138,79 @@ pub(crate) fn get_externally_implementable_item_impls<'tcx>( panic!("multiple not supported right now, but this is easily possible"); } - // println!("impls: {explicit_impls:?}"); - // println!("default impls: {default_impls:?}"); - - if let Some((chosen_impl, _)) = explicit_impls.first().or(default_impls.first()) { - let feed = tcx.create_def( - CRATE_DEF_ID, - Some(Symbol::intern(&format!("EII shim for {decl_did:?}"))), - DefKind::Fn, + let (chosen_impl, weak_linkage) = + match (case, explicit_impls.first(), default_impls.first()) { + (Case::EmitExternalIfExplicit, Some((explicit, impl_crate)), _) => { + if impl_crate != &LOCAL_CRATE { + continue; + } + (explicit, false) + } + // we don't care in this case if we find no implementation yet. Another can come + // downstream. + (Case::EmitExternalIfExplicit, None, _) => { + continue; + } + (Case::AlwaysEmit, Some((explicit, impl_crate)), _) => { + if impl_crate != &LOCAL_CRATE { + continue; + } + + (explicit, false) + } + (Case::AlwaysEmit, _, Some((deflt, _))) => (deflt, false), + + (Case::EmitMaybeWeak, Some((explicit, impl_crate)), _) => { + if impl_crate != &LOCAL_CRATE { + continue; + } + + (explicit, false) + } + // IMPORTANT! weak linkage because the symbol will also end up in the rlib and may need + // to be overwritten :( + (Case::EmitMaybeWeak, _, Some((deflt, _))) => (deflt, true), + + // We have a target to generate, but no impl to put in it. error! + (Case::EmitMaybeWeak | Case::AlwaysEmit, None, None) => { + tcx.dcx().emit_err(EiiWithoutImpl { + current_crate_name: tcx.crate_name(LOCAL_CRATE), + decl_crate_name: tcx.crate_name(decl_crate), + name: tcx.item_name(decl_did), + span: decl.span, + help: (), + }); + + continue; + } + }; + + let feed = tcx.create_def( + CRATE_DEF_ID, + Some(Symbol::intern(&format!("EII shim for {decl_did:?}"))), + DefKind::Fn, None, &mut DisambiguatorState::new(), - ); + ); - let extern_item_did = decl.eii_extern_item; + let extern_item_did = decl.eii_extern_item; - feed.generics_of(tcx.generics_of(extern_item_did).clone()); - feed.type_of(tcx.type_of(extern_item_did).clone()); - feed.def_span(tcx.def_span(chosen_impl)); - feed.visibility(tcx.visibility(chosen_impl)); - feed.feed_hir(); + feed.generics_of(tcx.generics_of(extern_item_did).clone()); + feed.type_of(tcx.type_of(extern_item_did).clone()); + feed.def_span(tcx.def_span(chosen_impl)); + feed.visibility(tcx.visibility(chosen_impl)); + feed.feed_hir(); - // println!("generating {extern_item_did:?} for impl {chosen_impl:?} in crate {} with did {decl_did:?}", tcx.crate_name(LOCAL_CRATE)); + // println!("generating {extern_item_did:?} for impl {chosen_impl:?} in crate {} with did {decl_did:?}", tcx.crate_name(LOCAL_CRATE)); - let shim_did = feed.def_id(); + let shim_did = feed.def_id(); - // println!("shim: {shim_did:?}"); + // println!("shim: {shim_did:?}"); - final_impls.insert( - shim_did, - EiiMapping { extern_item: extern_item_did, chosen_impl: *chosen_impl }, - ); - } else { - tcx.dcx().emit_err(EiiWithoutImpl { - current_crate_name: tcx.crate_name(LOCAL_CRATE), - decl_crate_name: tcx.crate_name(decl_crate), - name: tcx.item_name(decl_did), - span: decl.span, - help: (), - }); - } + final_impls.insert( + shim_did, + EiiMapping { extern_item: extern_item_did, chosen_impl: *chosen_impl, weak_linkage }, + ); } tcx.arena.alloc(final_impls) diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index b71697538b701..8a439754210a3 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -854,14 +854,6 @@ pub(crate) struct DeprecatedAnnotationHasNoEffect { pub span: Span, } -#[derive(Diagnostic)] -#[diag(passes_unknown_external_lang_item, code = E0264)] -pub(crate) struct UnknownExternLangItem { - #[primary_span] - pub span: Span, - pub lang_item: Symbol, -} - #[derive(Diagnostic)] #[diag(passes_panic_unwind_without_std)] #[help] diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 275714c2d0e44..9b570bf287555 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -75,6 +75,10 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> { actual_target, ); } + // Exception: for EIIs the macro gets copied to both a generated macro *and* the + // generated extern item. We need to ignore one of these, and it must be the + // macrodef. + Some(LangItem::PanicImpl) if actual_target == Target::MacroDef => return, // Known lang item with attribute on incorrect target. Some(lang_item) => { self.tcx.dcx().emit_err(LangItemOnIncorrectTarget { diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 9534d7103c9c7..9836bb451453a 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -9,7 +9,7 @@ use rustc_middle::middle::lang_items::required; use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; -use crate::errors::{MissingLangItem, PanicUnwindWithoutStd, UnknownExternLangItem}; +use crate::errors::{MissingLangItem, PanicUnwindWithoutStd}; /// Checks the crate for usage of weak lang items, returning a vector of all the /// lang items required by this crate, but not defined yet. @@ -31,17 +31,16 @@ pub(crate) fn check_crate( items.missing.push(LangItem::EhCatchTypeinfo); } - visit::Visitor::visit_crate(&mut WeakLangItemVisitor { tcx, items }, krate); + visit::Visitor::visit_crate(&mut WeakLangItemVisitor { items }, krate); verify(tcx, items); } -struct WeakLangItemVisitor<'a, 'tcx> { - tcx: TyCtxt<'tcx>, +struct WeakLangItemVisitor<'a> { items: &'a mut lang_items::LanguageItems, } -impl<'ast> visit::Visitor<'ast> for WeakLangItemVisitor<'_, '_> { +impl<'ast> visit::Visitor<'ast> for WeakLangItemVisitor<'_> { fn visit_foreign_item(&mut self, i: &'ast ast::ForeignItem) { if let Some((lang_item, _)) = lang_items::extract(&i.attrs) { if let Some(item) = LangItem::from_name(lang_item) @@ -50,8 +49,6 @@ impl<'ast> visit::Visitor<'ast> for WeakLangItemVisitor<'_, '_> { if self.items.get(item).is_none() { self.items.missing.push(item); } - } else { - self.tcx.dcx().emit_err(UnknownExternLangItem { span: i.span, lang_item }); } } } diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index e3ac690df81d5..df41d5d3fadde 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -21,6 +21,7 @@ use crate::any::Any; #[stable(feature = "panic_hooks", since = "1.10.0")] #[cfg(not(bootstrap))] #[eii(panic_handler)] +#[lang = "panic_impl"] pub(crate) fn panic_impl(info: &PanicInfo<'_>) -> !; #[doc(hidden)] diff --git a/tests/run-make/bin-emit-no-symbols/rmake.rs b/tests/run-make/bin-emit-no-symbols/rmake.rs index 5586e53c05084..9f26ce66d7057 100644 --- a/tests/run-make/bin-emit-no-symbols/rmake.rs +++ b/tests/run-make/bin-emit-no-symbols/rmake.rs @@ -10,7 +10,6 @@ use run_make_support::{llvm_readobj, rustc}; fn main() { rustc().emit("obj").input("app.rs").run(); let out = llvm_readobj().input("app.o").arg("--symbols").run(); - out.assert_stdout_contains("rust_begin_unwind"); out.assert_stdout_contains("rust_eh_personality"); out.assert_stdout_contains("__rg_oom"); } diff --git a/tests/ui/error-codes/E0264.rs b/tests/ui/error-codes/E0264.rs deleted file mode 100644 index 6adaf01fb5244..0000000000000 --- a/tests/ui/error-codes/E0264.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(lang_items)] - -extern "C" { - #[lang = "cake"] - fn cake(); //~ ERROR E0264 -} - -fn main() {} diff --git a/tests/ui/error-codes/E0264.stderr b/tests/ui/error-codes/E0264.stderr deleted file mode 100644 index 3503fb229e4f3..0000000000000 --- a/tests/ui/error-codes/E0264.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0264]: unknown external lang item: `cake` - --> $DIR/E0264.rs:5:5 - | -LL | fn cake(); - | ^^^^^^^^^^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0264`. From c747e71a0fcbdf912cdf7925c4b5b35f5f1f9307 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 18 Apr 2025 15:25:13 +0200 Subject: [PATCH 36/41] include EIIs in used crates check --- compiler/rustc_resolve/src/check_unused.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index b29878bda1e3c..267aabeb0bdc9 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -402,7 +402,7 @@ impl Resolver<'_, '_> { !tcx.is_compiler_builtins(cnum) && !tcx.is_panic_runtime(cnum) && !tcx.has_global_allocator(cnum) - // TODO: test for EII in the crate + && tcx.externally_implementable_items(cnum).is_empty() }) { maybe_unused_extern_crates.insert(id, import.span); } From 1c7af70050964d1975383dd41c6eaaabc8f64390 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 18 Apr 2025 17:50:02 +0200 Subject: [PATCH 37/41] fix clippy --- src/tools/clippy/clippy_utils/src/ast_utils/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) 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 8996b694ed8f7..899aa99d25c7e 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -382,6 +382,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { contract: lc, body: lb, define_opaque: _, + eii_impl: _, }), Fn(box ast::Fn { defaultness: rd, @@ -391,6 +392,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { contract: rc, body: rb, define_opaque: _, + eii_impl: _, }), ) => { eq_defaultness(*ld, *rd) @@ -539,6 +541,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { contract: lc, body: lb, define_opaque: _, + eii_impl: _, }), Fn(box ast::Fn { defaultness: rd, @@ -548,6 +551,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { contract: rc, body: rb, define_opaque: _, + eii_impl: _, }), ) => { eq_defaultness(*ld, *rd) @@ -622,6 +626,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { contract: lc, body: lb, define_opaque: _, + eii_impl: _, }), Fn(box ast::Fn { defaultness: rd, @@ -631,6 +636,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { contract: rc, body: rb, define_opaque: _, + eii_impl: _, }), ) => { eq_defaultness(*ld, *rd) From 7db4f70860a7815b9712fae02874dc0c1b4ad850 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 9 May 2025 14:07:32 +0200 Subject: [PATCH 38/41] error codes --- .../src/error_codes/E0805.md | 64 +++++++++++++++++++ compiler/rustc_error_codes/src/lib.rs | 1 + .../src/check/compare_eii.rs | 7 +- compiler/rustc_passes/src/check_attr.rs | 5 +- tests/ui/error-codes/E0805.rs | 12 ++++ tests/ui/error-codes/E0805.stderr | 29 +++++++++ 6 files changed, 111 insertions(+), 7 deletions(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0805.md create mode 100644 tests/ui/error-codes/E0805.rs create mode 100644 tests/ui/error-codes/E0805.stderr diff --git a/compiler/rustc_error_codes/src/error_codes/E0805.md b/compiler/rustc_error_codes/src/error_codes/E0805.md new file mode 100644 index 0000000000000..f5dc13b14b812 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0805.md @@ -0,0 +1,64 @@ +An externally implementable item is not compatible with its declaration. + +Erroneous code example: + +```rust,edition2021,compile_fail,E0805 +#![feature(eii)] + +#[eii(foo)] +fn x(); + +#[foo] +fn y(a: u64) -> u64 { +//~^ ERROR E0805 + a +} + + +fn main() {} +``` + +To fix this, `y`'s signature must match that of `x`: + +```rust,edition2021 +#![feature(eii)] + +#[eii(foo)] +fn x(); + +#[foo] +fn y() {} + + +fn main() {} +``` + +One common way this can be triggered is by using the wrong +signature for `#[panic_handler]`. +The signature is provided by `core`. + +```rust,edition2021,ignore +#![no_std] + +#[panic_handler] +fn on_panic() -> ! { +//~^ ERROR E0805 + + loop {} +} + +fn main() {} +``` + +Should be: + +```rust,edition2021,ignore +#![no_std] + +#[panic_handler] +fn on_panic(info: &core::panic::PanicInfo<'_>) -> ! { + loop {} +} + +fn main() {} +``` diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 2488d870899ce..6f5e4829802e9 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -547,6 +547,7 @@ E0801: 0801, E0802: 0802, E0803: 0803, E0804: 0804, +E0805: 0805, ); ) } diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index 84940c56e36fb..66d55eab6fff3 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use std::iter; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{Applicability, E0050, E0053, struct_span_code_err}; +use rustc_errors::{Applicability, E0805, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, FnSig, HirId, ItemKind}; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; @@ -182,7 +182,7 @@ fn compare_number_of_method_arguments<'tcx>( let mut err = struct_span_code_err!( tcx.dcx(), impl_span, - E0050, // FIXME(jdonszelmann): new error code + E0805, "`{external_impl_name}` has {} but #[{eii_name}] requires it to have {}", potentially_plural_count(external_impl_number_args, "parameter"), declaration_number_args @@ -279,7 +279,6 @@ pub(crate) fn compare_eii_function_types<'tcx>( if let Err(terr) = result { debug!(?external_impl_sig, ?declaration_sig, ?terr, "sub_types failed"); - // TODO: nice error let emitted = report_eii_mismatch( infcx, cause, @@ -330,7 +329,7 @@ fn report_eii_mismatch<'tcx>( let mut diag = struct_span_code_err!( tcx.dcx(), impl_err_span, - E0053, // TODO: new error code + E0805, "function `{}` has a type that is incompatible with the declaration of `#[{eii_name}]`", external_impl_name ); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d0cbab51d1c45..c37d2ee98bbc1 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -131,7 +131,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // no checks needed } Attribute::Parsed(AttributeKind::EiiMangleExtern { .. }) => { - // TODO: checks? + // FIXME: mangle extern should be removed } Attribute::Parsed(AttributeKind::AllowInternalUnstable(syms)) => self .check_allow_internal_unstable( @@ -304,8 +304,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::lang | sym::needs_allocator | sym::default_lib_allocator - | sym::custom_mir - | sym::eii_macro_for, // TODO: remove + | sym::custom_mir, .. ] => {} [name, ..] => { diff --git a/tests/ui/error-codes/E0805.rs b/tests/ui/error-codes/E0805.rs new file mode 100644 index 0000000000000..fcd71e478ed02 --- /dev/null +++ b/tests/ui/error-codes/E0805.rs @@ -0,0 +1,12 @@ +#![feature(eii)] + +#[eii(foo)] +fn x(); + +#[foo] +fn y(a: u64) -> u64 { +//~^ ERROR E0805 + a +} + +fn main() {} diff --git a/tests/ui/error-codes/E0805.stderr b/tests/ui/error-codes/E0805.stderr new file mode 100644 index 0000000000000..c1877e44803df --- /dev/null +++ b/tests/ui/error-codes/E0805.stderr @@ -0,0 +1,29 @@ +error: free function without a body + --> $DIR/E0805.rs:4:1 + | +LL | fn x(); + | ^^^^^^- + | | + | help: provide a definition for the function: `{ }` + +error: cannot find attribute `foo` in this scope + --> $DIR/E0805.rs:6:3 + | +LL | #[foo] + | ^^^ + +error: cannot find attribute `eii` in this scope + --> $DIR/E0805.rs:3:3 + | +LL | #[eii(foo)] + | ^^^ + +error[E0635]: unknown feature `eii` + --> $DIR/E0805.rs:1:12 + | +LL | #![feature(eii)] + | ^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0635`. From 774c09addd1fb2eabfd78359580647502136af4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 9 May 2025 14:07:59 +0200 Subject: [PATCH 39/41] fix some nameres bugs --- compiler/rustc_ast_lowering/src/item.rs | 2 +- compiler/rustc_builtin_macros/src/eii.rs | 54 ++++++++++++++++----- compiler/rustc_codegen_ssa/src/back/link.rs | 1 - 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 8def3301ddced..00a0f1d86b2ea 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -576,7 +576,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_path_simple_eii(&mut self, id: NodeId, path: &Path) -> Option { - let res = self.resolver.get_partial_res(id).unwrap(); + let res = self.resolver.get_partial_res(id)?; let Some(did) = res.expect_full_res().opt_def_id() else { self.dcx().span_delayed_bug(path.span, "should have errored in resolve"); return None; diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index b45f344c02653..1d206ac42d339 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -1,7 +1,9 @@ use rustc_ast::ptr::P; use rustc_ast::token::{Delimiter, TokenKind}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; -use rustc_ast::{DUMMY_NODE_ID, EIIImpl, EIIMacroFor, ItemKind, ast, token, tokenstream}; +use rustc_ast::{ + DUMMY_NODE_ID, EIIImpl, EIIMacroFor, ItemKind, Stmt, StmtKind, ast, token, tokenstream, +}; use rustc_ast_pretty::pprust::path_to_string; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::{Ident, Span, kw, sym}; @@ -53,7 +55,13 @@ fn eii_( ) -> Vec { let span = ecx.with_def_site_ctxt(span); - let Annotatable::Item(item) = item else { + let (item, stmt) = if let Annotatable::Item(item) = item { + (item, false) + } else if let Annotatable::Stmt(ref stmt) = item + && let StmtKind::Item(ref item) = stmt.kind + { + (item.clone(), true) + } else { ecx.dcx() .emit_err(EIIMacroExpectedFunction { span, name: path_to_string(&meta_item.path) }); return vec![item]; @@ -106,7 +114,7 @@ fn eii_( is_default: true, // important! }); - return_items.push(Annotatable::Item(P(ast::Item { + return_items.push(P(ast::Item { attrs: ThinVec::new(), id: ast::DUMMY_NODE_ID, span, @@ -128,7 +136,7 @@ fn eii_( stmts: thin_vec![ast::Stmt { id: DUMMY_NODE_ID, kind: ast::StmtKind::Item(P(ast::Item { - attrs: thin_vec![], // TODO: re-add some original attrs + attrs: thin_vec![], // FIXME: re-add some original attrs id: DUMMY_NODE_ID, span: item_span, vis: ast::Visibility { @@ -155,7 +163,7 @@ fn eii_( define_opaque: None, })), tokens: None, - }))) + })) } let decl_span = span.to(func.sig.span); @@ -199,7 +207,7 @@ fn eii_( style: ast::AttrStyle::Outer, span, }); - let extern_block = Annotatable::Item(P(ast::Item { + let extern_block = P(ast::Item { attrs: ast::AttrVec::default(), id: ast::DUMMY_NODE_ID, span, @@ -218,7 +226,7 @@ fn eii_( })]), }), tokens: None, - })); + }); let mut macro_attrs = attrs.clone(); macro_attrs.push( @@ -246,7 +254,7 @@ fn eii_( }, ); - let macro_def = Annotatable::Item(P(ast::Item { + let macro_def = P(ast::Item { attrs: macro_attrs, id: ast::DUMMY_NODE_ID, span, @@ -286,12 +294,21 @@ fn eii_( }, ), tokens: None, - })); + }); return_items.push(extern_block); return_items.push(macro_def); - return_items + if stmt { + return_items + .into_iter() + .map(|i| { + Annotatable::Stmt(P(Stmt { id: DUMMY_NODE_ID, kind: StmtKind::Item(i), span })) + }) + .collect() + } else { + return_items.into_iter().map(|i| Annotatable::Item(i)).collect() + } } use crate::errors::{ @@ -305,10 +322,17 @@ pub(crate) fn eii_macro_for( meta_item: &ast::MetaItem, mut item: Annotatable, ) -> Vec { - let Annotatable::Item(i) = &mut item else { + let i = if let Annotatable::Item(ref mut item) = item { + item + } else if let Annotatable::Stmt(ref mut stmt) = item + && let StmtKind::Item(ref mut item) = stmt.kind + { + item + } else { ecx.dcx().emit_err(EIIMacroForExpectedMacro { span }); return vec![item]; }; + let ItemKind::MacroDef(_, d) = &mut i.kind else { ecx.dcx().emit_err(EIIMacroForExpectedMacro { span }); return vec![item]; @@ -353,7 +377,13 @@ pub(crate) fn eii_macro( meta_item: &ast::MetaItem, mut item: Annotatable, ) -> Vec { - let Annotatable::Item(i) = &mut item else { + let i = if let Annotatable::Item(ref mut item) = item { + item + } else if let Annotatable::Stmt(ref mut stmt) = item + && let StmtKind::Item(ref mut item) = stmt.kind + { + item + } else { ecx.dcx() .emit_err(EIIMacroExpectedFunction { span, name: path_to_string(&meta_item.path) }); return vec![item]; diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 272dd1d4fcc44..159c17b0af757 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1988,7 +1988,6 @@ fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor /// used in any sections, so the linker will therefore pick relevant rlibs for linking, but /// unused `#[no_mangle]` or `#[used]` can still be discard by GC sections. /// -// TODO: does EII solves this? /// There's a few internal crates in the standard library (aka libcore and /// libstd) which actually have a circular dependence upon one another. This /// currently arises through "weak lang items" where libcore requires things From 3ab4ab3e857b3722b7c6ef310878377027b4700b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 9 May 2025 14:12:00 +0200 Subject: [PATCH 40/41] fix error messages --- compiler/rustc_passes/messages.ftl | 5 ----- 1 file changed, 5 deletions(-) diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 766b2ab890321..a6e56c3d956b7 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -440,11 +440,6 @@ passes_invalid_macro_export_arguments = invalid `#[macro_export]` argument passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments -passes_lang_item_fn = {$name -> - [panic_impl] `#[panic_handler]` - *[other] `{$name}` lang item -} function - passes_lang_item_on_incorrect_target = `{$name}` lang item must be applied to a {$expected_target} .label = attribute should be applied to a {$expected_target}, not a {$actual_target} From 7c70314686aa1667000a123887de7db34e7fb0c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 9 May 2025 14:15:00 +0200 Subject: [PATCH 41/41] fix fixmes --- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_middle/src/middle/codegen_fn_attrs.rs | 2 +- compiler/rustc_monomorphize/src/collector.rs | 2 +- compiler/rustc_monomorphize/src/partitioning.rs | 4 +--- compiler/rustc_passes/messages.ftl | 6 ------ compiler/rustc_passes/src/eii.rs | 4 ++-- 6 files changed, 6 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index af37f811a60c6..af2e767de21ef 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -258,7 +258,7 @@ pub(crate) struct CrateRoot { panic_in_drop_strategy: PanicStrategy, edition: Edition, - // TODO: these booleans can be replaced by the entries in `externally_implementable_items` + // FIXME(jdonszelmann): these booleans can be replaced by the entries in `externally_implementable_items` has_global_allocator: bool, has_alloc_error_handler: bool, has_default_lib_allocator: bool, diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index f60d72b99a69f..a04da59d79ec3 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -108,7 +108,7 @@ bitflags::bitflags! { /// `#[no_mangle]`: an indicator that the function's name should be the same /// as its symbol. const NO_MANGLE = 1 << 5; - // TODO: EIIs can replace this, most likely + // FIXME(jdonszelmann): EIIs can replace this, most likely /// `#[rustc_std_internal_symbol]`: an indicator that this symbol is a /// "weird symbol" for the standard library in that it has slightly /// different linkage, visibility, and reachability rules. diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 935aba4ca5269..de787852c60e6 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1555,7 +1555,7 @@ impl<'v> RootCollector<'_, 'v> { self.entry_fn.and_then(|(id, _)| id.as_local()) == Some(def_id) || self.tcx.is_reachable_non_generic(def_id) - // TODO: EII might remove this: + // FIXME(jdonszelmann): EII might remove this: || cfa .flags .contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index bb0349ed44d71..b06f6f73f51af 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -773,8 +773,6 @@ fn mono_item_linkage_and_visibility<'tcx>( // libraries. And shared libraries may later be linked together, both implementing the EII. // This conflicting implementations may show up. We want to ignore this and just link em // together anyway. LLVM ensures the last one is the one that's chosen - // TODO: this isn't the problem if they both decided to choose either the default or the - // same explicit impl but if their view on it differs it is a problem! if let MonoItem::Fn(Instance { def: InstanceKind::EiiShim { weak_linkage, .. }, .. }) = mono_item { @@ -951,7 +949,7 @@ fn mono_item_visibility<'tcx>( // LLVM internalize them as this decision is left up to the linker to // omit them, so prevent them from being internalized. let attrs = tcx.codegen_fn_attrs(def_id); - // TODO: EII might replace this + // FIXME(jdonszelmann): EII might replace this if attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) { *can_be_internalized = false; } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index a6e56c3d956b7..dc1168870ef9e 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -775,12 +775,6 @@ passes_unexportable_type_in_interface = {$desc} with `#[export_stable]` attribut passes_unexportable_type_repr = types with unstable layout are not exportable -passes_undefined_naked_function_abi = - Rust ABI is unsupported in naked functions - -passes_unknown_external_lang_item = - unknown external lang item: `{$lang_item}` - passes_unknown_feature = unknown feature `{$feature}` diff --git a/compiler/rustc_passes/src/eii.rs b/compiler/rustc_passes/src/eii.rs index 23ea8bf22bfff..dbe814d5511ab 100644 --- a/compiler/rustc_passes/src/eii.rs +++ b/compiler/rustc_passes/src/eii.rs @@ -189,8 +189,8 @@ pub(crate) fn get_externally_implementable_item_impls<'tcx>( CRATE_DEF_ID, Some(Symbol::intern(&format!("EII shim for {decl_did:?}"))), DefKind::Fn, - None, - &mut DisambiguatorState::new(), + None, + &mut DisambiguatorState::new(), ); let extern_item_did = decl.eii_extern_item;