1#![cfg_attr(bootstrap, feature(debug_closure_helpers))]
3#![doc(
4 html_root_url = "https://doc.rust-lang.org/nightly/",
5 html_playground_url = "https://play.rust-lang.org/"
6)]
7#![feature(ascii_char)]
8#![feature(ascii_char_variants)]
9#![feature(assert_matches)]
10#![feature(box_into_inner)]
11#![feature(box_patterns)]
12#![feature(file_buffered)]
13#![feature(formatting_options)]
14#![feature(if_let_guard)]
15#![feature(iter_advance_by)]
16#![feature(iter_intersperse)]
17#![feature(iter_order_by)]
18#![feature(rustc_private)]
19#![feature(test)]
20#![feature(trim_prefix_suffix)]
21#![warn(rustc::internal)]
22extern crate rustc_abi;
33extern crate rustc_ast;
34extern crate rustc_ast_pretty;
35extern crate rustc_attr_parsing;
36extern crate rustc_data_structures;
37extern crate rustc_driver;
38extern crate rustc_errors;
39extern crate rustc_feature;
40extern crate rustc_hir;
41extern crate rustc_hir_analysis;
42extern crate rustc_hir_pretty;
43extern crate rustc_index;
44extern crate rustc_infer;
45extern crate rustc_interface;
46extern crate rustc_lexer;
47extern crate rustc_lint;
48extern crate rustc_lint_defs;
49extern crate rustc_log;
50extern crate rustc_macros;
51extern crate rustc_metadata;
52extern crate rustc_middle;
53extern crate rustc_parse;
54extern crate rustc_passes;
55extern crate rustc_resolve;
56extern crate rustc_serialize;
57extern crate rustc_session;
58extern crate rustc_span;
59extern crate rustc_target;
60extern crate rustc_trait_selection;
61extern crate test;
62
63#[cfg(feature = "jemalloc")]
70extern crate tikv_jemalloc_sys as _;
71
72use std::env::{self, VarError};
73use std::io::{self, IsTerminal};
74use std::path::Path;
75use std::process;
76
77use rustc_errors::DiagCtxtHandle;
78use rustc_hir::def_id::LOCAL_CRATE;
79use rustc_hir::lints::DelayedLint;
80use rustc_interface::interface;
81use rustc_middle::ty::TyCtxt;
82use rustc_session::config::{ErrorOutputType, RustcOptGroup, make_crate_type_option};
83use rustc_session::{EarlyDiagCtxt, getopts};
84use tracing::info;
85
86use crate::clean::utils::DOC_RUST_LANG_ORG_VERSION;
87use crate::error::Error;
88use crate::formats::cache::Cache;
89
90macro_rules! map {
101 ($( $key: expr => $val: expr ),* $(,)*) => {{
102 let mut map = ::rustc_data_structures::fx::FxIndexMap::default();
103 $( map.insert($key, $val); )*
104 map
105 }}
106}
107
108mod clean;
109mod config;
110mod core;
111mod display;
112mod docfs;
113mod doctest;
114mod error;
115mod externalfiles;
116mod fold;
117mod formats;
118pub mod html;
120mod json;
121pub(crate) mod lint;
122mod markdown;
123mod passes;
124mod scrape_examples;
125mod theme;
126mod visit;
127mod visit_ast;
128mod visit_lib;
129
130pub fn main() {
131 let mut early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
132
133 rustc_driver::install_ice_hook(
134 "https://github.com/rust-lang/rust/issues/new\
135 ?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md",
136 |_| (),
137 );
138
139 crate::init_logging(&early_dcx);
147 match rustc_log::init_logger(rustc_log::LoggerConfig::from_env("RUSTDOC_LOG")) {
148 Ok(()) => {}
149 Err(rustc_log::Error::AlreadyInit(_)) => {}
165 Err(error) => early_dcx.early_fatal(error.to_string()),
166 }
167
168 let exit_code = rustc_driver::catch_with_exit_code(|| {
169 let at_args = rustc_driver::args::raw_args(&early_dcx);
170 main_args(&mut early_dcx, &at_args);
171 });
172 process::exit(exit_code);
173}
174
175fn init_logging(early_dcx: &EarlyDiagCtxt) {
176 let color_logs = match env::var("RUSTDOC_LOG_COLOR").as_deref() {
177 Ok("always") => true,
178 Ok("never") => false,
179 Ok("auto") | Err(VarError::NotPresent) => io::stdout().is_terminal(),
180 Ok(value) => early_dcx.early_fatal(format!(
181 "invalid log color value '{value}': expected one of always, never, or auto",
182 )),
183 Err(VarError::NotUnicode(value)) => early_dcx.early_fatal(format!(
184 "invalid log color value '{}': expected one of always, never, or auto",
185 value.to_string_lossy()
186 )),
187 };
188 let filter = tracing_subscriber::EnvFilter::from_env("RUSTDOC_LOG");
189 let layer = tracing_tree::HierarchicalLayer::default()
190 .with_writer(io::stderr)
191 .with_ansi(color_logs)
192 .with_targets(true)
193 .with_wraparound(10)
194 .with_verbose_exit(true)
195 .with_verbose_entry(true)
196 .with_indent_amount(2);
197 #[cfg(debug_assertions)]
198 let layer = layer.with_thread_ids(true).with_thread_names(true);
199
200 use tracing_subscriber::layer::SubscriberExt;
201 let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
202 tracing::subscriber::set_global_default(subscriber).unwrap();
203}
204
205fn opts() -> Vec<RustcOptGroup> {
206 use rustc_session::config::OptionKind::{Flag, FlagMulti, Multi, Opt};
207 use rustc_session::config::OptionStability::{Stable, Unstable};
208 use rustc_session::config::make_opt as opt;
209
210 vec![
211 opt(Stable, FlagMulti, "h", "help", "show this help message", ""),
212 opt(Stable, FlagMulti, "V", "version", "print rustdoc's version", ""),
213 opt(Stable, FlagMulti, "v", "verbose", "use verbose output", ""),
214 opt(Stable, Opt, "w", "output-format", "the output type to write", "[html]"),
215 opt(
216 Stable,
217 Opt,
218 "",
219 "output",
220 "Which directory to place the output. This option is deprecated, use --out-dir instead.",
221 "PATH",
222 ),
223 opt(Stable, Opt, "o", "out-dir", "which directory to place the output", "PATH"),
224 opt(Stable, Opt, "", "crate-name", "specify the name of this crate", "NAME"),
225 make_crate_type_option(),
226 opt(Stable, Multi, "L", "library-path", "directory to add to crate search path", "DIR"),
227 opt(Stable, Multi, "", "cfg", "pass a --cfg to rustc", ""),
228 opt(Stable, Multi, "", "check-cfg", "pass a --check-cfg to rustc", ""),
229 opt(Stable, Multi, "", "extern", "pass an --extern to rustc", "NAME[=PATH]"),
230 opt(
231 Unstable,
232 Multi,
233 "",
234 "extern-html-root-url",
235 "base URL to use for dependencies; for example, \
236 \"std=/doc\" links std::vec::Vec to /doc/std/vec/struct.Vec.html",
237 "NAME=URL",
238 ),
239 opt(
240 Unstable,
241 FlagMulti,
242 "",
243 "extern-html-root-takes-precedence",
244 "give precedence to `--extern-html-root-url`, not `html_root_url`",
245 "",
246 ),
247 opt(Stable, Multi, "C", "codegen", "pass a codegen option to rustc", "OPT[=VALUE]"),
248 opt(Stable, FlagMulti, "", "document-private-items", "document private items", ""),
249 opt(
250 Unstable,
251 FlagMulti,
252 "",
253 "document-hidden-items",
254 "document items that have doc(hidden)",
255 "",
256 ),
257 opt(Stable, FlagMulti, "", "test", "run code examples as tests", ""),
258 opt(Stable, Multi, "", "test-args", "arguments to pass to the test runner", "ARGS"),
259 opt(
260 Stable,
261 Opt,
262 "",
263 "test-run-directory",
264 "The working directory in which to run tests",
265 "PATH",
266 ),
267 opt(Stable, Opt, "", "target", "target triple to document", "TRIPLE"),
268 opt(
269 Stable,
270 Multi,
271 "",
272 "markdown-css",
273 "CSS files to include via <link> in a rendered Markdown file",
274 "FILES",
275 ),
276 opt(
277 Stable,
278 Multi,
279 "",
280 "html-in-header",
281 "files to include inline in the <head> section of a rendered Markdown file \
282 or generated documentation",
283 "FILES",
284 ),
285 opt(
286 Stable,
287 Multi,
288 "",
289 "html-before-content",
290 "files to include inline between <body> and the content of a rendered \
291 Markdown file or generated documentation",
292 "FILES",
293 ),
294 opt(
295 Stable,
296 Multi,
297 "",
298 "html-after-content",
299 "files to include inline between the content and </body> of a rendered \
300 Markdown file or generated documentation",
301 "FILES",
302 ),
303 opt(
304 Unstable,
305 Multi,
306 "",
307 "markdown-before-content",
308 "files to include inline between <body> and the content of a rendered \
309 Markdown file or generated documentation",
310 "FILES",
311 ),
312 opt(
313 Unstable,
314 Multi,
315 "",
316 "markdown-after-content",
317 "files to include inline between the content and </body> of a rendered \
318 Markdown file or generated documentation",
319 "FILES",
320 ),
321 opt(Stable, Opt, "", "markdown-playground-url", "URL to send code snippets to", "URL"),
322 opt(Stable, FlagMulti, "", "markdown-no-toc", "don't include table of contents", ""),
323 opt(
324 Stable,
325 Opt,
326 "e",
327 "extend-css",
328 "To add some CSS rules with a given file to generate doc with your own theme. \
329 However, your theme might break if the rustdoc's generated HTML changes, so be careful!",
330 "PATH",
331 ),
332 opt(
333 Unstable,
334 Multi,
335 "Z",
336 "",
337 "unstable / perma-unstable options (only on nightly build)",
338 "FLAG",
339 ),
340 opt(Stable, Opt, "", "sysroot", "Override the system root", "PATH"),
341 opt(
342 Unstable,
343 Opt,
344 "",
345 "playground-url",
346 "URL to send code snippets to, may be reset by --markdown-playground-url \
347 or `#![doc(html_playground_url=...)]`",
348 "URL",
349 ),
350 opt(
351 Unstable,
352 FlagMulti,
353 "",
354 "display-doctest-warnings",
355 "show warnings that originate in doctests",
356 "",
357 ),
358 opt(
359 Stable,
360 Opt,
361 "",
362 "crate-version",
363 "crate version to print into documentation",
364 "VERSION",
365 ),
366 opt(
367 Unstable,
368 FlagMulti,
369 "",
370 "sort-modules-by-appearance",
371 "sort modules by where they appear in the program, rather than alphabetically",
372 "",
373 ),
374 opt(
375 Stable,
376 Opt,
377 "",
378 "default-theme",
379 "Set the default theme. THEME should be the theme name, generally lowercase. \
380 If an unknown default theme is specified, the builtin default is used. \
381 The set of themes, and the rustdoc built-in default, are not stable.",
382 "THEME",
383 ),
384 opt(
385 Unstable,
386 Multi,
387 "",
388 "default-setting",
389 "Default value for a rustdoc setting (used when \"rustdoc-SETTING\" is absent \
390 from web browser Local Storage). If VALUE is not supplied, \"true\" is used. \
391 Supported SETTINGs and VALUEs are not documented and not stable.",
392 "SETTING[=VALUE]",
393 ),
394 opt(
395 Stable,
396 Multi,
397 "",
398 "theme",
399 "additional themes which will be added to the generated docs",
400 "FILES",
401 ),
402 opt(Stable, Multi, "", "check-theme", "check if given theme is valid", "FILES"),
403 opt(
404 Unstable,
405 Opt,
406 "",
407 "resource-suffix",
408 "suffix to add to CSS and JavaScript files, \
409 e.g., \"search-index.js\" will become \"search-index-suffix.js\"",
410 "PATH",
411 ),
412 opt(
413 Stable,
414 Opt,
415 "",
416 "edition",
417 "edition to use when compiling rust code (default: 2015)",
418 "EDITION",
419 ),
420 opt(
421 Stable,
422 Opt,
423 "",
424 "color",
425 "Configure coloring of output:
426 auto = colorize, if output goes to a tty (default);
427 always = always colorize output;
428 never = never colorize output",
429 "auto|always|never",
430 ),
431 opt(
432 Stable,
433 Opt,
434 "",
435 "error-format",
436 "How errors and other messages are produced",
437 "human|json|short",
438 ),
439 opt(
440 Stable,
441 Opt,
442 "",
443 "diagnostic-width",
444 "Provide width of the output for truncated error messages",
445 "WIDTH",
446 ),
447 opt(Stable, Opt, "", "json", "Configure the structure of JSON diagnostics", "CONFIG"),
448 opt(Stable, Multi, "A", "allow", "Set lint allowed", "LINT"),
449 opt(Stable, Multi, "W", "warn", "Set lint warnings", "LINT"),
450 opt(Stable, Multi, "", "force-warn", "Set lint force-warn", "LINT"),
451 opt(Stable, Multi, "D", "deny", "Set lint denied", "LINT"),
452 opt(Stable, Multi, "F", "forbid", "Set lint forbidden", "LINT"),
453 opt(
454 Stable,
455 Multi,
456 "",
457 "cap-lints",
458 "Set the most restrictive lint level. \
459 More restrictive lints are capped at this level. \
460 By default, it is at `forbid` level.",
461 "LEVEL",
462 ),
463 opt(Unstable, Opt, "", "index-page", "Markdown file to be used as index page", "PATH"),
464 opt(
465 Unstable,
466 FlagMulti,
467 "",
468 "enable-index-page",
469 "To enable generation of the index page",
470 "",
471 ),
472 opt(
473 Unstable,
474 Opt,
475 "",
476 "static-root-path",
477 "Path string to force loading static files from in output pages. \
478 If not set, uses combinations of '../' to reach the documentation root.",
479 "PATH",
480 ),
481 opt(
482 Unstable,
483 Opt,
484 "",
485 "persist-doctests",
486 "Directory to persist doctest executables into",
487 "PATH",
488 ),
489 opt(
490 Unstable,
491 FlagMulti,
492 "",
493 "show-coverage",
494 "calculate percentage of public items with documentation",
495 "",
496 ),
497 opt(
498 Stable,
499 Opt,
500 "",
501 "test-runtool",
502 "",
503 "The tool to run tests with when building for a different target than host",
504 ),
505 opt(
506 Stable,
507 Multi,
508 "",
509 "test-runtool-arg",
510 "",
511 "One argument (of possibly many) to pass to the runtool",
512 ),
513 opt(
514 Unstable,
515 Opt,
516 "",
517 "test-builder",
518 "The rustc-like binary to use as the test builder",
519 "PATH",
520 ),
521 opt(
522 Unstable,
523 Multi,
524 "",
525 "test-builder-wrapper",
526 "Wrapper program to pass test-builder and arguments",
527 "PATH",
528 ),
529 opt(Unstable, FlagMulti, "", "check", "Run rustdoc checks", ""),
530 opt(
531 Unstable,
532 FlagMulti,
533 "",
534 "generate-redirect-map",
535 "Generate JSON file at the top level instead of generating HTML redirection files",
536 "",
537 ),
538 opt(
539 Unstable,
540 Multi,
541 "",
542 "emit",
543 "Comma separated list of types of output for rustdoc to emit",
544 "[toolchain-shared-resources,invocation-specific,dep-info]",
545 ),
546 opt(Unstable, FlagMulti, "", "no-run", "Compile doctests without running them", ""),
547 opt(
548 Unstable,
549 Opt,
550 "",
551 "merge-doctests",
552 "Force all doctests to be compiled as a single binary, instead of one binary per test. If merging fails, rustdoc will emit a hard error.",
553 "yes|no|auto",
554 ),
555 opt(
556 Unstable,
557 Multi,
558 "",
559 "remap-path-prefix",
560 "Remap source names in compiler messages",
561 "FROM=TO",
562 ),
563 opt(
564 Unstable,
565 FlagMulti,
566 "",
567 "show-type-layout",
568 "Include the memory layout of types in the docs",
569 "",
570 ),
571 opt(Unstable, Flag, "", "no-capture", "Don't capture stdout and stderr of tests", ""),
572 opt(
573 Unstable,
574 Flag,
575 "",
576 "generate-link-to-definition",
577 "Make the identifiers in the HTML source code pages navigable",
578 "",
579 ),
580 opt(
581 Unstable,
582 Opt,
583 "",
584 "scrape-examples-output-path",
585 "",
586 "collect function call information and output at the given path",
587 ),
588 opt(
589 Unstable,
590 Multi,
591 "",
592 "scrape-examples-target-crate",
593 "",
594 "collect function call information for functions from the target crate",
595 ),
596 opt(Unstable, Flag, "", "scrape-tests", "Include test code when scraping examples", ""),
597 opt(
598 Unstable,
599 Multi,
600 "",
601 "with-examples",
602 "",
603 "path to function call information (for displaying examples in the documentation)",
604 ),
605 opt(
606 Unstable,
607 Opt,
608 "",
609 "merge",
610 "Controls how rustdoc handles files from previously documented crates in the doc root\n\
611 none = Do not write cross-crate information to the --out-dir\n\
612 shared = Append current crate's info to files found in the --out-dir\n\
613 finalize = Write current crate's info and --include-parts-dir info to the --out-dir, overwriting conflicting files",
614 "none|shared|finalize",
615 ),
616 opt(
617 Unstable,
618 Opt,
619 "",
620 "parts-out-dir",
621 "Writes trait implementations and other info for the current crate to provided path. Only use with --merge=none",
622 "path/to/doc.parts/<crate-name>",
623 ),
624 opt(
625 Unstable,
626 Multi,
627 "",
628 "include-parts-dir",
629 "Includes trait implementations and other crate info from provided path. Only use with --merge=finalize",
630 "path/to/doc.parts/<crate-name>",
631 ),
632 opt(Unstable, Flag, "", "html-no-source", "Disable HTML source code pages generation", ""),
633 opt(
634 Unstable,
635 Multi,
636 "",
637 "doctest-build-arg",
638 "One argument (of possibly many) to be used when compiling doctests",
639 "ARG",
640 ),
641 opt(
642 Unstable,
643 FlagMulti,
644 "",
645 "disable-minification",
646 "disable the minification of CSS/JS files (perma-unstable, do not use with cached files)",
647 "",
648 ),
649 opt(
650 Unstable,
651 Flag,
652 "",
653 "generate-macro-expansion",
654 "Add possibility to expand macros in the HTML source code pages",
655 "",
656 ),
657 opt(
659 Stable,
660 Multi,
661 "",
662 "plugin-path",
663 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
664 "DIR",
665 ),
666 opt(
667 Stable,
668 Multi,
669 "",
670 "passes",
671 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
672 "PASSES",
673 ),
674 opt(
675 Stable,
676 Multi,
677 "",
678 "plugins",
679 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
680 "PLUGINS",
681 ),
682 opt(
683 Stable,
684 FlagMulti,
685 "",
686 "no-defaults",
687 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
688 "",
689 ),
690 opt(
691 Stable,
692 Opt,
693 "r",
694 "input-format",
695 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
696 "[rust]",
697 ),
698 ]
699}
700
701fn usage(argv0: &str) {
702 let mut options = getopts::Options::new();
703 for option in opts() {
704 option.apply(&mut options);
705 }
706 println!("{}", options.usage(&format!("{argv0} [options] <input>")));
707 println!(" @path Read newline separated options from `path`\n");
708 println!(
709 "More information available at {DOC_RUST_LANG_ORG_VERSION}/rustdoc/what-is-rustdoc.html",
710 );
711}
712
713pub(crate) fn wrap_return(dcx: DiagCtxtHandle<'_>, res: Result<(), String>) {
714 match res {
715 Ok(()) => dcx.abort_if_errors(),
716 Err(err) => dcx.fatal(err),
717 }
718}
719
720fn run_renderer<
721 'tcx,
722 T: formats::FormatRenderer<'tcx>,
723 F: FnOnce(
724 clean::Crate,
725 config::RenderOptions,
726 Cache,
727 TyCtxt<'tcx>,
728 ) -> Result<(T, clean::Crate), Error>,
729>(
730 krate: clean::Crate,
731 renderopts: config::RenderOptions,
732 cache: formats::cache::Cache,
733 tcx: TyCtxt<'tcx>,
734 init: F,
735) {
736 match formats::run_format::<T, F>(krate, renderopts, cache, tcx, init) {
737 Ok(_) => tcx.dcx().abort_if_errors(),
738 Err(e) => {
739 let mut msg =
740 tcx.dcx().struct_fatal(format!("couldn't generate documentation: {}", e.error));
741 let file = e.file.display().to_string();
742 if !file.is_empty() {
743 msg.note(format!("failed to create or modify {e}"));
744 } else {
745 msg.note(format!("failed to create or modify file: {e}"));
746 }
747 msg.emit();
748 }
749 }
750}
751
752fn run_merge_finalize(opt: config::RenderOptions) -> Result<(), error::Error> {
756 assert!(
757 opt.should_merge.write_rendered_cci,
758 "config.rs only allows us to return InputMode::NoInputMergeFinalize if --merge=finalize"
759 );
760 assert!(
761 !opt.should_merge.read_rendered_cci,
762 "config.rs only allows us to return InputMode::NoInputMergeFinalize if --merge=finalize"
763 );
764 let crates = html::render::CrateInfo::read_many(&opt.include_parts_dir)?;
765 let include_sources = !opt.html_no_source;
766 html::render::write_not_crate_specific(
767 &crates,
768 &opt.output,
769 &opt,
770 &opt.themes,
771 opt.extension_css.as_deref(),
772 &opt.resource_suffix,
773 include_sources,
774 )?;
775 Ok(())
776}
777
778fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
779 let at_args = at_args.get(1..).unwrap_or_default();
788
789 let args = rustc_driver::args::arg_expand_all(early_dcx, at_args);
790
791 let mut options = getopts::Options::new();
792 for option in opts() {
793 option.apply(&mut options);
794 }
795 let matches = match options.parse(&args) {
796 Ok(m) => m,
797 Err(err) => {
798 early_dcx.early_fatal(err.to_string());
799 }
800 };
801
802 let (input, options, render_options, loaded_paths) =
805 match config::Options::from_matches(early_dcx, &matches, args) {
806 Some(opts) => opts,
807 None => return,
808 };
809
810 let dcx =
811 core::new_dcx(options.error_format, None, options.diagnostic_width, &options.unstable_opts);
812 let dcx = dcx.handle();
813
814 let input = match input {
815 config::InputMode::HasFile(input) => input,
816 config::InputMode::NoInputMergeFinalize => {
817 return wrap_return(
818 dcx,
819 rustc_span::create_session_globals_then(options.edition, &[], None, || {
820 run_merge_finalize(render_options)
821 .map_err(|e| format!("could not write merged cross-crate info: {e}"))
822 }),
823 );
824 }
825 };
826
827 let output_format = options.output_format;
828
829 match (
830 options.should_test || output_format == config::OutputFormat::Doctest,
831 config::markdown_input(&input),
832 ) {
833 (true, Some(_)) => return wrap_return(dcx, doctest::test_markdown(&input, options, dcx)),
834 (true, None) => return doctest::run(dcx, input, options),
835 (false, Some(md_input)) => {
836 let md_input = md_input.to_owned();
837 let edition = options.edition;
838 let config = core::create_config(input, options, &render_options);
839
840 return wrap_return(
844 dcx,
845 interface::run_compiler(config, |_compiler| {
846 markdown::render_and_write(&md_input, render_options, edition)
847 }),
848 );
849 }
850 (false, None) => {}
851 }
852
853 let show_coverage = options.show_coverage;
856 let run_check = options.run_check;
857
858 info!("starting to run rustc");
860
861 let crate_version = options.crate_version.clone();
866
867 let scrape_examples_options = options.scrape_examples_options.clone();
868 let bin_crate = options.bin_crate;
869
870 let output_format = options.output_format;
871 let config = core::create_config(input, options, &render_options);
872
873 let registered_lints = config.register_lints.is_some();
874
875 interface::run_compiler(config, |compiler| {
876 let sess = &compiler.sess;
877
878 for external_path in &loaded_paths {
881 let _ = sess.source_map().load_binary_file(external_path);
882 }
883
884 if sess.opts.describe_lints {
885 rustc_driver::describe_lints(sess, registered_lints);
886 return;
887 }
888
889 let krate = rustc_interface::passes::parse(sess);
890 rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| {
891 if sess.dcx().has_errors().is_some() {
892 sess.dcx().fatal("Compilation failed, aborting rustdoc");
893 }
894
895 let (krate, render_opts, mut cache, expanded_macros) = sess
896 .time("run_global_ctxt", || {
897 core::run_global_ctxt(tcx, show_coverage, render_options, output_format)
898 });
899 info!("finished with rustc");
900
901 if let Some(options) = scrape_examples_options {
902 return scrape_examples::run(krate, render_opts, cache, tcx, options, bin_crate);
903 }
904
905 cache.crate_version = crate_version;
906
907 if show_coverage {
908 return;
911 }
912
913 for owner_id in tcx.hir_crate_items(()).delayed_lint_items() {
914 if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) {
915 for lint in &delayed_lints.lints {
916 match lint {
917 DelayedLint::AttributeParsing(attribute_lint) => {
918 tcx.node_span_lint(
919 attribute_lint.lint_id.lint,
920 attribute_lint.id,
921 attribute_lint.span,
922 |diag| {
923 rustc_lint::decorate_attribute_lint(
924 tcx.sess,
925 Some(tcx),
926 &attribute_lint.kind,
927 diag,
928 );
929 },
930 );
931 }
932 }
933 }
934 }
935 }
936
937 if render_opts.dep_info().is_some() {
938 rustc_interface::passes::write_dep_info(tcx);
939 }
940
941 if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir {
942 dump_feature_usage_metrics(tcx, metrics_dir);
943 }
944
945 if run_check {
946 return;
948 }
949
950 info!("going to format");
951 match output_format {
952 config::OutputFormat::Html => sess.time("render_html", || {
953 run_renderer(
954 krate,
955 render_opts,
956 cache,
957 tcx,
958 |krate, render_opts, cache, tcx| {
959 html::render::Context::init(
960 krate,
961 render_opts,
962 cache,
963 tcx,
964 expanded_macros,
965 )
966 },
967 )
968 }),
969 config::OutputFormat::Json => sess.time("render_json", || {
970 run_renderer(krate, render_opts, cache, tcx, json::JsonRenderer::init)
971 }),
972 config::OutputFormat::Doctest => unreachable!(),
974 }
975 })
976 })
977}
978
979fn dump_feature_usage_metrics(tcxt: TyCtxt<'_>, metrics_dir: &Path) {
980 let hash = tcxt.crate_hash(LOCAL_CRATE);
981 let crate_name = tcxt.crate_name(LOCAL_CRATE);
982 let metrics_file_name = format!("unstable_feature_usage_metrics-{crate_name}-{hash}.json");
983 let metrics_path = metrics_dir.join(metrics_file_name);
984 if let Err(error) = tcxt.features().dump_feature_usage_metrics(metrics_path) {
985 tcxt.dcx().err(format!("cannot emit feature usage metrics: {error}"));
989 }
990}