diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 114b9835b98cf..bc75d6d79263e 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1951,6 +1951,15 @@ 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, HashStable_Generic)] +pub struct EIIMacroFor { + pub extern_item_path: Path, + pub impl_unsafe: bool, + pub span: Span, } #[derive(Clone, Encodable, Decodable, Debug, Copy, Hash, Eq, PartialEq)] @@ -3578,6 +3587,19 @@ 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, +} + +#[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, + pub is_default: bool, } #[derive(Clone, Encodable, Decodable, Debug)] @@ -3927,7 +3949,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 e49886721e364..fc335902d80f5 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(EIIMacroFor { extern_item_path, impl_unsafe: _, span: _ }) = eii_macro_for { + vis.visit_path(extern_item_path); + } visit_delim_args(vis, body); } @@ -836,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 EIIImpl { node_id, eii_macro_path, .. } in eii_impl { + vis.visit_id(node_id); + vis.visit_path(eii_macro_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 69a186c8cf1b7..f1aa7b5533a90 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,12 @@ 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(EIIMacroFor { extern_item_path, impl_unsafe: _, span: _ }) = + &ts.eii_macro_for + { + try_visit!(visitor.visit_path(extern_item_path, id)); + } } ItemKind::Delegation(box Delegation { id, @@ -953,10 +957,16 @@ 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)); + + 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)); 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 f48a571b86a7d..00a0f1d86b2ea 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -2,9 +2,10 @@ use rustc_abi::ExternAbi; use rustc_ast::ptr::P; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; +use rustc_attr_parsing::{AttributeKind, EIIDecl}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; +use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_hir::{self as hir, HirId, LifetimeSource, PredicateOrigin}; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; @@ -92,7 +93,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) }) } @@ -146,11 +147,88 @@ 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, .. }) if eii_impl.is_empty() => Vec::new(), + ItemKind::Fn(box Fn { eii_impl, .. }) => { + vec![hir::Attribute::Parsed(AttributeKind::EiiImpl( + eii_impl + .iter() + .flat_map( + |EIIImpl { + node_id, + eii_macro_path, + impl_safety, + span, + inner_span, + 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(), + ))] + } + ItemKind::MacroDef( + _, + MacroDef { + eii_macro_for: Some(EIIMacroFor { extern_item_path, impl_unsafe, 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(..) + | 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 attrs = self.lower_attrs(hir_id, &i.attrs, i.span); + + 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, @@ -462,7 +540,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,7 +551,12 @@ 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 }); + let macro_def = self.arena.alloc(ast::MacroDef { + body, + macro_rules: *macro_rules, + eii_macro_for: None, + }); + hir::ItemKind::Macro(ident, macro_def, macro_kind) } ItemKind::Delegation(box delegation) => { @@ -492,6 +575,16 @@ impl<'hir> LoweringContext<'_, 'hir> { } } + fn lower_path_simple_eii(&mut self, id: NodeId, path: &Path) -> Option { + 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; + }; + + Some(did) + } + fn lower_const_item( &mut self, ty: &Ty, @@ -635,7 +728,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; @@ -709,7 +802,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), @@ -771,7 +864,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, @@ -790,7 +883,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 { @@ -983,7 +1076,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 { @@ -1176,7 +1269,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), @@ -1885,7 +1978,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..4835dd3e4252d 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() { + if attrs.is_empty() && extra_hir_attributes.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..e7609b8e05286 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 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)); - 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..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 { @@ -2128,6 +2139,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 +2162,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..8445988373873 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; @@ -672,10 +671,24 @@ 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()); + for EIIImpl { eii_macro_path, impl_safety, .. } in eii_impl { + self.word("#["); + 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(); + } + let body_cb_ib = body.as_ref().map(|body| (body, self.head(""))); self.print_visibility(vis); diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index d2d1285b0756f..ced25f307e0bd 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; @@ -138,6 +139,23 @@ impl Deprecation { } } +#[derive(Copy, 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, + 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. @@ -189,6 +207,9 @@ pub enum AttributeKind { span: Span, comment: Symbol, }, + EiiImpl(ThinVec), + EiiMacroFor(EIIDecl), + EiiMangleExtern, 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_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_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 55c3df003fe16..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,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_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 73be954cefd76..19190f1e267e0 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/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/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs new file mode 100644 index 0000000000000..1d206ac42d339 --- /dev/null +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -0,0 +1,423 @@ +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, 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}; +use thin_vec::{ThinVec, thin_vec}; + +// ```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) +} + +pub(crate) fn unsafe_eii( + ecx: &mut ExtCtxt<'_>, + span: Span, + meta_item: &ast::MetaItem, + item: Annotatable, +) -> Vec { + eii_(ecx, span, meta_item, item, true) +} + +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); + + 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]; + }; + + let orig_item = item.clone(); + + let item = item.into_inner(); + + 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) }); + 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 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(P(ast::Item { + attrs: ThinVec::new(), + id: ast::DUMMY_NODE_ID, + span, + vis: ast::Visibility { span, kind: ast::VisibilityKind::Inherited, tokens: None }, + 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 { + 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![], // FIXME: re-add some original attrs + id: DUMMY_NODE_ID, + span: item_span, + vis: ast::Visibility { + span, + kind: ast::VisibilityKind::Inherited, + tokens: None + }, + kind: ItemKind::Fn(default_func), + tokens: None, + })), + span + }], + id: DUMMY_NODE_ID, + rules: ast::BlockCheckMode::Default, + span, + tokens: None, + }), + None, + ), + span, + attrs: ThinVec::new(), + tokens: None, + })), + define_opaque: 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), + // 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(); } + // #[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 = 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: attrs.clone(), + id: ast::DUMMY_NODE_ID, + span: item_span, + vis, + kind: ast::ForeignItemKind::Fn(func.clone()), + tokens: None, + })]), + }), + 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, + }, + tokens: None, + })), + id: ecx.sess.psess.attr_id_generator.mk_attr_id(), + style: ast::AttrStyle::Outer, + span, + }, + ); + + let macro_def = P(ast::Item { + attrs: macro_attrs, + 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(func.ident)] + eii_macro_for: Some(ast::EIIMacroFor { + extern_item_path: ast::Path::from_ident(func.ident), + impl_unsafe, + span: decl_span, + }), + }, + ), + tokens: None, + }); + + return_items.push(extern_block); + return_items.push(macro_def); + + 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::{ + EIIMacroExpectedFunction, EIIMacroExpectedMaxOneArgument, EIIMacroForExpectedList, + EIIMacroForExpectedMacro, EIIMacroForExpectedUnsafe, +}; + +pub(crate) fn eii_macro_for( + ecx: &mut ExtCtxt<'_>, + span: Span, + meta_item: &ast::MetaItem, + mut item: Annotatable, +) -> Vec { + 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]; + }; + + let Some(list) = meta_item.meta_item_list() else { + ecx.dcx().emit_err(EIIMacroForExpectedList { span: meta_item.span }); + return vec![item]; + }; + + 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 { + 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 { + ecx.dcx().emit_err(EIIMacroForExpectedUnsafe { span: i.span() }); + return vec![item]; + } + } else { + false + }; + + d.eii_macro_for = Some(EIIMacroFor { extern_item_path, impl_unsafe, span }); + + // 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 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]; + }; + + let ItemKind::Fn(f) = &mut i.kind else { + ecx.dcx() + .emit_err(EIIMacroExpectedFunction { span, name: path_to_string(&meta_item.path) }); + return vec![item]; + }; + + 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, + eii_macro_path: meta_item.path.clone(), + impl_safety: meta_item.unsafety, + span, + inner_span: meta_item.path.span, + is_default, + }); + + vec![item] +} 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_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 c2f5bf0f4571f..61cc87b6a87dd 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,10 @@ 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, + unsafe_eii: eii::unsafe_eii, + 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_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 06ba5b4f6a752..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, tcx.mk_args(&[ty.into()])), ExportedSymbol::NonGeneric(..) | ExportedSymbol::ThreadLocalShim(..) - | ExportedSymbol::NoDefId(..) => { + | ExportedSymbol::NoDefId(..) + | ExportedSymbol::Alias { .. } => { // These are no monomorphizations continue; } @@ -645,6 +659,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 +687,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 5d09e62f2742d..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,13 +112,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if let hir::Attribute::Parsed(p) = attr { match p { + AttributeKind::EiiMangleExtern => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::EII_MANGLE_EXTERN; + } AttributeKind::Repr(reprs) => { codegen_fn_attrs.alignment = reprs .iter() .filter_map(|(r, _)| if let ReprAlign(x) = r { Some(*x) } else { None }) .max(); } - _ => {} } } @@ -755,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/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index 35c3e3ed3150e..a5572810b335c 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -39,6 +39,8 @@ fn constness(tcx: TyCtxt<'_>, 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_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_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_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_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index c117e0fcf7ccc..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), @@ -1072,6 +1071,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_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index a5f89b7a076ae..84755fd5047af 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. @@ -478,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. 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/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 107aea4e5a401..2f7620a1ffc62 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), ItemKind::Macro(ident, def, mk), (*ident, def, *mk); expect_mod, (Ident, &'hir Mod<'hir>), ItemKind::Mod(ident, m), (*ident, m); 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/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 21d36ed54cdf4..6db9fb6543408 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, }) }) @@ -287,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_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/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_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 277bb7bd3e15c..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 @@ -294,6 +298,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 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 declaration + .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 new file mode 100644 index 0000000000000..66d55eab6fff3 --- /dev/null +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -0,0 +1,429 @@ +use std::borrow::Cow; +use std::iter; + +use rustc_data_structures::fx::FxIndexSet; +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}; +use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; +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; +use rustc_trait_selection::traits::ObligationCtxt; +use tracing::{debug, instrument}; + +use super::potentially_plural_count; +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, +/// 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> { + 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, + 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(implementation_generics) = tcx.hir_get_generics(external_impl) { + let mut impl_bounds = 0; + 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 { + impl_bounds += 1; + } + } + } + } + if impl_bounds == bounds_span.len() { + bounds_span = vec![]; + } else if implementation_generics.has_where_clause_predicates { + where_span = Some(implementation_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)) + .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); + 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, + E0805, + "`{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. +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, + 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 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, + tcx.fn_sig(external_impl).instantiate( + tcx, + infcx.fresh_args_for_item(external_impl_span, external_impl.to_def_id()), + ), + ); + let external_impl_sig = ocx.normalize(&norm_cause, param_env, external_impl_sig); + debug!(?external_impl_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"); + + let emitted = report_eii_mismatch( + infcx, + cause, + param_env, + terr, + (declaration, declaration_sig), + (external_impl, external_impl_sig), + eii_attr_span, + eii_name, + ); + 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>), + eii_attr_span: Span, + eii_name: Symbol, +) -> 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, + E0805, + "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 { + // 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 (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| { + 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"); + } + }); + + 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).or_else(|| Some(tcx.def_span(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/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..b384603680a64 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, 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}; @@ -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_function_types; use crate::autoderef::Autoderef; use crate::collect::CollectItemTypesVisitor; use crate::constrained_generic_params::{Parameter, identify_constrained_generic_params}; @@ -1320,6 +1322,31 @@ 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. + for EIIImpl { eii_macro, span, .. } 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(EIIDecl {eii_extern_item, ..}) => *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" + ) + } + } + 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_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 4520fbe352cea..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}; @@ -676,7 +677,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, .. } => { @@ -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/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_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 2b1661aaac8f0..638ead4a2d520 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -207,6 +207,31 @@ 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_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_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 99103f14d6823..e9e380a1541f4 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -2,7 +2,6 @@ use std::cell::RefCell; use rustc_abi::ExternAbi; use rustc_hir as hir; -use rustc_hir::def::DefKind; use rustc_hir::lang_items::LangItem; use rustc_hir_analysis::check::check_function_signature; use rustc_infer::infer::RegionVariableOrigin; @@ -150,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); } @@ -162,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_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_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/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 bd813cadedcd4..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!( @@ -1473,6 +1472,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>, @@ -1513,7 +1519,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/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 76bae39ef8c00..79e18fe790ffd 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; @@ -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 } @@ -373,6 +372,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 +456,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 7ac72ef814a9c..f2aa9cd1a8940 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())); @@ -713,7 +716,8 @@ 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( attrs, sym::default_lib_allocator, @@ -1851,7 +1855,9 @@ 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(); + 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); } @@ -1868,6 +1874,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..af2e767de21ef 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,12 @@ pub(crate) struct CrateRoot { required_panic_strategy: Option, panic_in_drop_strategy: PanicStrategy, edition: Edition, + + // FIXME(jdonszelmann): 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..3520eb428bc32 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_middle::middle::eii::EiiMap, ]); ) } diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index fee707f7b4c90..400f272772cd2 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.get_externally_implementable_item_impls(()).get(&hir_id.owner.def_id) + { + self.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..044c2d8b6b169 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_idents(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/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 00da1a6aeec7d..a04da59d79ec3 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; + // 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. @@ -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/eii.rs b/compiler/rustc_middle/src/middle/eii.rs new file mode 100644 index 0000000000000..f8e5724c303ca --- /dev/null +++ b/compiler/rustc_middle/src/middle/eii.rs @@ -0,0 +1,13 @@ +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 weak_linkage: bool, +} + +pub type EiiMap = FxIndexMap; 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/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/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..5b1926f154eb6 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -181,6 +181,15 @@ impl<'tcx> MonoItem<'tcx> { return opt_incr_drop_glue_mode(tcx, ty); } + // 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 }; + } + // 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. @@ -374,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, @@ -532,7 +541,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/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 1777756174bf9..bdec91e2c57f6 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: _, weak_linkage: _ } => {} 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..53f5114f1fefb 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; @@ -51,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; @@ -1113,6 +1115,10 @@ rustc_queries! { desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) } } + query get_externally_implementable_item_impls(_: ()) -> &'tcx EiiMap { + desc { "check externally implementable items" } + } + query check_mod_naked_functions(key: LocalModDefId) { desc { |tcx| "checking naked functions in {}", describe_as_module(key, tcx) } } @@ -1731,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]`" } @@ -1907,6 +1908,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/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_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_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 0d99a1b51499a..848a940c0e0ee 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, weak_linkage: bool }, } 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,12 @@ 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, 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_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..c187e617f851c 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -114,6 +114,64 @@ 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, weak_linkage: _ } => { + let source = MirSource::from_instance(e); + + // 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(chosen_fn_ty), + })); + + // 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); + 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, shim_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..de787852c60e6 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -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; @@ -964,7 +965,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 +1408,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) + // FIXME(jdonszelmann): EII might remove this: + || cfa .flags .contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) } @@ -1606,6 +1610,28 @@ 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 (shim_did, &EiiMapping { extern_item, chosen_impl, weak_linkage, .. }) in + self.tcx.get_externally_implementable_item_impls(()) + { + self.output.push(create_fn_mono_item( + self.tcx, + ty::Instance { + def: ty::InstanceKind::EiiShim { + def_id: (*shim_did).into(), + extern_item, + chosen_impl, + weak_linkage, + }, + args: ty::GenericArgs::empty(), + }, + DUMMY_SP, + )); + } + } } #[instrument(level = "debug", skip(tcx, output))] diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 6948dceddf904..b06f6f73f51af 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}; @@ -633,6 +633,14 @@ 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: _, + weak_linkage: _, + } => extern_item, ty::InstanceKind::VTableShim(..) | ty::InstanceKind::ReifyShim(..) | ty::InstanceKind::FnPtrShim(..) @@ -752,6 +760,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, @@ -759,7 +768,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 + 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) + } } type CguNameCache = UnordMap<(DefId, bool), Symbol>; @@ -802,6 +822,15 @@ fn mono_item_visibility<'tcx>( | InstanceKind::AsyncDropGlue(def_id, _) | 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 + // 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 +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); + // FIXME(jdonszelmann): EII might replace this if attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) { *can_be_internalized = false; } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index babc55ccc0f9e..8b4891f568167 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)) { @@ -2204,7 +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 })) + 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 +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 })) + 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/messages.ftl b/compiler/rustc_passes/messages.ftl index 6d815e510ea20..dc1168870ef9e 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 @@ -311,6 +322,25 @@ 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 + +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 = + `#[{$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 .label = not a free function, impl method or static @@ -410,19 +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_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} @@ -491,9 +508,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 @@ -761,9 +775,6 @@ passes_unexportable_type_in_interface = {$desc} with `#[export_stable]` attribut passes_unexportable_type_repr = types with unstable layout are not exportable -passes_unknown_external_lang_item = - unknown external lang item: `{$lang_item}` - passes_unknown_feature = unknown feature `{$feature}` diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c68f8df49fc70..c37d2ee98bbc1 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, 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}; @@ -124,6 +124,15 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::Stability { span, .. } | AttributeKind::ConstStability { span, .. }, ) => self.check_stability_promotable(*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::EiiMangleExtern { .. }) => { + // FIXME: mangle extern should be removed + } Attribute::Parsed(AttributeKind::AllowInternalUnstable(syms)) => self .check_allow_internal_unstable( hir_id, @@ -290,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 @@ -474,6 +482,36 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } + 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, is_default: _ } 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(EIIDecl { 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(), + }, + }); + } + } + } + /// 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) { @@ -763,12 +801,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 @@ -872,12 +921,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. @@ -2680,9 +2740,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(_, ast_macro_def, _) = 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/dead.rs b/compiler/rustc_passes/src/dead.rs index 0060e726a8e05..2d4a9f1fd1903 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}; @@ -690,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 { @@ -814,6 +813,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 new file mode 100644 index 0000000000000..dbe814d5511ab --- /dev/null +++ b/compiler/rustc_passes/src/eii.rs @@ -0,0 +1,217 @@ +//! Validity checking for weak lang items + +use std::iter; + +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::bug; +use rustc_middle::middle::eii::EiiMapping; +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_externally_implementable_item_impls<'tcx>( + tcx: TyCtxt<'tcx>, + (): (), +) -> &'tcx FxIndexMap { + #[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 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)); + + // 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(|| FoundEii { + decl: *decl, + decl_crate: cnum, + impls: Default::default(), + }) + .impls + .extend( + impls + .into_iter() + .map(|(did, i)| (*did, FoundImpl { imp: *i, impl_crate: 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, 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, FoundImpl { imp, impl_crate }) in impls { + if imp.is_default { + // println!("found default impl in {}", tcx.crate_name(cnum)); + default_impls.push((impl_did, impl_crate)); + } else { + // println!("found impl in {}", tcx.crate_name(cnum)); + explicit_impls.push((impl_did, impl_crate)); + } + } + + 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"); + } + + 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; + + 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( + 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 00682a9c7a794..8a439754210a3 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -854,18 +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_missing_panic_handler)] -pub(crate) struct MissingPanicHandler; - #[derive(Diagnostic)] #[diag(passes_panic_unwind_without_std)] #[help] @@ -881,8 +869,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 +879,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, @@ -1973,3 +1961,70 @@ pub(crate) enum UnexportableItem<'a> { field_name: &'a str, }, } + +#[derive(Diagnostic)] +#[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, +} + +#[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, + pub decl_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/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/lib.rs b/compiler/rustc_passes/src/lib.rs index 001725e28827d..d03d28d2cd2c4 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,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_externally_implementable_item_impls; } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index f0e8fa986feae..2bdf679047fbc 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; @@ -178,13 +179,26 @@ 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 }; 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(_)) + || self + .tcx + .get_externally_implementable_item_impls(()) + .contains_key(&search_item); + + if is_extern || eii_impl { self.reachable_symbols.insert(search_item); } } else { @@ -235,7 +249,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 { .. } @@ -381,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; @@ -415,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" @@ -466,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 @@ -477,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() { diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 93d164e7d01f8..9836bb451453a 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}; /// 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. @@ -33,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) @@ -52,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 }); } } } @@ -84,9 +79,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..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) - && !tcx.has_panic_handler(cnum) + && tcx.externally_implementable_items(cnum).is_empty() }) { maybe_unused_extern_crates.insert(id, import.span); } 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/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index faee0e7dd5ff9..ab2982103e9d5 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 EIIImpl { node_id, eii_macro_path, .. } in &f.eii_impl { + self.smart_resolve_path(*node_id, &None, &eii_macro_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 @@ -2835,6 +2849,17 @@ 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(EIIMacroFor { extern_item_path, impl_unsafe: _, span: _ }) = + ¯o_def.eii_macro_for + { + self.smart_resolve_path( + item.id, + &None, + extern_item_path, + PathSource::Expr(None), + ); + } } ItemKind::ForeignMod(_) | ItemKind::GlobalAsm(_) => { 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 { 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 f2f6d1a3bcf83..068d737b6ec3a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -875,6 +875,12 @@ symbols! { effects, eh_catch_typeinfo, eh_personality, + eii, + eii_impl, + eii_internals, + eii_macro, + eii_macro_for, + eii_mangle_extern, emit, emit_enum, emit_enum_variant, @@ -2219,6 +2225,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/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index a51d7da878a29..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}; @@ -240,6 +241,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 +259,19 @@ 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 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 { + 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 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/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( 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/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/macros/mod.rs b/library/core/src/macros/mod.rs index 7dc8c060cd5bc..8e7036379ea13 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1783,4 +1783,32 @@ pub(crate) mod builtin { pub macro deref($pat:pat) { 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 = "125418")] + #[rustc_builtin_macro] + #[allow_internal_unstable(eii_internals, decl_macro, rustc_attrs)] + pub macro eii($item:item) { + /* 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 = "125418")] + #[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")] + #[rustc_builtin_macro] + pub macro eii_macro_for($item:item) { + /* compiler built-in */ + } } diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index 5fa340a6147f6..df41d5d3fadde 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -16,6 +16,14 @@ 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)] +#[lang = "panic_impl"] +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) + } } ) } diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index 9737d0baec7ca..dad7d16eb562d 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 = "125418")] +#[cfg(not(bootstrap))] +pub use crate::macros::builtin::{eii, unsafe_eii}; + +#[unstable(feature = "eii_internals", issue = "none")] +#[cfg(not(bootstrap))] +pub use crate::macros::builtin::eii_macro_for; diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 68c9ac1e41463..ca45a70919327 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 = "125418")] +#[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`. 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 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) 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/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/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..9545ad007c57a --- /dev/null +++ b/tests/ui/eii/auxiliary/codegen2.rs @@ -0,0 +1,6 @@ +//@ 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..2b882c48d829a --- /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)] +pub fn decl2(x: u64); + +mod private { + #[eii(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 new file mode 100644 index 0000000000000..36a42ad199b0f --- /dev/null +++ b/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs @@ -0,0 +1,16 @@ +//@ no-prefer-dynamic +#![crate_type = "rlib"] +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[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/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.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/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..f53902875445e --- /dev/null +++ b/tests/ui/eii/cross_crate_wrong_ty.stderr @@ -0,0 +1,16 @@ +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 + | + ::: $DIR/auxiliary/cross_crate_eii_declaration.rs:15:5 + | +LL | pub safe fn bar(x: u64) -> u64; + | ------------------------------- requires 1 parameter + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0050`. 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..b1811b07eb17e --- /dev/null +++ b/tests/ui/eii/default/auxiliary/decl_with_default.rs @@ -0,0 +1,8 @@ +//@ 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..81557fa6891b8 --- /dev/null +++ b/tests/ui/eii/duplicate/auxiliary/decl.rs @@ -0,0 +1,6 @@ +//@ 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..d7c27f4dfde92 --- /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)] +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..c6336c1166e75 --- /dev/null +++ b/tests/ui/eii/duplicate/duplicate1.rs @@ -0,0 +1,12 @@ +//@ no-prefer-dynamic +//@ aux-build: impl1.rs +//@ 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; + +fn main() {} diff --git a/tests/ui/eii/duplicate/duplicate1.stderr b/tests/ui/eii/duplicate/duplicate1.stderr new file mode 100644 index 0000000000000..54cc141f88694 --- /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..e2b0acdbf30e8 --- /dev/null +++ b/tests/ui/eii/duplicate/duplicate2.rs @@ -0,0 +1,14 @@ +//@ no-prefer-dynamic +//@ aux-build: impl1.rs +//@ aux-build: impl2.rs +//@ 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; + +fn main() {} diff --git a/tests/ui/eii/duplicate/duplicate2.stderr b/tests/ui/eii/duplicate/duplicate2.stderr new file mode 100644 index 0000000000000..033e43c8b2fbd --- /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..87e6c409b10e8 --- /dev/null +++ b/tests/ui/eii/duplicate/duplicate3.rs @@ -0,0 +1,16 @@ +//@ no-prefer-dynamic +//@ aux-build: impl1.rs +//@ aux-build: impl2.rs +//@ aux-build: impl3.rs +//@ 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; +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..801d40e69c552 --- /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/errors.rs b/tests/ui/eii/errors.rs new file mode 100644 index 0000000000000..fab549c9e4b42 --- /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)] + +#[eii_macro_for(bar)] //~ ERROR `#[eii_macro_for(...)]` is only valid on macros +fn hello() { + #[eii_macro_for(bar)] //~ ERROR `#[eii_macro_for(...)]` is only valid on macros + let x = 3 + 3; +} + +#[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() {} + +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..b978125c502b8 --- /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 | #[eii_macro_for(bar)] + | ^^^^^^^^^^^^^^^^^^^^^ + +error: `#[eii_macro_for(...)]` is only valid on macros + --> $DIR/errors.rs:9:5 + | +LL | #[eii_macro_for(bar)] + | ^^^^^^^^^^^^^^^^^^^^^ + +error: `#[eii_macro_for(...)]` expects a list of one or two elements + --> $DIR/errors.rs:13:1 + | +LL | #[eii_macro_for] + | ^^^^^^^^^^^^^^^^ + +error: `#[eii_macro_for(...)]` expects a list of one or two elements + --> $DIR/errors.rs:14:1 + | +LL | #[eii_macro_for()] + | ^^^^^^^^^^^^^^^^^^ + +error: expected this argument to be "unsafe" + --> $DIR/errors.rs:15:22 + | +LL | #[eii_macro_for(bar, hello)] + | ^^^^^ + | +note: the second argument is optional + --> $DIR/errors.rs:15:22 + | +LL | #[eii_macro_for(bar, hello)] + | ^^^^^ + +error: `#[eii_macro_for(...)]` expects a list of one or two elements + --> $DIR/errors.rs:16:1 + | +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 | #[eii_macro_for(bar, hello, "unsafe")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[eii_macro_for(...)]` expects a list of one or two elements + --> $DIR/errors.rs:18:1 + | +LL | #[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 + 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..ec6405c11d2a4 --- /dev/null +++ b/tests/ui/eii/privacy2.rs @@ -0,0 +1,26 @@ +//@ aux-build:codegen3.rs +#![feature(eii)] + +extern crate codegen3 as codegen; + +// has a span but in the other crate +//~? ERROR `#[eii2]` required, but not found +//~? ERROR `#[eii3]` required, but not found + +#[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..a2e0977542a40 --- /dev/null +++ b/tests/ui/eii/privacy2.stderr @@ -0,0 +1,38 @@ +error[E0433]: failed to resolve: could not find `eii3` in `codegen` + --> $DIR/privacy2.rs:15:12 + | +LL | #[codegen::eii3] + | ^^^^ could not find `eii3` in `codegen` + +error[E0603]: function `decl1` is private + --> $DIR/privacy2.rs:25: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: `#[eii2]` required, but not found + --> $DIR/auxiliary/codegen3.rs:9:1 + | +LL | #[eii(eii2)] + | ^^^^^^^^^^^^ expected because `#[eii2]` was declared here in crate `codegen3` + | + = help: expected at least one implementation in crate `privacy2` or any of its dependencies + +error: `#[eii3]` required, but not found + --> $DIR/auxiliary/codegen3.rs:13:5 + | +LL | #[eii(eii3)] + | ^^^^^^^^^^^^ expected because `#[eii3]` was declared here in crate `codegen3` + | + = help: expected at least one implementation in crate `privacy2` or any of its dependencies + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0433, E0603. +For more information about an error, try `rustc --explain E0433`. diff --git a/tests/ui/eii/subtype_1.rs b/tests/ui/eii/subtype_1.rs new file mode 100644 index 0000000000000..f50c87887fe8a --- /dev/null +++ b/tests/ui/eii/subtype_1.rs @@ -0,0 +1,25 @@ +//@ compile-flags: --crate-type rlib +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[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 { +//~^ ERROR lifetime parameters or bounds of `other` do not match the declaration + &0 +} + +fn main() { + bar(&0); +} diff --git a/tests/ui/eii/subtype_1.stderr b/tests/ui/eii/subtype_1.stderr new file mode 100644 index 0000000000000..6a4ef6e16f9db --- /dev/null +++ b/tests/ui/eii/subtype_1.stderr @@ -0,0 +1,13 @@ +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 +... +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 new file mode 100644 index 0000000000000..e771fb7182552 --- /dev/null +++ b/tests/ui/eii/subtype_2.rs @@ -0,0 +1,25 @@ +//@ compile-flags: --crate-type rlib +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[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 { +//~^ ERROR lifetime parameters or bounds of `other` do not match the declaration + &0 +} + +fn main() { + bar(&0); +} diff --git a/tests/ui/eii/subtype_2.stderr b/tests/ui/eii/subtype_2.stderr new file mode 100644 index 0000000000000..5c925ca380e01 --- /dev/null +++ b/tests/ui/eii/subtype_2.stderr @@ -0,0 +1,13 @@ +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; + | ---- 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/subtype_3.rs b/tests/ui/eii/subtype_3.rs new file mode 100644 index 0000000000000..b685ee1d222a8 --- /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)] + +#[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..c3384bbbfe69d --- /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)] + +#[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/unsafe_impl_err.rs b/tests/ui/eii/unsafe_impl_err.rs new file mode 100644 index 0000000000000..423f5b1a93bec --- /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)] + +#[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..278dd9084220e --- /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)] + +#[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..0d8df934a38cf --- /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)] + +#[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..2cdd69bbdbdf0 --- /dev/null +++ b/tests/ui/eii/wrong_ret_ty.stderr @@ -0,0 +1,26 @@ +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 + | +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..0e06359b72526 --- /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)] + +#[eii_macro_for(bar)] +#[rustc_builtin_macro(eii_macro)] +macro foo() { + +} + +unsafe extern "Rust" { + safe fn bar(x: u64) -> u64; +} + +#[foo] +fn other(x: usize) -> 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..fae713a35aa96 --- /dev/null +++ b/tests/ui/eii/wrong_ty.stderr @@ -0,0 +1,27 @@ +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 + | +LL | safe fn bar(x: u64) -> u64; + | ^^^ + = note: expected signature `fn(u64) -> _` + 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 + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/eii/wrong_ty_2.rs b/tests/ui/eii/wrong_ty_2.rs new file mode 100644 index 0000000000000..665a2833da1d8 --- /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)] + +#[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 `other` has 0 parameters but #[foo] requires it to have + 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..2ed00f9e55ee0 --- /dev/null +++ b/tests/ui/eii/wrong_ty_2.stderr @@ -0,0 +1,14 @@ +error[E0050]: `other` has 0 parameters but #[foo] requires it to have 1 + --> $DIR/wrong_ty_2.rs:18:1 + | +LL | safe fn bar(x: u64) -> u64; + | --- 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 E0050`. 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/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`. 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`. 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/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`. 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`.