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