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