1#![cfg_attr(bootstrap, feature(trim_prefix_suffix))]
3#![cfg_attr(not(bootstrap), feature(exitcode_exit_method))]
4#![doc(
5 html_root_url = "https://doc.rust-lang.org/nightly/",
6 html_playground_url = "https://play.rust-lang.org/"
7)]
8#![feature(ascii_char)]
9#![feature(ascii_char_variants)]
10#![feature(deref_patterns)]
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 Stable,
370 Opt,
371 "",
372 "default-theme",
373 "Set the default theme. THEME should be the theme name, generally lowercase. \
374 If an unknown default theme is specified, the builtin default is used. \
375 The set of themes, and the rustdoc built-in default, are not stable.",
376 "THEME",
377 ),
378 opt(
379 Unstable,
380 Multi,
381 "",
382 "default-setting",
383 "Default value for a rustdoc setting (used when \"rustdoc-SETTING\" is absent \
384 from web browser Local Storage). If VALUE is not supplied, \"true\" is used. \
385 Supported SETTINGs and VALUEs are not documented and not stable.",
386 "SETTING[=VALUE]",
387 ),
388 opt(
389 Stable,
390 Multi,
391 "",
392 "theme",
393 "additional themes which will be added to the generated docs",
394 "FILES",
395 ),
396 opt(Stable, Multi, "", "check-theme", "check if given theme is valid", "FILES"),
397 opt(
398 Unstable,
399 Opt,
400 "",
401 "resource-suffix",
402 "suffix to add to CSS and JavaScript files, \
403 e.g., \"search-index.js\" will become \"search-index-suffix.js\"",
404 "PATH",
405 ),
406 opt(
407 Stable,
408 Opt,
409 "",
410 "edition",
411 "edition to use when compiling rust code (default: 2015)",
412 "EDITION",
413 ),
414 opt(
415 Stable,
416 Opt,
417 "",
418 "color",
419 "Configure coloring of output:
420 auto = colorize, if output goes to a tty (default);
421 always = always colorize output;
422 never = never colorize output",
423 "auto|always|never",
424 ),
425 opt(
426 Stable,
427 Opt,
428 "",
429 "error-format",
430 "How errors and other messages are produced",
431 "human|json|short",
432 ),
433 opt(
434 Stable,
435 Opt,
436 "",
437 "diagnostic-width",
438 "Provide width of the output for truncated error messages",
439 "WIDTH",
440 ),
441 opt(Stable, Opt, "", "json", "Configure the structure of JSON diagnostics", "CONFIG"),
442 opt(Stable, Multi, "A", "allow", "Set lint allowed", "LINT"),
443 opt(Stable, Multi, "W", "warn", "Set lint warnings", "LINT"),
444 opt(Stable, Multi, "", "force-warn", "Set lint force-warn", "LINT"),
445 opt(Stable, Multi, "D", "deny", "Set lint denied", "LINT"),
446 opt(Stable, Multi, "F", "forbid", "Set lint forbidden", "LINT"),
447 opt(
448 Stable,
449 Multi,
450 "",
451 "cap-lints",
452 "Set the most restrictive lint level. \
453 More restrictive lints are capped at this level. \
454 By default, it is at `forbid` level.",
455 "LEVEL",
456 ),
457 opt(
458 Stable,
459 Multi,
460 "",
461 "remap-path-prefix",
462 "Remap source names in compiler messages",
463 "FROM=TO",
464 ),
465 opt(Unstable, Opt, "", "index-page", "Markdown file to be used as index page", "PATH"),
466 opt(
467 Unstable,
468 FlagMulti,
469 "",
470 "enable-index-page",
471 "To enable generation of the index page",
472 "",
473 ),
474 opt(
475 Unstable,
476 Opt,
477 "",
478 "static-root-path",
479 "Path string to force loading static files from in output pages. \
480 If not set, uses combinations of '../' to reach the documentation root.",
481 "PATH",
482 ),
483 opt(
484 Unstable,
485 Opt,
486 "",
487 "persist-doctests",
488 "Directory to persist doctest executables into",
489 "PATH",
490 ),
491 opt(
492 Unstable,
493 FlagMulti,
494 "",
495 "show-coverage",
496 "calculate percentage of public items with documentation",
497 "",
498 ),
499 opt(
500 Stable,
501 Opt,
502 "",
503 "test-runtool",
504 "",
505 "The tool to run tests with when building for a different target than host",
506 ),
507 opt(
508 Stable,
509 Multi,
510 "",
511 "test-runtool-arg",
512 "",
513 "One argument (of possibly many) to pass to the runtool",
514 ),
515 opt(
516 Unstable,
517 Opt,
518 "",
519 "test-builder",
520 "The rustc-like binary to use as the test builder",
521 "PATH",
522 ),
523 opt(
524 Unstable,
525 Multi,
526 "",
527 "test-builder-wrapper",
528 "Wrapper program to pass test-builder and arguments",
529 "PATH",
530 ),
531 opt(Unstable, FlagMulti, "", "check", "Run rustdoc checks", ""),
532 opt(
533 Unstable,
534 FlagMulti,
535 "",
536 "generate-redirect-map",
537 "Generate JSON file at the top level instead of generating HTML redirection files",
538 "",
539 ),
540 opt(
541 Stable,
542 Multi,
543 "",
544 "emit",
545 "Comma separated list of types of output for rustdoc to emit",
546 "[html-static-files,html-non-static-files,dep-info]",
547 ),
548 opt(
549 Unstable,
550 Multi,
551 "",
552 "print",
553 "Rustdoc information to print on stdout (or to a file)",
554 "<INFO>[=<FILE>]",
555 ),
556 opt(Unstable, FlagMulti, "", "no-run", "Compile doctests without running them", ""),
557 opt(
558 Unstable,
559 Opt,
560 "",
561 "merge-doctests",
562 "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.",
563 "yes|no|auto",
564 ),
565 opt(
566 Unstable,
567 Opt,
568 "",
569 "remap-path-scope",
570 "Defines which scopes of paths should be remapped by `--remap-path-prefix`",
571 "[macro,diagnostics,debuginfo,coverage,object,all]",
572 ),
573 opt(
574 Unstable,
575 FlagMulti,
576 "",
577 "show-type-layout",
578 "Include the memory layout of types in the docs",
579 "",
580 ),
581 opt(Unstable, Flag, "", "no-capture", "Don't capture stdout and stderr of tests", ""),
582 opt(
583 Unstable,
584 Flag,
585 "",
586 "generate-link-to-definition",
587 "Make the identifiers in the HTML source code pages navigable",
588 "",
589 ),
590 opt(
591 Unstable,
592 Opt,
593 "",
594 "scrape-examples-output-path",
595 "",
596 "collect function call information and output at the given path",
597 ),
598 opt(
599 Unstable,
600 Multi,
601 "",
602 "scrape-examples-target-crate",
603 "",
604 "collect function call information for functions from the target crate",
605 ),
606 opt(Unstable, Flag, "", "scrape-tests", "Include test code when scraping examples", ""),
607 opt(
608 Unstable,
609 Multi,
610 "",
611 "with-examples",
612 "",
613 "path to function call information (for displaying examples in the documentation)",
614 ),
615 opt(
616 Unstable,
617 Opt,
618 "",
619 "write-doc-meta-dir",
620 "Writes trait implementations and other info for the current crate to provided path",
621 "path/to/doc.meta",
622 ),
623 opt(
624 Unstable,
625 Multi,
626 "",
627 "read-doc-meta-dir",
628 "Includes trait implementations and other crate info from provided path",
629 "path/to/doc.meta",
630 ),
631 opt(
632 Unstable,
633 Opt,
634 "",
635 "parts-out-dir",
636 "Deprecated synonym of write-doc-meta-dir",
637 "path/to/doc.meta",
638 ),
639 opt(
640 Unstable,
641 Multi,
642 "",
643 "include-parts-dir",
644 "Deprecated synonym of read-doc-meta-dir",
645 "path/to/doc.meta",
646 ),
647 opt(
648 Unstable,
649 Opt,
650 "",
651 "merge",
652 "Deprecated option to specify read/write-doc-meta-dir mode",
653 "none, shared, finalize",
654 ),
655 opt(Unstable, Flag, "", "html-no-source", "Disable HTML source code pages generation", ""),
656 opt(
657 Unstable,
658 Multi,
659 "",
660 "doctest-build-arg",
661 "One argument (of possibly many) to be used when compiling doctests",
662 "ARG",
663 ),
664 opt(
665 Unstable,
666 FlagMulti,
667 "",
668 "disable-minification",
669 "disable the minification of CSS/JS files (perma-unstable, do not use with cached files)",
670 "",
671 ),
672 opt(
673 Unstable,
674 Flag,
675 "",
676 "generate-macro-expansion",
677 "Add possibility to expand macros in the HTML source code pages",
678 "",
679 ),
680 opt(
682 Stable,
683 Multi,
684 "",
685 "plugin-path",
686 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
687 "DIR",
688 ),
689 opt(
690 Stable,
691 Multi,
692 "",
693 "passes",
694 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
695 "PASSES",
696 ),
697 opt(
698 Stable,
699 Multi,
700 "",
701 "plugins",
702 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
703 "PLUGINS",
704 ),
705 opt(
706 Stable,
707 FlagMulti,
708 "",
709 "no-defaults",
710 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
711 "",
712 ),
713 opt(
714 Stable,
715 Opt,
716 "r",
717 "input-format",
718 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
719 "[rust]",
720 ),
721 ]
722}
723
724fn usage(argv0: &str) {
725 let mut options = getopts::Options::new();
726 for option in opts() {
727 option.apply(&mut options);
728 }
729 println!("{}", options.usage(&format!("{argv0} [options] <input>")));
730 println!(" @path Read newline separated options from `path`\n");
731 println!(
732 "More information available at {DOC_RUST_LANG_ORG_VERSION}/rustdoc/what-is-rustdoc.html",
733 );
734}
735
736pub(crate) fn wrap_return(dcx: DiagCtxtHandle<'_>, res: Result<(), String>) {
737 match res {
738 Ok(()) => dcx.abort_if_errors(),
739 Err(err) => dcx.fatal(err),
740 }
741}
742
743fn run_renderer<
744 'tcx,
745 T: formats::FormatRenderer<'tcx>,
746 F: FnOnce(
747 clean::Crate,
748 config::RenderOptions,
749 Cache,
750 TyCtxt<'tcx>,
751 ) -> Result<(T, clean::Crate), Error>,
752>(
753 krate: clean::Crate,
754 renderopts: config::RenderOptions,
755 cache: formats::cache::Cache,
756 tcx: TyCtxt<'tcx>,
757 init: F,
758) {
759 match formats::run_format::<T, F>(krate, renderopts, cache, tcx, init) {
760 Ok(_) => tcx.dcx().abort_if_errors(),
761 Err(e) => {
762 let mut msg =
763 tcx.dcx().struct_fatal(format!("couldn't generate documentation: {}", e.error));
764 let file = e.file.display().to_string();
765 if !file.is_empty() {
766 msg.note(format!("failed to create or modify {e}"));
767 } else {
768 msg.note(format!("failed to create or modify file: {e}"));
769 }
770 msg.emit();
771 }
772 }
773}
774
775fn run_merge_finalize(
779 render_options: config::RenderOptions,
780 compiler: &interface::Compiler,
781) -> Result<(), error::Error> {
782 assert!(
783 render_options.should_merge.write_rendered_cci,
784 "config.rs only allows us to return InputMode::NoInputMergeFinalize if --merge=finalize"
785 );
786 assert!(
787 !render_options.should_merge.read_rendered_cci,
788 "config.rs only allows us to return InputMode::NoInputMergeFinalize if --merge=finalize"
789 );
790 let crates = html::render::CrateInfo::read_many(&render_options.include_parts_dir)?;
791 let include_sources = !render_options.html_no_source;
792
793 html::render::write_not_crate_specific(
794 &crates,
795 &render_options.output,
796 &render_options,
797 &render_options.themes,
798 render_options.extension_css.as_deref(),
799 &render_options.resource_suffix,
800 include_sources,
801 &crate::html::layout::Layout {
802 logo: String::new(),
803 favicon: String::new(),
804 external_html: render_options.external_html.clone(),
805 default_settings: render_options.default_settings.clone(),
806 krate: String::new(),
807 krate_version: String::new(),
808 css_file_extension: render_options.extension_css.clone(),
809 scrape_examples_extension: false,
810 },
811 &compiler.sess,
812 )?;
813 Ok(())
814}
815
816fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
817 let at_args = at_args.get(1..).unwrap_or_default();
826
827 let args = rustc_driver::args::arg_expand_all(early_dcx, at_args);
828
829 let mut options = getopts::Options::new();
830 for option in opts() {
831 option.apply(&mut options);
832 }
833 let matches = match options.parse(&args) {
834 Ok(m) => m,
835 Err(err) => {
836 early_dcx.early_fatal(err.to_string());
837 }
838 };
839
840 let (input, options, render_options, loaded_paths) =
843 match config::Options::from_matches(early_dcx, &matches, args) {
844 Some(opts) => opts,
845 None => return,
846 };
847
848 let dcx =
849 core::new_dcx(options.error_format, None, options.diagnostic_width, &options.unstable_opts);
850 let dcx = dcx.handle();
851
852 let input = match input {
853 config::InputMode::HasFile(input) => input,
854 config::InputMode::NoInputMergeFinalize => {
855 if !options.prints.is_empty() {
856 dcx.fatal("`--print` is not supported for the `--write-doc-meta-dir` option");
857 }
858
859 let config = core::create_config(
860 Input::Str {
861 name: rustc_span::FileName::Custom(String::new()),
862 input: String::new(),
863 },
864 options,
865 &render_options,
866 );
867 return wrap_return(
868 dcx,
869 interface::run_compiler(config, |compiler| {
870 run_merge_finalize(render_options, compiler)
871 .map_err(|e| format!("could not write merged cross-crate info: {e}"))
872 }),
873 );
874 }
875 };
876 let md_input = config::markdown_input(&input);
877
878 if options.should_test || options.output_format == config::OutputFormat::Doctest {
879 if !options.prints.is_empty() {
880 dcx.fatal(format!(
881 "`--print` is not yet supported for the `{}` option",
882 if options.should_test { "--test" } else { "--output-format=doctest" }
883 ));
884 }
885
886 return match md_input {
887 Some(_) => wrap_return(dcx, doctest::test_markdown(&input, options, dcx)),
888 None => doctest::run(dcx, input, options),
889 };
890 }
891
892 if let Some(md_input) = md_input {
893 if !options.prints.is_empty() {
894 dcx.fatal("`--print` is not yet supported for standalone Markdown files");
895 }
896
897 return {
898 let md_input = md_input.to_owned();
899 let edition = options.edition;
900 let config = core::create_config(input, options, &render_options);
901 let registered_lints = config.register_lints.is_some();
902
903 wrap_return(
907 dcx,
908 interface::run_compiler(config, |compiler| {
909 let sess = &compiler.sess;
910
911 if sess.opts.describe_lints {
913 rustc_driver::describe_lints(sess, registered_lints);
914 return Ok(());
915 }
916
917 let file = sess
920 .source_map()
921 .load_file(&md_input)
922 .map_err(|e| format!("{md_input}: {e}", md_input = md_input.display()))?;
923 let inner_span = Span::new(
924 file.start_pos,
925 BytePos(file.start_pos.0 + file.normalized_source_len.0),
926 SyntaxContext::root(),
927 None,
928 );
929 let krate = ast::Crate {
930 attrs: Default::default(),
931 items: Default::default(),
932 spans: ast::ModSpans { inner_span, ..Default::default() },
933 id: ast::DUMMY_NODE_ID,
934 is_placeholder: false,
935 };
936 let (res, _incr_comp_session) =
937 rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| {
938 let has_dep_info = render_options.dep_info().is_some();
939 if render_options.emit.contains(&EmitType::HtmlNonStaticFiles) {
940 markdown::render_and_write(file, render_options, edition)?;
941 }
942 if has_dep_info {
943 for external_path in &loaded_paths {
946 let _ =
947 compiler.sess.source_map().load_binary_file(external_path);
948 }
949 rustc_interface::passes::write_dep_info(tcx);
950 }
951 Ok(())
952 });
953 res
954 }),
955 )
956 };
957 }
958
959 let show_coverage = options.show_coverage;
962 let run_check = options.run_check;
963
964 info!("starting to run rustc");
966
967 let crate_version = options.crate_version.clone();
972
973 let scrape_examples_options = options.scrape_examples_options.clone();
974 let bin_crate = options.bin_crate;
975
976 let output_format = options.output_format;
977 let config = core::create_config(input, options, &render_options);
978 let registered_lints = config.register_lints.is_some();
979
980 interface::run_compiler(config, |compiler| {
981 let sess = &compiler.sess;
982
983 for external_path in &loaded_paths {
986 let _ = sess.source_map().load_binary_file(external_path);
987 }
988
989 if sess.opts.describe_lints {
991 rustc_driver::describe_lints(sess, registered_lints);
992 return;
993 }
994
995 if rustc_driver::print_crate_info(&*compiler.codegen_backend, sess, true)
997 == rustc_driver::Compilation::Stop
998 {
999 return;
1000 }
1001
1002 let krate = rustc_interface::passes::parse(sess);
1003 rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| {
1004 if sess.dcx().has_errors().is_some() {
1005 sess.dcx().fatal("Compilation failed, aborting rustdoc");
1006 }
1007
1008 let (krate, render_opts, mut cache, expanded_macros) = sess
1009 .time("run_global_ctxt", || {
1010 core::run_global_ctxt(tcx, show_coverage, render_options, output_format)
1011 });
1012 info!("finished with rustc");
1013
1014 if let Some(options) = scrape_examples_options {
1015 return scrape_examples::run(krate, render_opts, cache, tcx, options, bin_crate);
1016 }
1017
1018 if show_coverage {
1019 return;
1022 }
1023
1024 cache.crate_version = crate_version;
1025
1026 rustc_interface::passes::emit_delayed_lints(tcx);
1027
1028 if render_opts.dep_info().is_some() {
1029 rustc_interface::passes::write_dep_info(tcx);
1030 }
1031
1032 if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir {
1033 dump_feature_usage_metrics(tcx, metrics_dir);
1034 }
1035
1036 if run_check {
1037 return;
1039 }
1040
1041 info!("going to format");
1042 match output_format {
1043 config::OutputFormat::Html => sess.time("render_html", || {
1044 run_renderer(
1045 krate,
1046 render_opts,
1047 cache,
1048 tcx,
1049 |krate, render_opts, cache, tcx| {
1050 html::render::Context::init(
1051 krate,
1052 render_opts,
1053 cache,
1054 tcx,
1055 expanded_macros,
1056 )
1057 },
1058 )
1059 }),
1060 config::OutputFormat::IrJson => sess.time("render_json", || {
1061 run_renderer(krate, render_opts, cache, tcx, json::JsonRenderer::init)
1062 }),
1063 config::OutputFormat::Doctest | config::OutputFormat::CoverageJson => {
1065 unreachable!()
1066 }
1067 }
1068 });
1069 })
1070}
1071
1072fn dump_feature_usage_metrics(tcx: TyCtxt<'_>, metrics_dir: &Path) {
1073 let hash = tcx.crate_hash(LOCAL_CRATE);
1074 let crate_name = tcx.crate_name(LOCAL_CRATE);
1075 let metrics_file_name = format!("unstable_feature_usage_metrics-{crate_name}-{hash}.json");
1076 let metrics_path = metrics_dir.join(metrics_file_name);
1077 if let Err(error) = tcx.features().dump_feature_usage_metrics(metrics_path) {
1078 tcx.dcx().err(format!("cannot emit feature usage metrics: {error}"));
1082 }
1083}