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_advance_by)]
15#![feature(iter_intersperse)]
16#![feature(round_char_boundary)]
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 \"{file}\""));
764 }
765 msg.emit();
766 }
767 }
768}
769
770fn run_merge_finalize(opt: config::RenderOptions) -> Result<(), error::Error> {
774 assert!(
775 opt.should_merge.write_rendered_cci,
776 "config.rs only allows us to return InputMode::NoInputMergeFinalize if --merge=finalize"
777 );
778 assert!(
779 !opt.should_merge.read_rendered_cci,
780 "config.rs only allows us to return InputMode::NoInputMergeFinalize if --merge=finalize"
781 );
782 let crates = html::render::CrateInfo::read_many(&opt.include_parts_dir)?;
783 let include_sources = !opt.html_no_source;
784 html::render::write_not_crate_specific(
785 &crates,
786 &opt.output,
787 &opt,
788 &opt.themes,
789 opt.extension_css.as_deref(),
790 &opt.resource_suffix,
791 include_sources,
792 )?;
793 Ok(())
794}
795
796fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
797 let at_args = at_args.get(1..).unwrap_or_default();
806
807 let args = rustc_driver::args::arg_expand_all(early_dcx, at_args);
808
809 let mut options = getopts::Options::new();
810 for option in opts() {
811 option.apply(&mut options);
812 }
813 let matches = match options.parse(&args) {
814 Ok(m) => m,
815 Err(err) => {
816 early_dcx.early_fatal(err.to_string());
817 }
818 };
819
820 let (input, options, render_options, loaded_paths) =
823 match config::Options::from_matches(early_dcx, &matches, args) {
824 Some(opts) => opts,
825 None => return,
826 };
827
828 let dcx =
829 core::new_dcx(options.error_format, None, options.diagnostic_width, &options.unstable_opts);
830 let dcx = dcx.handle();
831
832 let input = match input {
833 config::InputMode::HasFile(input) => input,
834 config::InputMode::NoInputMergeFinalize => {
835 return wrap_return(
836 dcx,
837 run_merge_finalize(render_options)
838 .map_err(|e| format!("could not write merged cross-crate info: {e}")),
839 );
840 }
841 };
842
843 let output_format = options.output_format;
844
845 match (
846 options.should_test || output_format == config::OutputFormat::Doctest,
847 config::markdown_input(&input),
848 ) {
849 (true, Some(_)) => return wrap_return(dcx, doctest::test_markdown(&input, options)),
850 (true, None) => return doctest::run(dcx, input, options),
851 (false, Some(md_input)) => {
852 let md_input = md_input.to_owned();
853 let edition = options.edition;
854 let config = core::create_config(input, options, &render_options);
855
856 return wrap_return(
860 dcx,
861 interface::run_compiler(config, |_compiler| {
862 markdown::render_and_write(&md_input, render_options, edition)
863 }),
864 );
865 }
866 (false, None) => {}
867 }
868
869 let show_coverage = options.show_coverage;
872 let run_check = options.run_check;
873
874 info!("starting to run rustc");
876
877 let crate_version = options.crate_version.clone();
882
883 let scrape_examples_options = options.scrape_examples_options.clone();
884 let bin_crate = options.bin_crate;
885
886 let output_format = options.output_format;
887 let config = core::create_config(input, options, &render_options);
888
889 let registered_lints = config.register_lints.is_some();
890
891 interface::run_compiler(config, |compiler| {
892 let sess = &compiler.sess;
893
894 for external_path in &loaded_paths {
897 let _ = sess.source_map().load_file(external_path);
898 }
899
900 if sess.opts.describe_lints {
901 rustc_driver::describe_lints(sess, registered_lints);
902 return;
903 }
904
905 let krate = rustc_interface::passes::parse(sess);
906 rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| {
907 if sess.dcx().has_errors().is_some() {
908 sess.dcx().fatal("Compilation failed, aborting rustdoc");
909 }
910
911 let (krate, render_opts, mut cache, expanded_macros) = sess
912 .time("run_global_ctxt", || {
913 core::run_global_ctxt(tcx, show_coverage, render_options, output_format)
914 });
915 info!("finished with rustc");
916
917 if let Some(options) = scrape_examples_options {
918 return scrape_examples::run(krate, render_opts, cache, tcx, options, bin_crate);
919 }
920
921 cache.crate_version = crate_version;
922
923 if show_coverage {
924 return;
927 }
928
929 if render_opts.dep_info().is_some() {
930 rustc_interface::passes::write_dep_info(tcx);
931 }
932
933 if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir {
934 dump_feature_usage_metrics(tcx, metrics_dir);
935 }
936
937 if run_check {
938 return;
940 }
941
942 info!("going to format");
943 match output_format {
944 config::OutputFormat::Html => sess.time("render_html", || {
945 run_renderer(
946 krate,
947 render_opts,
948 cache,
949 tcx,
950 |krate, render_opts, cache, tcx| {
951 html::render::Context::init(
952 krate,
953 render_opts,
954 cache,
955 tcx,
956 expanded_macros,
957 )
958 },
959 )
960 }),
961 config::OutputFormat::Json => sess.time("render_json", || {
962 run_renderer(krate, render_opts, cache, tcx, json::JsonRenderer::init)
963 }),
964 config::OutputFormat::Doctest => unreachable!(),
966 }
967 })
968 })
969}
970
971fn dump_feature_usage_metrics(tcxt: TyCtxt<'_>, metrics_dir: &Path) {
972 let hash = tcxt.crate_hash(LOCAL_CRATE);
973 let crate_name = tcxt.crate_name(LOCAL_CRATE);
974 let metrics_file_name = format!("unstable_feature_usage_metrics-{crate_name}-{hash}.json");
975 let metrics_path = metrics_dir.join(metrics_file_name);
976 if let Err(error) = tcxt.features().dump_feature_usage_metrics(metrics_path) {
977 tcxt.dcx().err(format!("cannot emit feature usage metrics: {error}"));
981 }
982}