lib.rs - source (original) (raw)
rustdoc/
lib.rs
1#![doc(
2 html_root_url = "https://doc.rust-lang.org/nightly/",
3 html_playground_url = "https://play.rust-lang.org/"
4)]
5#![feature(rustc_private)]
6#![feature(assert_matches)]
7#![feature(box_patterns)]
8#![feature(debug_closure_helpers)]
9#![feature(file_buffered)]
10#![feature(format_args_nl)]
11#![feature(if_let_guard)]
12#![feature(impl_trait_in_assoc_type)]
13#![feature(iter_intersperse)]
14#![feature(let_chains)]
15#![feature(never_type)]
16#![feature(round_char_boundary)]
17#![feature(test)]
18#![feature(type_alias_impl_trait)]
19#![feature(type_ascription)]
20#![recursion_limit = "256"]
21#![warn(rustc::internal)]
22#![allow(clippy::collapsible_if, clippy::collapsible_else_if)]
23#![allow(rustc::diagnostic_outside_of_impl)]
24#![allow(rustc::untranslatable_diagnostic)]
25
26extern crate thin_vec;
27
28// N.B. these need `extern crate` even in 2018 edition
29// because they're loaded implicitly from the sysroot.
30// The reason they're loaded from the sysroot is because
31// the rustdoc artifacts aren't stored in rustc's cargo target directory.
32// So if `rustc` was specified in Cargo.toml, this would spuriously rebuild crates.
33//
34// Dependencies listed in Cargo.toml do not need `extern crate`.
35
36extern crate pulldown_cmark;
37extern crate rustc_abi;
38extern crate rustc_ast;
39extern crate rustc_ast_pretty;
40extern crate rustc_attr_parsing;
41extern crate rustc_data_structures;
42extern crate rustc_driver;
43extern crate rustc_errors;
44extern crate rustc_expand;
45extern crate rustc_feature;
46extern crate rustc_hir;
47extern crate rustc_hir_analysis;
48extern crate rustc_hir_pretty;
49extern crate rustc_index;
50extern crate rustc_infer;
51extern crate rustc_interface;
52extern crate rustc_lexer;
53extern crate rustc_lint;
54extern crate rustc_lint_defs;
55extern crate rustc_log;
56extern crate rustc_macros;
57extern crate rustc_metadata;
58extern crate rustc_middle;
59extern crate rustc_parse;
60extern crate rustc_passes;
61extern crate rustc_resolve;
62extern crate rustc_serialize;
63extern crate rustc_session;
64extern crate rustc_span;
65extern crate rustc_target;
66extern crate rustc_trait_selection;
67extern crate test;
68
69// See docs in https://github.com/rust-lang/rust/blob/master/compiler/rustc/src/main.rs
70// about jemalloc.
71#[cfg(feature = "jemalloc")]
72extern crate tikv_jemalloc_sys as jemalloc_sys;
73
74use std::env::{self, VarError};
75use std::io::{self, IsTerminal};
76use std::process;
77
78use rustc_errors::DiagCtxtHandle;
79use rustc_interface::interface;
80use rustc_middle::ty::TyCtxt;
81use rustc_session::config::{ErrorOutputType, RustcOptGroup, make_crate_type_option};
82use rustc_session::{EarlyDiagCtxt, getopts};
83use tracing::info;
84
85use crate::clean::utils::DOC_RUST_LANG_ORG_VERSION;
86
87/// A macro to create a FxHashMap.
88///
89/// Example:
90///
91/// ```ignore(cannot-test-this-because-non-exported-macro)
92/// let letters = map!{"a" => "b", "c" => "d"};
93/// ```
94///
95/// Trailing commas are allowed.
96/// Commas between elements are required (even if the expression is a block).
97macro_rules! map {
98 ($( <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>k</mi><mi>e</mi><mi>y</mi><mo>:</mo><mi>e</mi><mi>x</mi><mi>p</mi><mi>r</mi><mo>=</mo><mo>></mo></mrow><annotation encoding="application/x-tex">key: expr => </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.03148em;">k</span><span class="mord mathnormal" style="margin-right:0.03588em;">ey</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.7335em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">e</span><span class="mord mathnormal">x</span><span class="mord mathnormal">p</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=></span></span></span></span>val: expr ),* $(,)*) => {{
99 let mut map = ::rustc_data_structures::fx::FxIndexMap::default();
100 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mi>m</mi><mi>a</mi><mi>p</mi><mi mathvariant="normal">.</mi><mi>i</mi><mi>n</mi><mi>s</mi><mi>e</mi><mi>r</mi><mi>t</mi><mo stretchy="false">(</mo></mrow><annotation encoding="application/x-tex">( map.insert(</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathnormal">ma</span><span class="mord mathnormal">p</span><span class="mord">.</span><span class="mord mathnormal">in</span><span class="mord mathnormal" style="margin-right:0.02778em;">ser</span><span class="mord mathnormal">t</span><span class="mopen">(</span></span></span></span>key, $val); )*
101 map
102 }}
103}
104
105mod clean;
106mod config;
107mod core;
108mod display;
109mod docfs;
110mod doctest;
111mod error;
112mod externalfiles;
113mod fold;
114mod formats;
115// used by the error-index generator, so it needs to be public
116pub mod html;
117mod json;
118pub(crate) mod lint;
119mod markdown;
120mod passes;
121mod scrape_examples;
122mod theme;
123mod visit;
124mod visit_ast;
125mod visit_lib;
126
127pub fn main() {
128 // See docs in https://github.com/rust-lang/rust/blob/master/compiler/rustc/src/main.rs
129 // about jemalloc.
130 #[cfg(feature = "jemalloc")]
131 {
132 use std::os::raw::{c_int, c_void};
133
134 #[used]
135 static _F1: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::calloc;
136 #[used]
137 static _F2: unsafe extern "C" fn(*mut *mut c_void, usize, usize) -> c_int =
138 jemalloc_sys::posix_memalign;
139 #[used]
140 static _F3: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::aligned_alloc;
141 #[used]
142 static _F4: unsafe extern "C" fn(usize) -> *mut c_void = jemalloc_sys::malloc;
143 #[used]
144 static _F5: unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void = jemalloc_sys::realloc;
145 #[used]
146 static _F6: unsafe extern "C" fn(*mut c_void) = jemalloc_sys::free;
147
148 #[cfg(target_os = "macos")]
149 {
150 unsafe extern "C" {
151 fn _rjem_je_zone_register();
152 }
153
154 #[used]
155 static _F7: unsafe extern "C" fn() = _rjem_je_zone_register;
156 }
157 }
158
159 let mut early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
160
161 rustc_driver::install_ice_hook(
162 "https://github.com/rust-lang/rust/issues/new\
163 ?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md",
164 |_| (),
165 );
166
167 // When using CI artifacts with `download-rustc`, tracing is unconditionally built
168 // with `--features=static_max_level_info`, which disables almost all rustdoc logging. To avoid
169 // this, compile our own version of `tracing` that logs all levels.
170 // NOTE: this compiles both versions of tracing unconditionally, because
171 // - The compile time hit is not that bad, especially compared to rustdoc's incremental times, and
172 // - Otherwise, there's no warning that logging is being ignored when `download-rustc` is enabled
173
174 crate::init_logging(&early_dcx);
175 match rustc_log::init_logger(rustc_log::LoggerConfig::from_env("RUSTDOC_LOG")) {
176 Ok(()) => {}
177 // With `download-rustc = true` there are definitely 2 distinct tracing crates in the
178 // dependency graph: one in the downloaded sysroot and one built just now as a dependency of
179 // rustdoc. So the sysroot's tracing is definitely not yet initialized here.
180 //
181 // But otherwise, depending on link style, there may or may not be 2 tracing crates in play.
182 // The one we just initialized in `crate::init_logging` above is rustdoc's direct dependency
183 // on tracing. When rustdoc is built by x.py using Cargo, rustc_driver's and rustc_log's
184 // tracing dependency is distinct from this one and also needs to be initialized (using the
185 // same RUSTDOC_LOG environment variable for both). Other build systems may use just a
186 // single tracing crate throughout the rustc and rustdoc build.
187 //
188 // The reason initializing 2 tracings does not show double logging when `download-rustc =
189 // false` and `debug_logging = true` is because all rustc logging goes only to its version
190 // of tracing (the one in the sysroot) and all of rustdoc's logging only goes to its version
191 // (the one in Cargo.toml).
192 Err(rustc_log::Error::AlreadyInit(_)) => {}
193 Err(error) => early_dcx.early_fatal(error.to_string()),
194 }
195
196 let exit_code = rustc_driver::catch_with_exit_code(|| {
197 let at_args = rustc_driver::args::raw_args(&early_dcx);
198 main_args(&mut early_dcx, &at_args);
199 });
200 process::exit(exit_code);
201}
202
203fn init_logging(early_dcx: &EarlyDiagCtxt) {
204 let color_logs = match env::var("RUSTDOC_LOG_COLOR").as_deref() {
205 Ok("always") => true,
206 Ok("never") => false,
207 Ok("auto") | Err(VarError::NotPresent) => io::stdout().is_terminal(),
208 Ok(value) => early_dcx.early_fatal(format!(
209 "invalid log color value '{value}': expected one of always, never, or auto",
210 )),
211 Err(VarError::NotUnicode(value)) => early_dcx.early_fatal(format!(
212 "invalid log color value '{}': expected one of always, never, or auto",
213 value.to_string_lossy()
214 )),
215 };
216 let filter = tracing_subscriber::EnvFilter::from_env("RUSTDOC_LOG");
217 let layer = tracing_tree::HierarchicalLayer::default()
218 .with_writer(io::stderr)
219 .with_ansi(color_logs)
220 .with_targets(true)
221 .with_wraparound(10)
222 .with_verbose_exit(true)
223 .with_verbose_entry(true)
224 .with_indent_amount(2);
225 #[cfg(debug_assertions)]
226 let layer = layer.with_thread_ids(true).with_thread_names(true);
227
228 use tracing_subscriber::layer::SubscriberExt;
229 let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
230 tracing::subscriber::set_global_default(subscriber).unwrap();
231}
232
233fn opts() -> Vec<RustcOptGroup> {
234 use rustc_session::config::OptionKind::{Flag, FlagMulti, Multi, Opt};
235 use rustc_session::config::OptionStability::{Stable, Unstable};
236 use rustc_session::config::make_opt as opt;
237
238 vec![
239 opt(Stable, FlagMulti, "h", "help", "show this help message", ""),
240 opt(Stable, FlagMulti, "V", "version", "print rustdoc's version", ""),
241 opt(Stable, FlagMulti, "v", "verbose", "use verbose output", ""),
242 opt(Stable, Opt, "w", "output-format", "the output type to write", "[html]"),
243 opt(
244 Stable,
245 Opt,
246 "",
247 "output",
248 "Which directory to place the output. This option is deprecated, use --out-dir instead.",
249 "PATH",
250 ),
251 opt(Stable, Opt, "o", "out-dir", "which directory to place the output", "PATH"),
252 opt(Stable, Opt, "", "crate-name", "specify the name of this crate", "NAME"),
253 make_crate_type_option(),
254 opt(Stable, Multi, "L", "library-path", "directory to add to crate search path", "DIR"),
255 opt(Stable, Multi, "", "cfg", "pass a --cfg to rustc", ""),
256 opt(Stable, Multi, "", "check-cfg", "pass a --check-cfg to rustc", ""),
257 opt(Stable, Multi, "", "extern", "pass an --extern to rustc", "NAME[=PATH]"),
258 opt(
259 Unstable,
260 Multi,
261 "",
262 "extern-html-root-url",
263 "base URL to use for dependencies; for example, \
264 \"std=/doc\" links std::vec::Vec to /doc/std/vec/struct.Vec.html",
265 "NAME=URL",
266 ),
267 opt(
268 Unstable,
269 FlagMulti,
270 "",
271 "extern-html-root-takes-precedence",
272 "give precedence to `--extern-html-root-url`, not `html_root_url`",
273 "",
274 ),
275 opt(Stable, Multi, "C", "codegen", "pass a codegen option to rustc", "OPT[=VALUE]"),
276 opt(Stable, FlagMulti, "", "document-private-items", "document private items", ""),
277 opt(
278 Unstable,
279 FlagMulti,
280 "",
281 "document-hidden-items",
282 "document items that have doc(hidden)",
283 "",
284 ),
285 opt(Stable, FlagMulti, "", "test", "run code examples as tests", ""),
286 opt(Stable, Multi, "", "test-args", "arguments to pass to the test runner", "ARGS"),
287 opt(
288 Stable,
289 Opt,
290 "",
291 "test-run-directory",
292 "The working directory in which to run tests",
293 "PATH",
294 ),
295 opt(Stable, Opt, "", "target", "target triple to document", "TRIPLE"),
296 opt(
297 Stable,
298 Multi,
299 "",
300 "markdown-css",
301 "CSS files to include via <link> in a rendered Markdown file",
302 "FILES",
303 ),
304 opt(
305 Stable,
306 Multi,
307 "",
308 "html-in-header",
309 "files to include inline in the <head> section of a rendered Markdown file \
310 or generated documentation",
311 "FILES",
312 ),
313 opt(
314 Stable,
315 Multi,
316 "",
317 "html-before-content",
318 "files to include inline between <body> and the content of a rendered \
319 Markdown file or generated documentation",
320 "FILES",
321 ),
322 opt(
323 Stable,
324 Multi,
325 "",
326 "html-after-content",
327 "files to include inline between the content and </body> of a rendered \
328 Markdown file or generated documentation",
329 "FILES",
330 ),
331 opt(
332 Unstable,
333 Multi,
334 "",
335 "markdown-before-content",
336 "files to include inline between <body> and the content of a rendered \
337 Markdown file or generated documentation",
338 "FILES",
339 ),
340 opt(
341 Unstable,
342 Multi,
343 "",
344 "markdown-after-content",
345 "files to include inline between the content and </body> of a rendered \
346 Markdown file or generated documentation",
347 "FILES",
348 ),
349 opt(Stable, Opt, "", "markdown-playground-url", "URL to send code snippets to", "URL"),
350 opt(Stable, FlagMulti, "", "markdown-no-toc", "don't include table of contents", ""),
351 opt(
352 Stable,
353 Opt,
354 "e",
355 "extend-css",
356 "To add some CSS rules with a given file to generate doc with your own theme. \
357 However, your theme might break if the rustdoc's generated HTML changes, so be careful!",
358 "PATH",
359 ),
360 opt(
361 Unstable,
362 Multi,
363 "Z",
364 "",
365 "unstable / perma-unstable options (only on nightly build)",
366 "FLAG",
367 ),
368 opt(Stable, Opt, "", "sysroot", "Override the system root", "PATH"),
369 opt(
370 Unstable,
371 Opt,
372 "",
373 "playground-url",
374 "URL to send code snippets to, may be reset by --markdown-playground-url \
375 or `#![doc(html_playground_url=...)]`",
376 "URL",
377 ),
378 opt(
379 Unstable,
380 FlagMulti,
381 "",
382 "display-doctest-warnings",
383 "show warnings that originate in doctests",
384 "",
385 ),
386 opt(
387 Stable,
388 Opt,
389 "",
390 "crate-version",
391 "crate version to print into documentation",
392 "VERSION",
393 ),
394 opt(
395 Unstable,
396 FlagMulti,
397 "",
398 "sort-modules-by-appearance",
399 "sort modules by where they appear in the program, rather than alphabetically",
400 "",
401 ),
402 opt(
403 Stable,
404 Opt,
405 "",
406 "default-theme",
407 "Set the default theme. THEME should be the theme name, generally lowercase. \
408 If an unknown default theme is specified, the builtin default is used. \
409 The set of themes, and the rustdoc built-in default, are not stable.",
410 "THEME",
411 ),
412 opt(
413 Unstable,
414 Multi,
415 "",
416 "default-setting",
417 "Default value for a rustdoc setting (used when \"rustdoc-SETTING\" is absent \
418 from web browser Local Storage). If VALUE is not supplied, \"true\" is used. \
419 Supported SETTINGs and VALUEs are not documented and not stable.",
420 "SETTING[=VALUE]",
421 ),
422 opt(
423 Stable,
424 Multi,
425 "",
426 "theme",
427 "additional themes which will be added to the generated docs",
428 "FILES",
429 ),
430 opt(Stable, Multi, "", "check-theme", "check if given theme is valid", "FILES"),
431 opt(
432 Unstable,
433 Opt,
434 "",
435 "resource-suffix",
436 "suffix to add to CSS and JavaScript files, \
437 e.g., \"search-index.js\" will become \"search-index-suffix.js\"",
438 "PATH",
439 ),
440 opt(
441 Stable,
442 Opt,
443 "",
444 "edition",
445 "edition to use when compiling rust code (default: 2015)",
446 "EDITION",
447 ),
448 opt(
449 Stable,
450 Opt,
451 "",
452 "color",
453 "Configure coloring of output:
454 auto = colorize, if output goes to a tty (default);
455 always = always colorize output;
456 never = never colorize output",
457 "auto|always|never",
458 ),
459 opt(
460 Stable,
461 Opt,
462 "",
463 "error-format",
464 "How errors and other messages are produced",
465 "human|json|short",
466 ),
467 opt(
468 Stable,
469 Opt,
470 "",
471 "diagnostic-width",
472 "Provide width of the output for truncated error messages",
473 "WIDTH",
474 ),
475 opt(Stable, Opt, "", "json", "Configure the structure of JSON diagnostics", "CONFIG"),
476 opt(Stable, Multi, "A", "allow", "Set lint allowed", "LINT"),
477 opt(Stable, Multi, "W", "warn", "Set lint warnings", "LINT"),
478 opt(Stable, Multi, "", "force-warn", "Set lint force-warn", "LINT"),
479 opt(Stable, Multi, "D", "deny", "Set lint denied", "LINT"),
480 opt(Stable, Multi, "F", "forbid", "Set lint forbidden", "LINT"),
481 opt(
482 Stable,
483 Multi,
484 "",
485 "cap-lints",
486 "Set the most restrictive lint level. \
487 More restrictive lints are capped at this level. \
488 By default, it is at `forbid` level.",
489 "LEVEL",
490 ),
491 opt(Unstable, Opt, "", "index-page", "Markdown file to be used as index page", "PATH"),
492 opt(
493 Unstable,
494 FlagMulti,
495 "",
496 "enable-index-page",
497 "To enable generation of the index page",
498 "",
499 ),
500 opt(
501 Unstable,
502 Opt,
503 "",
504 "static-root-path",
505 "Path string to force loading static files from in output pages. \
506 If not set, uses combinations of '../' to reach the documentation root.",
507 "PATH",
508 ),
509 opt(
510 Unstable,
511 Opt,
512 "",
513 "persist-doctests",
514 "Directory to persist doctest executables into",
515 "PATH",
516 ),
517 opt(
518 Unstable,
519 FlagMulti,
520 "",
521 "show-coverage",
522 "calculate percentage of public items with documentation",
523 "",
524 ),
525 opt(
526 Stable,
527 Opt,
528 "",
529 "test-runtool",
530 "",
531 "The tool to run tests with when building for a different target than host",
532 ),
533 opt(
534 Stable,
535 Multi,
536 "",
537 "test-runtool-arg",
538 "",
539 "One argument (of possibly many) to pass to the runtool",
540 ),
541 opt(
542 Unstable,
543 Opt,
544 "",
545 "test-builder",
546 "The rustc-like binary to use as the test builder",
547 "PATH",
548 ),
549 opt(
550 Unstable,
551 Multi,
552 "",
553 "test-builder-wrapper",
554 "Wrapper program to pass test-builder and arguments",
555 "PATH",
556 ),
557 opt(Unstable, FlagMulti, "", "check", "Run rustdoc checks", ""),
558 opt(
559 Unstable,
560 FlagMulti,
561 "",
562 "generate-redirect-map",
563 "Generate JSON file at the top level instead of generating HTML redirection files",
564 "",
565 ),
566 opt(
567 Unstable,
568 Multi,
569 "",
570 "emit",
571 "Comma separated list of types of output for rustdoc to emit",
572 "[unversioned-shared-resources,toolchain-shared-resources,invocation-specific,dep-info]",
573 ),
574 opt(Unstable, FlagMulti, "", "no-run", "Compile doctests without running them", ""),
575 opt(
576 Unstable,
577 Multi,
578 "",
579 "remap-path-prefix",
580 "Remap source names in compiler messages",
581 "FROM=TO",
582 ),
583 opt(
584 Unstable,
585 FlagMulti,
586 "",
587 "show-type-layout",
588 "Include the memory layout of types in the docs",
589 "",
590 ),
591 opt(Unstable, Flag, "", "nocapture", "Don't capture stdout and stderr of tests", ""),
592 opt(
593 Unstable,
594 Flag,
595 "",
596 "generate-link-to-definition",
597 "Make the identifiers in the HTML source code pages navigable",
598 "",
599 ),
600 opt(
601 Unstable,
602 Opt,
603 "",
604 "scrape-examples-output-path",
605 "",
606 "collect function call information and output at the given path",
607 ),
608 opt(
609 Unstable,
610 Multi,
611 "",
612 "scrape-examples-target-crate",
613 "",
614 "collect function call information for functions from the target crate",
615 ),
616 opt(Unstable, Flag, "", "scrape-tests", "Include test code when scraping examples", ""),
617 opt(
618 Unstable,
619 Multi,
620 "",
621 "with-examples",
622 "",
623 "path to function call information (for displaying examples in the documentation)",
624 ),
625 opt(
626 Unstable,
627 Opt,
628 "",
629 "merge",
630 "Controls how rustdoc handles files from previously documented crates in the doc root\n\
631 none = Do not write cross-crate information to the --out-dir\n\
632 shared = Append current crate's info to files found in the --out-dir\n\
633 finalize = Write current crate's info and --include-parts-dir info to the --out-dir, overwriting conflicting files",
634 "none|shared|finalize",
635 ),
636 opt(
637 Unstable,
638 Opt,
639 "",
640 "parts-out-dir",
641 "Writes trait implementations and other info for the current crate to provided path. Only use with --merge=none",
642 "path/to/doc.parts/<crate-name>",
643 ),
644 opt(
645 Unstable,
646 Multi,
647 "",
648 "include-parts-dir",
649 "Includes trait implementations and other crate info from provided path. Only use with --merge=finalize",
650 "path/to/doc.parts/<crate-name>",
651 ),
652 opt(Unstable, Flag, "", "html-no-source", "Disable HTML source code pages generation", ""),
653 opt(
654 Unstable,
655 Multi,
656 "",
657 "doctest-compilation-args",
658 "",
659 "add arguments to be used when compiling doctests",
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 // deprecated / removed options
670 opt(
671 Stable,
672 Multi,
673 "",
674 "plugin-path",
675 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
676 "DIR",
677 ),
678 opt(
679 Stable,
680 Multi,
681 "",
682 "passes",
683 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
684 "PASSES",
685 ),
686 opt(
687 Stable,
688 Multi,
689 "",
690 "plugins",
691 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
692 "PLUGINS",
693 ),
694 opt(
695 Stable,
696 FlagMulti,
697 "",
698 "no-defaults",
699 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
700 "",
701 ),
702 opt(
703 Stable,
704 Opt,
705 "r",
706 "input-format",
707 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
708 "[rust]",
709 ),
710 ]
711}
712
713fn usage(argv0: &str) {
714 let mut options = getopts::Options::new();
715 for option in opts() {
716 option.apply(&mut options);
717 }
718 println!("{}", options.usage(&format!("{argv0} [options] <input>")));
719 println!(" @path Read newline separated options from `path`\n");
720 println!(
721 "More information available at {DOC_RUST_LANG_ORG_VERSION}/rustdoc/what-is-rustdoc.html",
722 );
723}
724
725pub(crate) fn wrap_return(dcx: DiagCtxtHandle<'_>, res: Result<(), String>) {
726 match res {
727 Ok(()) => dcx.abort_if_errors(),
728 Err(err) => dcx.fatal(err),
729 }
730}
731
732fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>(
733 krate: clean::Crate,
734 renderopts: config::RenderOptions,
735 cache: formats::cache::Cache,
736 tcx: TyCtxt<'tcx>,
737) {
738 match formats::run_format::<T>(krate, renderopts, cache, tcx) {
739 Ok(_) => tcx.dcx().abort_if_errors(),
740 Err(e) => {
741 let mut msg =
742 tcx.dcx().struct_fatal(format!("couldn't generate documentation: {}", e.error));
743 let file = e.file.display().to_string();
744 if !file.is_empty() {
745 msg.note(format!("failed to create or modify \"{file}\""));
746 }
747 msg.emit();
748 }
749 }
750}
751
752/// Renders and writes cross-crate info files, like the search index. This function exists so that
753/// we can run rustdoc without a crate root in the `--merge=finalize` mode. Cross-crate info files
754/// discovered via `--include-parts-dir` are combined and written to the doc root.
755fn run_merge_finalize(opt: config::RenderOptions) -> Result<(), error::Error> {
756 assert!(
757 opt.should_merge.write_rendered_cci,
758 "config.rs only allows us to return InputMode::NoInputMergeFinalize if --merge=finalize"
759 );
760 assert!(
761 !opt.should_merge.read_rendered_cci,
762 "config.rs only allows us to return InputMode::NoInputMergeFinalize if --merge=finalize"
763 );
764 let crates = html::render::CrateInfo::read_many(&opt.include_parts_dir)?;
765 let include_sources = !opt.html_no_source;
766 html::render::write_not_crate_specific(
767 &crates,
768 &opt.output,
769 &opt,
770 &opt.themes,
771 opt.extension_css.as_deref(),
772 &opt.resource_suffix,
773 include_sources,
774 )?;
775 Ok(())
776}
777
778fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
779 // Throw away the first argument, the name of the binary.
780 // In case of at_args being empty, as might be the case by
781 // passing empty argument array to execve under some platforms,
782 // just use an empty slice.
783 //
784 // This situation was possible before due to arg_expand_all being
785 // called before removing the argument, enabling a crash by calling
786 // the compiler with @empty_file as argv[0] and no more arguments.
787 let at_args = at_args.get(1..).unwrap_or_default();
788
789 let args = rustc_driver::args::arg_expand_all(early_dcx, at_args);
790
791 let mut options = getopts::Options::new();
792 for option in opts() {
793 option.apply(&mut options);
794 }
795 let matches = match options.parse(&args) {
796 Ok(m) => m,
797 Err(err) => {
798 early_dcx.early_fatal(err.to_string());
799 }
800 };
801
802 // Note that we discard any distinction between different non-zero exit
803 // codes from `from_matches` here.
804 let (input, options, render_options) =
805 match config::Options::from_matches(early_dcx, &matches, args) {
806 Some(opts) => opts,
807 None => return,
808 };
809
810 let dcx =
811 core::new_dcx(options.error_format, None, options.diagnostic_width, &options.unstable_opts);
812 let dcx = dcx.handle();
813
814 let input = match input {
815 config::InputMode::HasFile(input) => input,
816 config::InputMode::NoInputMergeFinalize => {
817 return wrap_return(
818 dcx,
819 run_merge_finalize(render_options)
820 .map_err(|e| format!("could not write merged cross-crate info: {e}")),
821 );
822 }
823 };
824
825 let output_format = options.output_format;
826
827 match (
828 options.should_test || output_format == config::OutputFormat::Doctest,
829 config::markdown_input(&input),
830 ) {
831 (true, Some(_)) => return wrap_return(dcx, doctest::test_markdown(&input, options)),
832 (true, None) => return doctest::run(dcx, input, options),
833 (false, Some(md_input)) => {
834 let md_input = md_input.to_owned();
835 let edition = options.edition;
836 let config = core::create_config(input, options, &render_options);
837
838 // `markdown::render` can invoke `doctest::make_test`, which
839 // requires session globals and a thread pool, so we use
840 // `run_compiler`.
841 return wrap_return(
842 dcx,
843 interface::run_compiler(config, |_compiler| {
844 markdown::render_and_write(&md_input, render_options, edition)
845 }),
846 );
847 }
848 (false, None) => {}
849 }
850
851 // need to move these items separately because we lose them by the time the closure is called,
852 // but we can't create the dcx ahead of time because it's not Send
853 let show_coverage = options.show_coverage;
854 let run_check = options.run_check;
855
856 // First, parse the crate and extract all relevant information.
857 info!("starting to run rustc");
858
859 // Interpret the input file as a rust source file, passing it through the
860 // compiler all the way through the analysis passes. The rustdoc output is
861 // then generated from the cleaned AST of the crate. This runs all the
862 // plug/cleaning passes.
863 let crate_version = options.crate_version.clone();
864
865 let scrape_examples_options = options.scrape_examples_options.clone();
866 let bin_crate = options.bin_crate;
867
868 let config = core::create_config(input, options, &render_options);
869
870 let registered_lints = config.register_lints.is_some();
871
872 interface::run_compiler(config, |compiler| {
873 let sess = &compiler.sess;
874
875 if sess.opts.describe_lints {
876 rustc_driver::describe_lints(sess, registered_lints);
877 return;
878 }
879
880 let krate = rustc_interface::passes::parse(sess);
881 rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| {
882 if sess.dcx().has_errors().is_some() {
883 sess.dcx().fatal("Compilation failed, aborting rustdoc");
884 }
885
886 let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || {
887 core::run_global_ctxt(tcx, show_coverage, render_options, output_format)
888 });
889 info!("finished with rustc");
890
891 if let Some(options) = scrape_examples_options {
892 return scrape_examples::run(krate, render_opts, cache, tcx, options, bin_crate);
893 }
894
895 cache.crate_version = crate_version;
896
897 if show_coverage {
898 // if we ran coverage, bail early, we don't need to also generate docs at this point
899 // (also we didn't load in any of the useful passes)
900 return;
901 }
902
903 if render_opts.dep_info().is_some() {
904 rustc_interface::passes::write_dep_info(tcx);
905 }
906
907 if run_check {
908 // Since we're in "check" mode, no need to generate anything beyond this point.
909 return;
910 }
911
912 info!("going to format");
913 match output_format {
914 config::OutputFormat::Html => sess.time("render_html", || {
915 run_renderer::<html::render::Context<'_>>(krate, render_opts, cache, tcx)
916 }),
917 config::OutputFormat::Json => sess.time("render_json", || {
918 run_renderer::<json::JsonRenderer<'_>>(krate, render_opts, cache, tcx)
919 }),
920 // Already handled above with doctest runners.
921 config::OutputFormat::Doctest => unreachable!(),
922 }
923 })
924 })
925}