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>&gt;</mo></mrow><annotation encoding="application/x-tex">key: expr =&gt; </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">=&gt;</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}