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