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