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