Skip to content

Commit 640ce99

Browse files
committed
Auto merge of #83738 - jyn514:only-load-some-crates, r=petrochenkov
rustdoc: Don't load all extern crates unconditionally Instead, only load the crates that are linked to with intra-doc links. This doesn't help very much with any of rustdoc's fundamental issues with freezing the resolver, but it at least fixes a stable-to-stable regression, and makes the crate loading model somewhat more consistent with rustc's. I tested and it unfortunately does not help at all with #82496. Closes #68427. Let me know if you want me to open a separate issue for not freezing the resolver. r? `@petrochenkov` cc `@eddyb` `@ollie27`
2 parents ccd9975 + e4244e3 commit 640ce99

File tree

10 files changed

+90
-48
lines changed

10 files changed

+90
-48
lines changed

src/librustdoc/core.rs

+55-31
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use rustc_ast as ast;
12
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
23
use rustc_data_structures::sync::{self, Lrc};
34
use rustc_driver::abort_on_err;
@@ -22,7 +23,7 @@ use rustc_session::DiagnosticOutput;
2223
use rustc_session::Session;
2324
use rustc_span::source_map;
2425
use rustc_span::symbol::sym;
25-
use rustc_span::{Span, DUMMY_SP};
26+
use rustc_span::Span;
2627

2728
use std::cell::RefCell;
2829
use std::collections::hash_map::Entry;
@@ -348,42 +349,65 @@ crate fn create_config(
348349
}
349350

350351
crate fn create_resolver<'a>(
351-
externs: config::Externs,
352352
queries: &Queries<'a>,
353353
sess: &Session,
354354
) -> Rc<RefCell<interface::BoxedResolver>> {
355-
let extern_names: Vec<String> = externs
356-
.iter()
357-
.filter(|(_, entry)| entry.add_prelude)
358-
.map(|(name, _)| name)
359-
.cloned()
360-
.collect();
361-
362355
let parts = abort_on_err(queries.expansion(), sess).peek();
363-
let resolver = parts.1.borrow();
364-
365-
// Before we actually clone it, let's force all the extern'd crates to
366-
// actually be loaded, just in case they're only referred to inside
367-
// intra-doc links
368-
resolver.borrow_mut().access(|resolver| {
369-
sess.time("load_extern_crates", || {
370-
for extern_name in &extern_names {
371-
debug!("loading extern crate {}", extern_name);
372-
if let Err(()) = resolver
373-
.resolve_str_path_error(
374-
DUMMY_SP,
375-
extern_name,
376-
TypeNS,
377-
LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id(),
378-
) {
379-
warn!("unable to resolve external crate {} (do you have an unused `--extern` crate?)", extern_name)
380-
}
356+
let (krate, resolver, _) = &*parts;
357+
let resolver = resolver.borrow().clone();
358+
359+
// Letting the resolver escape at the end of the function leads to inconsistencies between the
360+
// crates the TyCtxt sees and the resolver sees (because the resolver could load more crates
361+
// after escaping). Hopefully `IntraLinkCrateLoader` gets all the crates we need ...
362+
struct IntraLinkCrateLoader {
363+
current_mod: DefId,
364+
resolver: Rc<RefCell<interface::BoxedResolver>>,
365+
}
366+
impl ast::visit::Visitor<'_> for IntraLinkCrateLoader {
367+
fn visit_attribute(&mut self, attr: &ast::Attribute) {
368+
use crate::html::markdown::{markdown_links, MarkdownLink};
369+
use crate::passes::collect_intra_doc_links::Disambiguator;
370+
371+
if let Some(doc) = attr.doc_str() {
372+
for MarkdownLink { link, .. } in markdown_links(&doc.as_str()) {
373+
// FIXME: this misses a *lot* of the preprocessing done in collect_intra_doc_links
374+
// I think most of it shouldn't be necessary since we only need the crate prefix?
375+
let path_str = match Disambiguator::from_str(&link) {
376+
Ok(x) => x.map_or(link.as_str(), |(_, p)| p),
377+
Err(_) => continue,
378+
};
379+
self.resolver.borrow_mut().access(|resolver| {
380+
let _ = resolver.resolve_str_path_error(
381+
attr.span,
382+
path_str,
383+
TypeNS,
384+
self.current_mod,
385+
);
386+
});
387+
}
381388
}
382-
});
383-
});
389+
ast::visit::walk_attribute(self, attr);
390+
}
391+
392+
fn visit_item(&mut self, item: &ast::Item) {
393+
use rustc_ast_lowering::ResolverAstLowering;
394+
395+
if let ast::ItemKind::Mod(..) = item.kind {
396+
let new_mod =
397+
self.resolver.borrow_mut().access(|resolver| resolver.local_def_id(item.id));
398+
let old_mod = mem::replace(&mut self.current_mod, new_mod.to_def_id());
399+
ast::visit::walk_item(self, item);
400+
self.current_mod = old_mod;
401+
} else {
402+
ast::visit::walk_item(self, item);
403+
}
404+
}
405+
}
406+
let crate_id = LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id();
407+
let mut loader = IntraLinkCrateLoader { current_mod: crate_id, resolver };
408+
ast::visit::walk_crate(&mut loader, krate);
384409

385-
// Now we're good to clone the resolver because everything should be loaded
386-
resolver.clone()
410+
loader.resolver
387411
}
388412

389413
crate fn run_global_ctxt(

src/librustdoc/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ extern crate tracing;
3131
//
3232
// Dependencies listed in Cargo.toml do not need `extern crate`.
3333
extern crate rustc_ast;
34+
extern crate rustc_ast_lowering;
3435
extern crate rustc_ast_pretty;
3536
extern crate rustc_attr;
3637
extern crate rustc_data_structures;
@@ -645,7 +646,6 @@ fn main_options(options: config::Options) -> MainResult {
645646
let default_passes = options.default_passes;
646647
let output_format = options.output_format;
647648
// FIXME: fix this clone (especially render_options)
648-
let externs = options.externs.clone();
649649
let manual_passes = options.manual_passes.clone();
650650
let render_options = options.render_options.clone();
651651
let config = core::create_config(options);
@@ -657,7 +657,7 @@ fn main_options(options: config::Options) -> MainResult {
657657
// We need to hold on to the complete resolver, so we cause everything to be
658658
// cloned for the analysis passes to use. Suboptimal, but necessary in the
659659
// current architecture.
660-
let resolver = core::create_resolver(externs, queries, &sess);
660+
let resolver = core::create_resolver(queries, &sess);
661661

662662
if sess.has_errors() {
663663
sess.fatal("Compilation failed, aborting rustdoc");

src/librustdoc/passes/collect_intra_doc_links.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1517,7 +1517,7 @@ fn range_between_backticks(ori_link: &MarkdownLink) -> Range<usize> {
15171517

15181518
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
15191519
/// Disambiguators for a link.
1520-
enum Disambiguator {
1520+
crate enum Disambiguator {
15211521
/// `prim@`
15221522
///
15231523
/// This is buggy, see <https://github.com/rust-lang/rust/pull/77875#discussion_r503583103>
@@ -1546,7 +1546,7 @@ impl Disambiguator {
15461546
/// This returns `Ok(Some(...))` if a disambiguator was found,
15471547
/// `Ok(None)` if no disambiguator was found, or `Err(...)`
15481548
/// if there was a problem with the disambiguator.
1549-
fn from_str(link: &str) -> Result<Option<(Self, &str)>, (String, Range<usize>)> {
1549+
crate fn from_str(link: &str) -> Result<Option<(Self, &str)>, (String, Range<usize>)> {
15501550
use Disambiguator::{Kind, Namespace as NS, Primitive};
15511551

15521552
if let Some(idx) = link.find('@') {

src/librustdoc/passes/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ crate use self::unindent_comments::UNINDENT_COMMENTS;
3030
mod propagate_doc_cfg;
3131
crate use self::propagate_doc_cfg::PROPAGATE_DOC_CFG;
3232

33-
mod collect_intra_doc_links;
33+
crate mod collect_intra_doc_links;
3434
crate use self::collect_intra_doc_links::COLLECT_INTRA_DOC_LINKS;
3535

3636
mod doc_test_lints;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// no-prefer-dynamic
2+
#![crate_type = "lib"]
3+
#![no_std]
4+
#![feature(lang_items)]
5+
6+
use core::panic::PanicInfo;
7+
use core::sync::atomic::{self, Ordering};
8+
9+
#[panic_handler]
10+
fn panic(_info: &PanicInfo) -> ! {
11+
loop {
12+
atomic::compiler_fence(Ordering::SeqCst);
13+
}
14+
}
15+
16+
#[lang = "eh_personality"]
17+
fn foo() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// check-pass
2+
// aux-crate:panic_item=panic-item.rs
3+
// @has unused_extern_crate/index.html
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// aux-build:issue-66159-1.rs
2+
// aux-crate:priv:issue_66159_1=issue-66159-1.rs
3+
// build-aux-docs
4+
// compile-flags:-Z unstable-options
5+
6+
// @has extern_crate_only_used_in_link/index.html
7+
// @has - '//a[@href="../issue_66159_1/struct.Something.html"]' 'issue_66159_1::Something'
8+
//! [issue_66159_1::Something]

src/test/rustdoc/issue-66159.rs

-10
This file was deleted.

src/tools/compiletest/src/header.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -708,8 +708,8 @@ impl Config {
708708
self.parse_name_value_directive(line, "aux-crate").map(|r| {
709709
let mut parts = r.trim().splitn(2, '=');
710710
(
711-
parts.next().expect("aux-crate name").to_string(),
712-
parts.next().expect("aux-crate value").to_string(),
711+
parts.next().expect("missing aux-crate name (e.g. log=log.rs)").to_string(),
712+
parts.next().expect("missing aux-crate value (e.g. log=log.rs)").to_string(),
713713
)
714714
})
715715
}

0 commit comments

Comments
 (0)