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