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