"Fossies" - the Fresh Open Source Software Archive

Member "rustc-1.60.0-src/src/librustdoc/lib.rs" (4 Apr 2022, 30896 Bytes) of package /linux/misc/rustc-1.60.0-src.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Rust source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "lib.rs": 1.59.0_vs_1.60.0.

    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(array_methods)]
    7 #![feature(assert_matches)]
    8 #![feature(bool_to_option)]
    9 #![feature(box_patterns)]
   10 #![feature(control_flow_enum)]
   11 #![feature(box_syntax)]
   12 #![feature(let_else)]
   13 #![feature(nll)]
   14 #![feature(test)]
   15 #![feature(crate_visibility_modifier)]
   16 #![feature(never_type)]
   17 #![feature(once_cell)]
   18 #![feature(type_ascription)]
   19 #![feature(iter_intersperse)]
   20 #![feature(type_alias_impl_trait)]
   21 #![feature(generic_associated_types)]
   22 #![recursion_limit = "256"]
   23 #![warn(rustc::internal)]
   24 #![allow(clippy::collapsible_if, clippy::collapsible_else_if)]
   25 
   26 #[macro_use]
   27 extern crate tracing;
   28 
   29 // N.B. these need `extern crate` even in 2018 edition
   30 // because they're loaded implicitly from the sysroot.
   31 // The reason they're loaded from the sysroot is because
   32 // the rustdoc artifacts aren't stored in rustc's cargo target directory.
   33 // So if `rustc` was specified in Cargo.toml, this would spuriously rebuild crates.
   34 //
   35 // Dependencies listed in Cargo.toml do not need `extern crate`.
   36 
   37 extern crate rustc_ast;
   38 extern crate rustc_ast_lowering;
   39 extern crate rustc_ast_pretty;
   40 extern crate rustc_attr;
   41 extern crate rustc_const_eval;
   42 extern crate rustc_data_structures;
   43 extern crate rustc_driver;
   44 extern crate rustc_errors;
   45 extern crate rustc_expand;
   46 extern crate rustc_feature;
   47 extern crate rustc_hir;
   48 extern crate rustc_hir_pretty;
   49 extern crate rustc_index;
   50 extern crate rustc_infer;
   51 extern crate rustc_interface;
   52 extern crate rustc_lexer;
   53 extern crate rustc_lint;
   54 extern crate rustc_lint_defs;
   55 extern crate rustc_macros;
   56 extern crate rustc_metadata;
   57 extern crate rustc_middle;
   58 extern crate rustc_parse;
   59 extern crate rustc_passes;
   60 extern crate rustc_resolve;
   61 extern crate rustc_serialize;
   62 extern crate rustc_session;
   63 extern crate rustc_span;
   64 extern crate rustc_target;
   65 extern crate rustc_trait_selection;
   66 extern crate rustc_typeck;
   67 extern 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")]
   72 extern crate tikv_jemalloc_sys;
   73 #[cfg(feature = "jemalloc")]
   74 use tikv_jemalloc_sys as jemalloc_sys;
   75 
   76 use std::default::Default;
   77 use std::env::{self, VarError};
   78 use std::io;
   79 use std::process;
   80 
   81 use rustc_driver::{abort_on_err, describe_lints};
   82 use rustc_errors::ErrorReported;
   83 use rustc_interface::interface;
   84 use rustc_middle::ty::TyCtxt;
   85 use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup};
   86 use rustc_session::getopts;
   87 use rustc_session::{early_error, early_warn};
   88 
   89 use crate::clean::utils::DOC_RUST_LANG_ORG_CHANNEL;
   90 use crate::passes::collect_intra_doc_links;
   91 
   92 /// A macro to create a FxHashMap.
   93 ///
   94 /// Example:
   95 ///
   96 /// ```
   97 /// let letters = map!{"a" => "b", "c" => "d"};
   98 /// ```
   99 ///
  100 /// Trailing commas are allowed.
  101 /// Commas between elements are required (even if the expression is a block).
  102 macro_rules! map {
  103     ($( $key: expr => $val: expr ),* $(,)*) => {{
  104         let mut map = ::rustc_data_structures::fx::FxHashMap::default();
  105         $( map.insert($key, $val); )*
  106         map
  107     }}
  108 }
  109 
  110 mod clean;
  111 mod config;
  112 mod core;
  113 mod docfs;
  114 mod doctest;
  115 mod error;
  116 mod externalfiles;
  117 mod fold;
  118 mod formats;
  119 // used by the error-index generator, so it needs to be public
  120 pub mod html;
  121 mod json;
  122 crate mod lint;
  123 mod markdown;
  124 mod passes;
  125 mod scrape_examples;
  126 mod theme;
  127 mod visit;
  128 mod visit_ast;
  129 mod visit_lib;
  130 
  131 pub fn main() {
  132     // See docs in https://github.com/rust-lang/rust/blob/master/compiler/rustc/src/main.rs
  133     // about jemalloc.
  134     #[cfg(feature = "jemalloc")]
  135     {
  136         use std::os::raw::{c_int, c_void};
  137 
  138         #[used]
  139         static _F1: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::calloc;
  140         #[used]
  141         static _F2: unsafe extern "C" fn(*mut *mut c_void, usize, usize) -> c_int =
  142             jemalloc_sys::posix_memalign;
  143         #[used]
  144         static _F3: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::aligned_alloc;
  145         #[used]
  146         static _F4: unsafe extern "C" fn(usize) -> *mut c_void = jemalloc_sys::malloc;
  147         #[used]
  148         static _F5: unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void = jemalloc_sys::realloc;
  149         #[used]
  150         static _F6: unsafe extern "C" fn(*mut c_void) = jemalloc_sys::free;
  151 
  152         #[cfg(target_os = "macos")]
  153         {
  154             extern "C" {
  155                 fn _rjem_je_zone_register();
  156             }
  157 
  158             #[used]
  159             static _F7: unsafe extern "C" fn() = _rjem_je_zone_register;
  160         }
  161     }
  162 
  163     rustc_driver::set_sigpipe_handler();
  164     rustc_driver::install_ice_hook();
  165 
  166     // When using CI artifacts (with `download_stage1 = true`), tracing is unconditionally built
  167     // with `--features=static_max_level_info`, which disables almost all rustdoc logging. To avoid
  168     // this, compile our own version of `tracing` that logs all levels.
  169     // NOTE: this compiles both versions of tracing unconditionally, because
  170     // - The compile time hit is not that bad, especially compared to rustdoc's incremental times, and
  171     // - Otherwise, there's no warning that logging is being ignored when `download_stage1 = true`.
  172     // NOTE: The reason this doesn't show double logging when `download_stage1 = false` and
  173     // `debug_logging = true` is because all rustc logging goes to its version of tracing (the one
  174     // in the sysroot), and all of rustdoc's logging goes to its version (the one in Cargo.toml).
  175     init_logging();
  176     rustc_driver::init_env_logger("RUSTDOC_LOG");
  177 
  178     let exit_code = rustc_driver::catch_with_exit_code(|| match get_args() {
  179         Some(args) => main_args(&args),
  180         _ => Err(ErrorReported),
  181     });
  182     process::exit(exit_code);
  183 }
  184 
  185 fn init_logging() {
  186     let color_logs = match std::env::var("RUSTDOC_LOG_COLOR").as_deref() {
  187         Ok("always") => true,
  188         Ok("never") => false,
  189         Ok("auto") | Err(VarError::NotPresent) => atty::is(atty::Stream::Stdout),
  190         Ok(value) => early_error(
  191             ErrorOutputType::default(),
  192             &format!("invalid log color value '{}': expected one of always, never, or auto", value),
  193         ),
  194         Err(VarError::NotUnicode(value)) => early_error(
  195             ErrorOutputType::default(),
  196             &format!(
  197                 "invalid log color value '{}': expected one of always, never, or auto",
  198                 value.to_string_lossy()
  199             ),
  200         ),
  201     };
  202     let filter = tracing_subscriber::EnvFilter::from_env("RUSTDOC_LOG");
  203     let layer = tracing_tree::HierarchicalLayer::default()
  204         .with_writer(io::stderr)
  205         .with_indent_lines(true)
  206         .with_ansi(color_logs)
  207         .with_targets(true)
  208         .with_wraparound(10)
  209         .with_verbose_exit(true)
  210         .with_verbose_entry(true)
  211         .with_indent_amount(2);
  212     #[cfg(parallel_compiler)]
  213     let layer = layer.with_thread_ids(true).with_thread_names(true);
  214 
  215     use tracing_subscriber::layer::SubscriberExt;
  216     let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
  217     tracing::subscriber::set_global_default(subscriber).unwrap();
  218 }
  219 
  220 fn get_args() -> Option<Vec<String>> {
  221     env::args_os()
  222         .enumerate()
  223         .map(|(i, arg)| {
  224             arg.into_string()
  225                 .map_err(|arg| {
  226                     early_warn(
  227                         ErrorOutputType::default(),
  228                         &format!("Argument {} is not valid Unicode: {:?}", i, arg),
  229                     );
  230                 })
  231                 .ok()
  232         })
  233         .collect()
  234 }
  235 
  236 fn opts() -> Vec<RustcOptGroup> {
  237     let stable: fn(_, fn(&mut getopts::Options) -> &mut _) -> _ = RustcOptGroup::stable;
  238     let unstable: fn(_, fn(&mut getopts::Options) -> &mut _) -> _ = RustcOptGroup::unstable;
  239     vec![
  240         stable("h", |o| o.optflagmulti("h", "help", "show this help message")),
  241         stable("V", |o| o.optflagmulti("V", "version", "print rustdoc's version")),
  242         stable("v", |o| o.optflagmulti("v", "verbose", "use verbose output")),
  243         stable("w", |o| o.optopt("w", "output-format", "the output type to write", "[html]")),
  244         stable("output", |o| {
  245             o.optopt(
  246                 "",
  247                 "output",
  248                 "Which directory to place the output. \
  249                  This option is deprecated, use --out-dir instead.",
  250                 "PATH",
  251             )
  252         }),
  253         stable("o", |o| o.optopt("o", "out-dir", "which directory to place the output", "PATH")),
  254         stable("crate-name", |o| {
  255             o.optopt("", "crate-name", "specify the name of this crate", "NAME")
  256         }),
  257         make_crate_type_option(),
  258         stable("L", |o| {
  259             o.optmulti("L", "library-path", "directory to add to crate search path", "DIR")
  260         }),
  261         stable("cfg", |o| o.optmulti("", "cfg", "pass a --cfg to rustc", "")),
  262         stable("extern", |o| o.optmulti("", "extern", "pass an --extern to rustc", "NAME[=PATH]")),
  263         unstable("extern-html-root-url", |o| {
  264             o.optmulti(
  265                 "",
  266                 "extern-html-root-url",
  267                 "base URL to use for dependencies; for example, \
  268                  \"std=/doc\" links std::vec::Vec to /doc/std/vec/struct.Vec.html",
  269                 "NAME=URL",
  270             )
  271         }),
  272         unstable("extern-html-root-takes-precedence", |o| {
  273             o.optflagmulti(
  274                 "",
  275                 "extern-html-root-takes-precedence",
  276                 "give precedence to `--extern-html-root-url`, not `html_root_url`",
  277             )
  278         }),
  279         stable("C", |o| {
  280             o.optmulti("C", "codegen", "pass a codegen option to rustc", "OPT[=VALUE]")
  281         }),
  282         stable("document-private-items", |o| {
  283             o.optflagmulti("", "document-private-items", "document private items")
  284         }),
  285         unstable("document-hidden-items", |o| {
  286             o.optflagmulti("", "document-hidden-items", "document items that have doc(hidden)")
  287         }),
  288         stable("test", |o| o.optflagmulti("", "test", "run code examples as tests")),
  289         stable("test-args", |o| {
  290             o.optmulti("", "test-args", "arguments to pass to the test runner", "ARGS")
  291         }),
  292         unstable("test-run-directory", |o| {
  293             o.optopt(
  294                 "",
  295                 "test-run-directory",
  296                 "The working directory in which to run tests",
  297                 "PATH",
  298             )
  299         }),
  300         stable("target", |o| o.optopt("", "target", "target triple to document", "TRIPLE")),
  301         stable("markdown-css", |o| {
  302             o.optmulti(
  303                 "",
  304                 "markdown-css",
  305                 "CSS files to include via <link> in a rendered Markdown file",
  306                 "FILES",
  307             )
  308         }),
  309         stable("html-in-header", |o| {
  310             o.optmulti(
  311                 "",
  312                 "html-in-header",
  313                 "files to include inline in the <head> section of a rendered Markdown file \
  314                  or generated documentation",
  315                 "FILES",
  316             )
  317         }),
  318         stable("html-before-content", |o| {
  319             o.optmulti(
  320                 "",
  321                 "html-before-content",
  322                 "files to include inline between <body> and the content of a rendered \
  323                  Markdown file or generated documentation",
  324                 "FILES",
  325             )
  326         }),
  327         stable("html-after-content", |o| {
  328             o.optmulti(
  329                 "",
  330                 "html-after-content",
  331                 "files to include inline between the content and </body> of a rendered \
  332                  Markdown file or generated documentation",
  333                 "FILES",
  334             )
  335         }),
  336         unstable("markdown-before-content", |o| {
  337             o.optmulti(
  338                 "",
  339                 "markdown-before-content",
  340                 "files to include inline between <body> and the content of a rendered \
  341                  Markdown file or generated documentation",
  342                 "FILES",
  343             )
  344         }),
  345         unstable("markdown-after-content", |o| {
  346             o.optmulti(
  347                 "",
  348                 "markdown-after-content",
  349                 "files to include inline between the content and </body> of a rendered \
  350                  Markdown file or generated documentation",
  351                 "FILES",
  352             )
  353         }),
  354         stable("markdown-playground-url", |o| {
  355             o.optopt("", "markdown-playground-url", "URL to send code snippets to", "URL")
  356         }),
  357         stable("markdown-no-toc", |o| {
  358             o.optflagmulti("", "markdown-no-toc", "don't include table of contents")
  359         }),
  360         stable("e", |o| {
  361             o.optopt(
  362                 "e",
  363                 "extend-css",
  364                 "To add some CSS rules with a given file to generate doc with your \
  365                  own theme. However, your theme might break if the rustdoc's generated HTML \
  366                  changes, so be careful!",
  367                 "PATH",
  368             )
  369         }),
  370         unstable("Z", |o| {
  371             o.optmulti("Z", "", "internal and debugging options (only on nightly build)", "FLAG")
  372         }),
  373         stable("sysroot", |o| o.optopt("", "sysroot", "Override the system root", "PATH")),
  374         unstable("playground-url", |o| {
  375             o.optopt(
  376                 "",
  377                 "playground-url",
  378                 "URL to send code snippets to, may be reset by --markdown-playground-url \
  379                  or `#![doc(html_playground_url=...)]`",
  380                 "URL",
  381             )
  382         }),
  383         unstable("display-doctest-warnings", |o| {
  384             o.optflagmulti(
  385                 "",
  386                 "display-doctest-warnings",
  387                 "show warnings that originate in doctests",
  388             )
  389         }),
  390         stable("crate-version", |o| {
  391             o.optopt("", "crate-version", "crate version to print into documentation", "VERSION")
  392         }),
  393         unstable("sort-modules-by-appearance", |o| {
  394             o.optflagmulti(
  395                 "",
  396                 "sort-modules-by-appearance",
  397                 "sort modules by where they appear in the program, rather than alphabetically",
  398             )
  399         }),
  400         stable("default-theme", |o| {
  401             o.optopt(
  402                 "",
  403                 "default-theme",
  404                 "Set the default theme. THEME should be the theme name, generally lowercase. \
  405                  If an unknown default theme is specified, the builtin default is used. \
  406                  The set of themes, and the rustdoc built-in default, are not stable.",
  407                 "THEME",
  408             )
  409         }),
  410         unstable("default-setting", |o| {
  411             o.optmulti(
  412                 "",
  413                 "default-setting",
  414                 "Default value for a rustdoc setting (used when \"rustdoc-SETTING\" is absent \
  415                  from web browser Local Storage). If VALUE is not supplied, \"true\" is used. \
  416                  Supported SETTINGs and VALUEs are not documented and not stable.",
  417                 "SETTING[=VALUE]",
  418             )
  419         }),
  420         stable("theme", |o| {
  421             o.optmulti(
  422                 "",
  423                 "theme",
  424                 "additional themes which will be added to the generated docs",
  425                 "FILES",
  426             )
  427         }),
  428         stable("check-theme", |o| {
  429             o.optmulti("", "check-theme", "check if given theme is valid", "FILES")
  430         }),
  431         unstable("resource-suffix", |o| {
  432             o.optopt(
  433                 "",
  434                 "resource-suffix",
  435                 "suffix to add to CSS and JavaScript files, e.g., \"light.css\" will become \
  436                  \"light-suffix.css\"",
  437                 "PATH",
  438             )
  439         }),
  440         stable("edition", |o| {
  441             o.optopt(
  442                 "",
  443                 "edition",
  444                 "edition to use when compiling rust code (default: 2015)",
  445                 "EDITION",
  446             )
  447         }),
  448         stable("color", |o| {
  449             o.optopt(
  450                 "",
  451                 "color",
  452                 "Configure coloring of output:
  453                                           auto   = colorize, if output goes to a tty (default);
  454                                           always = always colorize output;
  455                                           never  = never colorize output",
  456                 "auto|always|never",
  457             )
  458         }),
  459         stable("error-format", |o| {
  460             o.optopt(
  461                 "",
  462                 "error-format",
  463                 "How errors and other messages are produced",
  464                 "human|json|short",
  465             )
  466         }),
  467         stable("json", |o| {
  468             o.optopt("", "json", "Configure the structure of JSON diagnostics", "CONFIG")
  469         }),
  470         unstable("disable-minification", |o| {
  471             o.optflagmulti("", "disable-minification", "Disable minification applied on JS files")
  472         }),
  473         stable("allow", |o| o.optmulti("A", "allow", "Set lint allowed", "LINT")),
  474         stable("warn", |o| o.optmulti("W", "warn", "Set lint warnings", "LINT")),
  475         stable("force-warn", |o| o.optmulti("", "force-warn", "Set lint force-warn", "LINT")),
  476         stable("deny", |o| o.optmulti("D", "deny", "Set lint denied", "LINT")),
  477         stable("forbid", |o| o.optmulti("F", "forbid", "Set lint forbidden", "LINT")),
  478         stable("cap-lints", |o| {
  479             o.optmulti(
  480                 "",
  481                 "cap-lints",
  482                 "Set the most restrictive lint level. \
  483                  More restrictive lints are capped at this \
  484                  level. By default, it is at `forbid` level.",
  485                 "LEVEL",
  486             )
  487         }),
  488         unstable("index-page", |o| {
  489             o.optopt("", "index-page", "Markdown file to be used as index page", "PATH")
  490         }),
  491         unstable("enable-index-page", |o| {
  492             o.optflagmulti("", "enable-index-page", "To enable generation of the index page")
  493         }),
  494         unstable("static-root-path", |o| {
  495             o.optopt(
  496                 "",
  497                 "static-root-path",
  498                 "Path string to force loading static files from in output pages. \
  499                  If not set, uses combinations of '../' to reach the documentation root.",
  500                 "PATH",
  501             )
  502         }),
  503         unstable("disable-per-crate-search", |o| {
  504             o.optflagmulti(
  505                 "",
  506                 "disable-per-crate-search",
  507                 "disables generating the crate selector on the search box",
  508             )
  509         }),
  510         unstable("persist-doctests", |o| {
  511             o.optopt(
  512                 "",
  513                 "persist-doctests",
  514                 "Directory to persist doctest executables into",
  515                 "PATH",
  516             )
  517         }),
  518         unstable("show-coverage", |o| {
  519             o.optflagmulti(
  520                 "",
  521                 "show-coverage",
  522                 "calculate percentage of public items with documentation",
  523             )
  524         }),
  525         unstable("enable-per-target-ignores", |o| {
  526             o.optflagmulti(
  527                 "",
  528                 "enable-per-target-ignores",
  529                 "parse ignore-foo for ignoring doctests on a per-target basis",
  530             )
  531         }),
  532         unstable("runtool", |o| {
  533             o.optopt(
  534                 "",
  535                 "runtool",
  536                 "",
  537                 "The tool to run tests with when building for a different target than host",
  538             )
  539         }),
  540         unstable("runtool-arg", |o| {
  541             o.optmulti(
  542                 "",
  543                 "runtool-arg",
  544                 "",
  545                 "One (of possibly many) arguments to pass to the runtool",
  546             )
  547         }),
  548         unstable("test-builder", |o| {
  549             o.optopt("", "test-builder", "The rustc-like binary to use as the test builder", "PATH")
  550         }),
  551         unstable("check", |o| o.optflagmulti("", "check", "Run rustdoc checks")),
  552         unstable("generate-redirect-map", |o| {
  553             o.optflagmulti(
  554                 "",
  555                 "generate-redirect-map",
  556                 "Generate JSON file at the top level instead of generating HTML redirection files",
  557             )
  558         }),
  559         unstable("emit", |o| {
  560             o.optmulti(
  561                 "",
  562                 "emit",
  563                 "Comma separated list of types of output for rustdoc to emit",
  564                 "[unversioned-shared-resources,toolchain-shared-resources,invocation-specific]",
  565             )
  566         }),
  567         unstable("no-run", |o| {
  568             o.optflagmulti("", "no-run", "Compile doctests without running them")
  569         }),
  570         unstable("show-type-layout", |o| {
  571             o.optflagmulti("", "show-type-layout", "Include the memory layout of types in the docs")
  572         }),
  573         unstable("nocapture", |o| {
  574             o.optflag("", "nocapture", "Don't capture stdout and stderr of tests")
  575         }),
  576         unstable("generate-link-to-definition", |o| {
  577             o.optflag(
  578                 "",
  579                 "generate-link-to-definition",
  580                 "Make the identifiers in the HTML source code pages navigable",
  581             )
  582         }),
  583         unstable("scrape-examples-output-path", |o| {
  584             o.optopt(
  585                 "",
  586                 "scrape-examples-output-path",
  587                 "",
  588                 "collect function call information and output at the given path",
  589             )
  590         }),
  591         unstable("scrape-examples-target-crate", |o| {
  592             o.optmulti(
  593                 "",
  594                 "scrape-examples-target-crate",
  595                 "",
  596                 "collect function call information for functions from the target crate",
  597             )
  598         }),
  599         unstable("scrape-tests", |o| {
  600             o.optflag("", "scrape-tests", "Include test code when scraping examples")
  601         }),
  602         unstable("with-examples", |o| {
  603             o.optmulti(
  604                 "",
  605                 "with-examples",
  606                 "",
  607                 "path to function call information (for displaying examples in the documentation)",
  608             )
  609         }),
  610         // deprecated / removed options
  611         stable("plugin-path", |o| {
  612             o.optmulti(
  613                 "",
  614                 "plugin-path",
  615                 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
  616                 for more information",
  617                 "DIR",
  618             )
  619         }),
  620         stable("passes", |o| {
  621             o.optmulti(
  622                 "",
  623                 "passes",
  624                 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
  625                 for more information",
  626                 "PASSES",
  627             )
  628         }),
  629         stable("plugins", |o| {
  630             o.optmulti(
  631                 "",
  632                 "plugins",
  633                 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
  634                 for more information",
  635                 "PLUGINS",
  636             )
  637         }),
  638         stable("no-default", |o| {
  639             o.optflagmulti(
  640                 "",
  641                 "no-defaults",
  642                 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
  643                 for more information",
  644             )
  645         }),
  646         stable("r", |o| {
  647             o.optopt(
  648                 "r",
  649                 "input-format",
  650                 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
  651                 for more information",
  652                 "[rust]",
  653             )
  654         }),
  655     ]
  656 }
  657 
  658 fn usage(argv0: &str) {
  659     let mut options = getopts::Options::new();
  660     for option in opts() {
  661         (option.apply)(&mut options);
  662     }
  663     println!("{}", options.usage(&format!("{} [options] <input>", argv0)));
  664     println!("    @path               Read newline separated options from `path`\n");
  665     println!(
  666         "More information available at {}/rustdoc/what-is-rustdoc.html",
  667         DOC_RUST_LANG_ORG_CHANNEL
  668     );
  669 }
  670 
  671 /// A result type used by several functions under `main()`.
  672 type MainResult = Result<(), ErrorReported>;
  673 
  674 fn main_args(at_args: &[String]) -> MainResult {
  675     let args = rustc_driver::args::arg_expand_all(at_args);
  676 
  677     let mut options = getopts::Options::new();
  678     for option in opts() {
  679         (option.apply)(&mut options);
  680     }
  681     let matches = match options.parse(&args[1..]) {
  682         Ok(m) => m,
  683         Err(err) => {
  684             early_error(ErrorOutputType::default(), &err.to_string());
  685         }
  686     };
  687 
  688     // Note that we discard any distinction between different non-zero exit
  689     // codes from `from_matches` here.
  690     let options = match config::Options::from_matches(&matches) {
  691         Ok(opts) => opts,
  692         Err(code) => return if code == 0 { Ok(()) } else { Err(ErrorReported) },
  693     };
  694     rustc_interface::util::run_in_thread_pool_with_globals(
  695         options.edition,
  696         1, // this runs single-threaded, even in a parallel compiler
  697         move || main_options(options),
  698     )
  699 }
  700 
  701 fn wrap_return(diag: &rustc_errors::Handler, res: Result<(), String>) -> MainResult {
  702     match res {
  703         Ok(()) => Ok(()),
  704         Err(err) => {
  705             diag.struct_err(&err).emit();
  706             Err(ErrorReported)
  707         }
  708     }
  709 }
  710 
  711 fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>(
  712     krate: clean::Crate,
  713     renderopts: config::RenderOptions,
  714     cache: formats::cache::Cache,
  715     tcx: TyCtxt<'tcx>,
  716 ) -> MainResult {
  717     match formats::run_format::<T>(krate, renderopts, cache, tcx) {
  718         Ok(_) => Ok(()),
  719         Err(e) => {
  720             let mut msg =
  721                 tcx.sess.struct_err(&format!("couldn't generate documentation: {}", e.error));
  722             let file = e.file.display().to_string();
  723             if file.is_empty() {
  724                 msg.emit()
  725             } else {
  726                 msg.note(&format!("failed to create or modify \"{}\"", file)).emit()
  727             }
  728             Err(ErrorReported)
  729         }
  730     }
  731 }
  732 
  733 fn main_options(options: config::Options) -> MainResult {
  734     let diag = core::new_handler(options.error_format, None, &options.debugging_opts);
  735 
  736     match (options.should_test, options.markdown_input()) {
  737         (true, true) => return wrap_return(&diag, markdown::test(options)),
  738         (true, false) => return doctest::run(options),
  739         (false, true) => {
  740             return wrap_return(
  741                 &diag,
  742                 markdown::render(&options.input, options.render_options, options.edition),
  743             );
  744         }
  745         (false, false) => {}
  746     }
  747 
  748     // need to move these items separately because we lose them by the time the closure is called,
  749     // but we can't create the Handler ahead of time because it's not Send
  750     let show_coverage = options.show_coverage;
  751     let run_check = options.run_check;
  752 
  753     // First, parse the crate and extract all relevant information.
  754     info!("starting to run rustc");
  755 
  756     // Interpret the input file as a rust source file, passing it through the
  757     // compiler all the way through the analysis passes. The rustdoc output is
  758     // then generated from the cleaned AST of the crate. This runs all the
  759     // plug/cleaning passes.
  760     let crate_version = options.crate_version.clone();
  761 
  762     let output_format = options.output_format;
  763     // FIXME: fix this clone (especially render_options)
  764     let externs = options.externs.clone();
  765     let render_options = options.render_options.clone();
  766     let scrape_examples_options = options.scrape_examples_options.clone();
  767     let config = core::create_config(options);
  768 
  769     interface::create_compiler_and_run(config, |compiler| {
  770         compiler.enter(|queries| {
  771             let sess = compiler.session();
  772 
  773             if sess.opts.describe_lints {
  774                 let (_, lint_store) = &*queries.register_plugins()?.peek();
  775                 describe_lints(sess, lint_store, true);
  776                 return Ok(());
  777             }
  778 
  779             // We need to hold on to the complete resolver, so we cause everything to be
  780             // cloned for the analysis passes to use. Suboptimal, but necessary in the
  781             // current architecture.
  782             // FIXME(#83761): Resolver cloning can lead to inconsistencies between data in the
  783             // two copies because one of the copies can be modified after `TyCtxt` construction.
  784             let (resolver, resolver_caches) = {
  785                 let (krate, resolver, _) = &*abort_on_err(queries.expansion(), sess).peek();
  786                 let resolver_caches = resolver.borrow_mut().access(|resolver| {
  787                     collect_intra_doc_links::early_resolve_intra_doc_links(resolver, krate, externs)
  788                 });
  789                 (resolver.clone(), resolver_caches)
  790             };
  791 
  792             if sess.diagnostic().has_errors_or_lint_errors() {
  793                 sess.fatal("Compilation failed, aborting rustdoc");
  794             }
  795 
  796             let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).peek_mut();
  797 
  798             global_ctxt.enter(|tcx| {
  799                 let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || {
  800                     core::run_global_ctxt(
  801                         tcx,
  802                         resolver,
  803                         resolver_caches,
  804                         show_coverage,
  805                         render_options,
  806                         output_format,
  807                     )
  808                 });
  809                 info!("finished with rustc");
  810 
  811                 if let Some(options) = scrape_examples_options {
  812                     return scrape_examples::run(krate, render_opts, cache, tcx, options);
  813                 }
  814 
  815                 cache.crate_version = crate_version;
  816 
  817                 if show_coverage {
  818                     // if we ran coverage, bail early, we don't need to also generate docs at this point
  819                     // (also we didn't load in any of the useful passes)
  820                     return Ok(());
  821                 } else if run_check {
  822                     // Since we're in "check" mode, no need to generate anything beyond this point.
  823                     return Ok(());
  824                 }
  825 
  826                 info!("going to format");
  827                 match output_format {
  828                     config::OutputFormat::Html => sess.time("render_html", || {
  829                         run_renderer::<html::render::Context<'_>>(krate, render_opts, cache, tcx)
  830                     }),
  831                     config::OutputFormat::Json => sess.time("render_json", || {
  832                         run_renderer::<json::JsonRenderer<'_>>(krate, render_opts, cache, tcx)
  833                     }),
  834                 }
  835             })
  836         })
  837     })
  838 }