diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index a5a835d4a78c3..845eb6a74feed 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -40,6 +40,10 @@ struct LanguageItemCollector<'ast, 'tcx> { // so we can avoid constructing this map for local def-ids. item_spans: FxHashMap, parent_item: Option<&'ast ast::Item>, + /// Weak lang items declared by foreign items, in visit order. Whether + /// they end up missing is decided only once collection has finished, + /// which used to require a second full crate walk. + weak_foreign_candidates: Vec, } impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> { @@ -51,6 +55,7 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> { tcx, resolver, items: LanguageItems::new(), + weak_foreign_candidates: Vec::new(), item_spans: FxHashMap::default(), parent_item: None, } @@ -269,7 +274,8 @@ fn get_lang_items(tcx: TyCtxt<'_>, (): ()) -> LanguageItems { visit::Visitor::visit_crate(&mut collector, krate); // Find all required but not-yet-defined lang items. - weak_lang_items::check_crate(tcx, &mut collector.items, krate); + let weak_foreign_candidates = std::mem::take(&mut collector.weak_foreign_candidates); + weak_lang_items::check_crate(tcx, &mut collector.items, &weak_foreign_candidates); // Return all the lang items that were found. collector.items @@ -314,6 +320,12 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { } fn visit_foreign_item(&mut self, i: &'ast ast::ForeignItem) { + if let Some((lang_item, _)) = extract_ast(&i.attrs) + && let Some(item) = LangItem::from_name(lang_item) + && item.is_weak() + { + self.weak_foreign_candidates.push(item); + } self.check_for_lang( Target::Fn, self.resolver.owners[&i.id].def_id, diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 50730b852455c..d1e50fbfd3fa2 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -1,7 +1,5 @@ //! Validity checking for weak lang items -use rustc_ast as ast; -use rustc_ast::visit; use rustc_data_structures::fx::FxHashSet; use rustc_hir::lang_items::{self, LangItem}; use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS; @@ -10,14 +8,18 @@ use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; use crate::diagnostics::{MissingLangItem, MissingPanicHandler, PanicUnwindWithoutStd}; -use crate::lang_items::extract_ast; /// 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. +/// +/// `weak_foreign_candidates` holds the weak lang items declared by the +/// crate's foreign items, in visit order; the lang item collector records +/// them during its walk so no second crate walk is needed here. Whether a +/// candidate is missing can only be decided now, after collection finished. pub(crate) fn check_crate( tcx: TyCtxt<'_>, items: &mut lang_items::LanguageItems, - krate: &ast::Crate, + weak_foreign_candidates: &[LangItem], ) { // This is never called by user code, it's generated by the compiler. It // will never implicitly be added to the `missing` array unless we do so @@ -26,26 +28,13 @@ pub(crate) fn check_crate( items.missing.push(LangItem::EhPersonality); } - visit::Visitor::visit_crate(&mut WeakLangItemVisitor { items }, krate); - - verify(tcx, items); -} - -struct WeakLangItemVisitor<'a> { - items: &'a mut lang_items::LanguageItems, -} - -impl<'ast> visit::Visitor<'ast> for WeakLangItemVisitor<'_> { - fn visit_foreign_item(&mut self, i: &'ast ast::ForeignItem) { - if let Some((lang_item, _)) = extract_ast(&i.attrs) - && let Some(item) = LangItem::from_name(lang_item) - && item.is_weak() - { - if self.items.get(item).is_none() { - self.items.missing.push(item); - } + for &item in weak_foreign_candidates { + if items.get(item).is_none() { + items.missing.push(item); } } + + verify(tcx, items); } fn verify(tcx: TyCtxt<'_>, items: &lang_items::LanguageItems) {