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