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