|  | // tidy-alphabetical-start | 
|  | #![doc( | 
|  | html_root_url = "https://doc.rust-lang.org/nightly/", | 
|  | html_playground_url = "https://play.rust-lang.org/" | 
|  | )] | 
|  | #![feature(ascii_char)] | 
|  | #![feature(ascii_char_variants)] | 
|  | #![feature(assert_matches)] | 
|  | #![feature(box_patterns)] | 
|  | #![feature(debug_closure_helpers)] | 
|  | #![feature(file_buffered)] | 
|  | #![feature(format_args_nl)] | 
|  | #![feature(if_let_guard)] | 
|  | #![feature(iter_intersperse)] | 
|  | #![feature(round_char_boundary)] | 
|  | #![feature(rustc_private)] | 
|  | #![feature(test)] | 
|  | #![warn(rustc::internal)] | 
|  | // tidy-alphabetical-end | 
|  |  | 
|  | extern crate thin_vec; | 
|  |  | 
|  | // N.B. these need `extern crate` even in 2018 edition | 
|  | // because they're loaded implicitly from the sysroot. | 
|  | // The reason they're loaded from the sysroot is because | 
|  | // the rustdoc artifacts aren't stored in rustc's cargo target directory. | 
|  | // So if `rustc` was specified in Cargo.toml, this would spuriously rebuild crates. | 
|  | // | 
|  | // Dependencies listed in Cargo.toml do not need `extern crate`. | 
|  |  | 
|  | extern crate pulldown_cmark; | 
|  | extern crate rustc_abi; | 
|  | extern crate rustc_ast; | 
|  | extern crate rustc_ast_pretty; | 
|  | extern crate rustc_attr_data_structures; | 
|  | extern crate rustc_attr_parsing; | 
|  | extern crate rustc_data_structures; | 
|  | extern crate rustc_driver; | 
|  | extern crate rustc_errors; | 
|  | extern crate rustc_expand; | 
|  | extern crate rustc_feature; | 
|  | extern crate rustc_hir; | 
|  | extern crate rustc_hir_analysis; | 
|  | extern crate rustc_hir_pretty; | 
|  | extern crate rustc_index; | 
|  | extern crate rustc_infer; | 
|  | extern crate rustc_interface; | 
|  | extern crate rustc_lexer; | 
|  | extern crate rustc_lint; | 
|  | extern crate rustc_lint_defs; | 
|  | extern crate rustc_log; | 
|  | extern crate rustc_macros; | 
|  | extern crate rustc_metadata; | 
|  | extern crate rustc_middle; | 
|  | extern crate rustc_parse; | 
|  | extern crate rustc_passes; | 
|  | extern crate rustc_resolve; | 
|  | extern crate rustc_serialize; | 
|  | extern crate rustc_session; | 
|  | extern crate rustc_span; | 
|  | extern crate rustc_target; | 
|  | extern crate rustc_trait_selection; | 
|  | extern crate test; | 
|  |  | 
|  | // See docs in https://github.com/rust-lang/rust/blob/master/compiler/rustc/src/main.rs | 
|  | // about jemalloc. | 
|  | #[cfg(feature = "jemalloc")] | 
|  | extern crate tikv_jemalloc_sys as jemalloc_sys; | 
|  |  | 
|  | use std::env::{self, VarError}; | 
|  | use std::io::{self, IsTerminal}; | 
|  | use std::path::Path; | 
|  | use std::process; | 
|  |  | 
|  | use rustc_errors::DiagCtxtHandle; | 
|  | use rustc_hir::def_id::LOCAL_CRATE; | 
|  | use rustc_interface::interface; | 
|  | use rustc_middle::ty::TyCtxt; | 
|  | use rustc_session::config::{ErrorOutputType, RustcOptGroup, make_crate_type_option}; | 
|  | use rustc_session::{EarlyDiagCtxt, getopts}; | 
|  | use tracing::info; | 
|  |  | 
|  | use crate::clean::utils::DOC_RUST_LANG_ORG_VERSION; | 
|  |  | 
|  | /// A macro to create a FxHashMap. | 
|  | /// | 
|  | /// Example: | 
|  | /// | 
|  | /// ```ignore(cannot-test-this-because-non-exported-macro) | 
|  | /// let letters = map!{"a" => "b", "c" => "d"}; | 
|  | /// ``` | 
|  | /// | 
|  | /// Trailing commas are allowed. | 
|  | /// Commas between elements are required (even if the expression is a block). | 
|  | macro_rules! map { | 
|  | ($( $key: expr => $val: expr ),* $(,)*) => {{ | 
|  | let mut map = ::rustc_data_structures::fx::FxIndexMap::default(); | 
|  | $( map.insert($key, $val); )* | 
|  | map | 
|  | }} | 
|  | } | 
|  |  | 
|  | mod clean; | 
|  | mod config; | 
|  | mod core; | 
|  | mod display; | 
|  | mod docfs; | 
|  | mod doctest; | 
|  | mod error; | 
|  | mod externalfiles; | 
|  | mod fold; | 
|  | mod formats; | 
|  | // used by the error-index generator, so it needs to be public | 
|  | pub mod html; | 
|  | mod json; | 
|  | pub(crate) mod lint; | 
|  | mod markdown; | 
|  | mod passes; | 
|  | mod scrape_examples; | 
|  | mod theme; | 
|  | mod visit; | 
|  | mod visit_ast; | 
|  | mod visit_lib; | 
|  |  | 
|  | pub fn main() { | 
|  | // See docs in https://github.com/rust-lang/rust/blob/master/compiler/rustc/src/main.rs | 
|  | // about jemalloc. | 
|  | #[cfg(feature = "jemalloc")] | 
|  | { | 
|  | use std::os::raw::{c_int, c_void}; | 
|  |  | 
|  | #[used] | 
|  | static _F1: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::calloc; | 
|  | #[used] | 
|  | static _F2: unsafe extern "C" fn(*mut *mut c_void, usize, usize) -> c_int = | 
|  | jemalloc_sys::posix_memalign; | 
|  | #[used] | 
|  | static _F3: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::aligned_alloc; | 
|  | #[used] | 
|  | static _F4: unsafe extern "C" fn(usize) -> *mut c_void = jemalloc_sys::malloc; | 
|  | #[used] | 
|  | static _F5: unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void = jemalloc_sys::realloc; | 
|  | #[used] | 
|  | static _F6: unsafe extern "C" fn(*mut c_void) = jemalloc_sys::free; | 
|  |  | 
|  | #[cfg(target_os = "macos")] | 
|  | { | 
|  | unsafe extern "C" { | 
|  | fn _rjem_je_zone_register(); | 
|  | } | 
|  |  | 
|  | #[used] | 
|  | static _F7: unsafe extern "C" fn() = _rjem_je_zone_register; | 
|  | } | 
|  | } | 
|  |  | 
|  | let mut early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default()); | 
|  |  | 
|  | rustc_driver::install_ice_hook( | 
|  | "https://github.com/rust-lang/rust/issues/new\ | 
|  | ?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md", | 
|  | |_| (), | 
|  | ); | 
|  |  | 
|  | // When using CI artifacts with `download-rustc`, tracing is unconditionally built | 
|  | // with `--features=static_max_level_info`, which disables almost all rustdoc logging. To avoid | 
|  | // this, compile our own version of `tracing` that logs all levels. | 
|  | // NOTE: this compiles both versions of tracing unconditionally, because | 
|  | // - The compile time hit is not that bad, especially compared to rustdoc's incremental times, and | 
|  | // - Otherwise, there's no warning that logging is being ignored when `download-rustc` is enabled | 
|  |  | 
|  | crate::init_logging(&early_dcx); | 
|  | match rustc_log::init_logger(rustc_log::LoggerConfig::from_env("RUSTDOC_LOG")) { | 
|  | Ok(()) => {} | 
|  | // With `download-rustc = true` there are definitely 2 distinct tracing crates in the | 
|  | // dependency graph: one in the downloaded sysroot and one built just now as a dependency of | 
|  | // rustdoc. So the sysroot's tracing is definitely not yet initialized here. | 
|  | // | 
|  | // But otherwise, depending on link style, there may or may not be 2 tracing crates in play. | 
|  | // The one we just initialized in `crate::init_logging` above is rustdoc's direct dependency | 
|  | // on tracing. When rustdoc is built by x.py using Cargo, rustc_driver's and rustc_log's | 
|  | // tracing dependency is distinct from this one and also needs to be initialized (using the | 
|  | // same RUSTDOC_LOG environment variable for both). Other build systems may use just a | 
|  | // single tracing crate throughout the rustc and rustdoc build. | 
|  | // | 
|  | // The reason initializing 2 tracings does not show double logging when `download-rustc = | 
|  | // false` and `debug_logging = true` is because all rustc logging goes only to its version | 
|  | // of tracing (the one in the sysroot) and all of rustdoc's logging only goes to its version | 
|  | // (the one in Cargo.toml). | 
|  | Err(rustc_log::Error::AlreadyInit(_)) => {} | 
|  | Err(error) => early_dcx.early_fatal(error.to_string()), | 
|  | } | 
|  |  | 
|  | let exit_code = rustc_driver::catch_with_exit_code(|| { | 
|  | let at_args = rustc_driver::args::raw_args(&early_dcx); | 
|  | main_args(&mut early_dcx, &at_args); | 
|  | }); | 
|  | process::exit(exit_code); | 
|  | } | 
|  |  | 
|  | fn init_logging(early_dcx: &EarlyDiagCtxt) { | 
|  | let color_logs = match env::var("RUSTDOC_LOG_COLOR").as_deref() { | 
|  | Ok("always") => true, | 
|  | Ok("never") => false, | 
|  | Ok("auto") | Err(VarError::NotPresent) => io::stdout().is_terminal(), | 
|  | Ok(value) => early_dcx.early_fatal(format!( | 
|  | "invalid log color value '{value}': expected one of always, never, or auto", | 
|  | )), | 
|  | Err(VarError::NotUnicode(value)) => early_dcx.early_fatal(format!( | 
|  | "invalid log color value '{}': expected one of always, never, or auto", | 
|  | value.to_string_lossy() | 
|  | )), | 
|  | }; | 
|  | let filter = tracing_subscriber::EnvFilter::from_env("RUSTDOC_LOG"); | 
|  | let layer = tracing_tree::HierarchicalLayer::default() | 
|  | .with_writer(io::stderr) | 
|  | .with_ansi(color_logs) | 
|  | .with_targets(true) | 
|  | .with_wraparound(10) | 
|  | .with_verbose_exit(true) | 
|  | .with_verbose_entry(true) | 
|  | .with_indent_amount(2); | 
|  | #[cfg(debug_assertions)] | 
|  | let layer = layer.with_thread_ids(true).with_thread_names(true); | 
|  |  | 
|  | use tracing_subscriber::layer::SubscriberExt; | 
|  | let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer); | 
|  | tracing::subscriber::set_global_default(subscriber).unwrap(); | 
|  | } | 
|  |  | 
|  | fn opts() -> Vec<RustcOptGroup> { | 
|  | use rustc_session::config::OptionKind::{Flag, FlagMulti, Multi, Opt}; | 
|  | use rustc_session::config::OptionStability::{Stable, Unstable}; | 
|  | use rustc_session::config::make_opt as opt; | 
|  |  | 
|  | vec![ | 
|  | opt(Stable, FlagMulti, "h", "help", "show this help message", ""), | 
|  | opt(Stable, FlagMulti, "V", "version", "print rustdoc's version", ""), | 
|  | opt(Stable, FlagMulti, "v", "verbose", "use verbose output", ""), | 
|  | opt(Stable, Opt, "w", "output-format", "the output type to write", "[html]"), | 
|  | opt( | 
|  | Stable, | 
|  | Opt, | 
|  | "", | 
|  | "output", | 
|  | "Which directory to place the output. This option is deprecated, use --out-dir instead.", | 
|  | "PATH", | 
|  | ), | 
|  | opt(Stable, Opt, "o", "out-dir", "which directory to place the output", "PATH"), | 
|  | opt(Stable, Opt, "", "crate-name", "specify the name of this crate", "NAME"), | 
|  | make_crate_type_option(), | 
|  | opt(Stable, Multi, "L", "library-path", "directory to add to crate search path", "DIR"), | 
|  | opt(Stable, Multi, "", "cfg", "pass a --cfg to rustc", ""), | 
|  | opt(Stable, Multi, "", "check-cfg", "pass a --check-cfg to rustc", ""), | 
|  | opt(Stable, Multi, "", "extern", "pass an --extern to rustc", "NAME[=PATH]"), | 
|  | opt( | 
|  | Unstable, | 
|  | Multi, | 
|  | "", | 
|  | "extern-html-root-url", | 
|  | "base URL to use for dependencies; for example, \ | 
|  | \"std=/doc\" links std::vec::Vec to /doc/std/vec/struct.Vec.html", | 
|  | "NAME=URL", | 
|  | ), | 
|  | opt( | 
|  | Unstable, | 
|  | FlagMulti, | 
|  | "", | 
|  | "extern-html-root-takes-precedence", | 
|  | "give precedence to `--extern-html-root-url`, not `html_root_url`", | 
|  | "", | 
|  | ), | 
|  | opt(Stable, Multi, "C", "codegen", "pass a codegen option to rustc", "OPT[=VALUE]"), | 
|  | opt(Stable, FlagMulti, "", "document-private-items", "document private items", ""), | 
|  | opt( | 
|  | Unstable, | 
|  | FlagMulti, | 
|  | "", | 
|  | "document-hidden-items", | 
|  | "document items that have doc(hidden)", | 
|  | "", | 
|  | ), | 
|  | opt(Stable, FlagMulti, "", "test", "run code examples as tests", ""), | 
|  | opt(Stable, Multi, "", "test-args", "arguments to pass to the test runner", "ARGS"), | 
|  | opt( | 
|  | Stable, | 
|  | Opt, | 
|  | "", | 
|  | "test-run-directory", | 
|  | "The working directory in which to run tests", | 
|  | "PATH", | 
|  | ), | 
|  | opt(Stable, Opt, "", "target", "target triple to document", "TRIPLE"), | 
|  | opt( | 
|  | Stable, | 
|  | Multi, | 
|  | "", | 
|  | "markdown-css", | 
|  | "CSS files to include via <link> in a rendered Markdown file", | 
|  | "FILES", | 
|  | ), | 
|  | opt( | 
|  | Stable, | 
|  | Multi, | 
|  | "", | 
|  | "html-in-header", | 
|  | "files to include inline in the <head> section of a rendered Markdown file \ | 
|  | or generated documentation", | 
|  | "FILES", | 
|  | ), | 
|  | opt( | 
|  | Stable, | 
|  | Multi, | 
|  | "", | 
|  | "html-before-content", | 
|  | "files to include inline between <body> and the content of a rendered \ | 
|  | Markdown file or generated documentation", | 
|  | "FILES", | 
|  | ), | 
|  | opt( | 
|  | Stable, | 
|  | Multi, | 
|  | "", | 
|  | "html-after-content", | 
|  | "files to include inline between the content and </body> of a rendered \ | 
|  | Markdown file or generated documentation", | 
|  | "FILES", | 
|  | ), | 
|  | opt( | 
|  | Unstable, | 
|  | Multi, | 
|  | "", | 
|  | "markdown-before-content", | 
|  | "files to include inline between <body> and the content of a rendered \ | 
|  | Markdown file or generated documentation", | 
|  | "FILES", | 
|  | ), | 
|  | opt( | 
|  | Unstable, | 
|  | Multi, | 
|  | "", | 
|  | "markdown-after-content", | 
|  | "files to include inline between the content and </body> of a rendered \ | 
|  | Markdown file or generated documentation", | 
|  | "FILES", | 
|  | ), | 
|  | opt(Stable, Opt, "", "markdown-playground-url", "URL to send code snippets to", "URL"), | 
|  | opt(Stable, FlagMulti, "", "markdown-no-toc", "don't include table of contents", ""), | 
|  | opt( | 
|  | Stable, | 
|  | Opt, | 
|  | "e", | 
|  | "extend-css", | 
|  | "To add some CSS rules with a given file to generate doc with your own theme. \ | 
|  | However, your theme might break if the rustdoc's generated HTML changes, so be careful!", | 
|  | "PATH", | 
|  | ), | 
|  | opt( | 
|  | Unstable, | 
|  | Multi, | 
|  | "Z", | 
|  | "", | 
|  | "unstable / perma-unstable options (only on nightly build)", | 
|  | "FLAG", | 
|  | ), | 
|  | opt(Stable, Opt, "", "sysroot", "Override the system root", "PATH"), | 
|  | opt( | 
|  | Unstable, | 
|  | Opt, | 
|  | "", | 
|  | "playground-url", | 
|  | "URL to send code snippets to, may be reset by --markdown-playground-url \ | 
|  | or `#![doc(html_playground_url=...)]`", | 
|  | "URL", | 
|  | ), | 
|  | opt( | 
|  | Unstable, | 
|  | FlagMulti, | 
|  | "", | 
|  | "display-doctest-warnings", | 
|  | "show warnings that originate in doctests", | 
|  | "", | 
|  | ), | 
|  | opt( | 
|  | Stable, | 
|  | Opt, | 
|  | "", | 
|  | "crate-version", | 
|  | "crate version to print into documentation", | 
|  | "VERSION", | 
|  | ), | 
|  | opt( | 
|  | Unstable, | 
|  | FlagMulti, | 
|  | "", | 
|  | "sort-modules-by-appearance", | 
|  | "sort modules by where they appear in the program, rather than alphabetically", | 
|  | "", | 
|  | ), | 
|  | opt( | 
|  | Stable, | 
|  | Opt, | 
|  | "", | 
|  | "default-theme", | 
|  | "Set the default theme. THEME should be the theme name, generally lowercase. \ | 
|  | If an unknown default theme is specified, the builtin default is used. \ | 
|  | The set of themes, and the rustdoc built-in default, are not stable.", | 
|  | "THEME", | 
|  | ), | 
|  | opt( | 
|  | Unstable, | 
|  | Multi, | 
|  | "", | 
|  | "default-setting", | 
|  | "Default value for a rustdoc setting (used when \"rustdoc-SETTING\" is absent \ | 
|  | from web browser Local Storage). If VALUE is not supplied, \"true\" is used. \ | 
|  | Supported SETTINGs and VALUEs are not documented and not stable.", | 
|  | "SETTING[=VALUE]", | 
|  | ), | 
|  | opt( | 
|  | Stable, | 
|  | Multi, | 
|  | "", | 
|  | "theme", | 
|  | "additional themes which will be added to the generated docs", | 
|  | "FILES", | 
|  | ), | 
|  | opt(Stable, Multi, "", "check-theme", "check if given theme is valid", "FILES"), | 
|  | opt( | 
|  | Unstable, | 
|  | Opt, | 
|  | "", | 
|  | "resource-suffix", | 
|  | "suffix to add to CSS and JavaScript files, \ | 
|  | e.g., \"search-index.js\" will become \"search-index-suffix.js\"", | 
|  | "PATH", | 
|  | ), | 
|  | opt( | 
|  | Stable, | 
|  | Opt, | 
|  | "", | 
|  | "edition", | 
|  | "edition to use when compiling rust code (default: 2015)", | 
|  | "EDITION", | 
|  | ), | 
|  | opt( | 
|  | Stable, | 
|  | Opt, | 
|  | "", | 
|  | "color", | 
|  | "Configure coloring of output: | 
|  | auto   = colorize, if output goes to a tty (default); | 
|  | always = always colorize output; | 
|  | never  = never colorize output", | 
|  | "auto|always|never", | 
|  | ), | 
|  | opt( | 
|  | Stable, | 
|  | Opt, | 
|  | "", | 
|  | "error-format", | 
|  | "How errors and other messages are produced", | 
|  | "human|json|short", | 
|  | ), | 
|  | opt( | 
|  | Stable, | 
|  | Opt, | 
|  | "", | 
|  | "diagnostic-width", | 
|  | "Provide width of the output for truncated error messages", | 
|  | "WIDTH", | 
|  | ), | 
|  | opt(Stable, Opt, "", "json", "Configure the structure of JSON diagnostics", "CONFIG"), | 
|  | opt(Stable, Multi, "A", "allow", "Set lint allowed", "LINT"), | 
|  | opt(Stable, Multi, "W", "warn", "Set lint warnings", "LINT"), | 
|  | opt(Stable, Multi, "", "force-warn", "Set lint force-warn", "LINT"), | 
|  | opt(Stable, Multi, "D", "deny", "Set lint denied", "LINT"), | 
|  | opt(Stable, Multi, "F", "forbid", "Set lint forbidden", "LINT"), | 
|  | opt( | 
|  | Stable, | 
|  | Multi, | 
|  | "", | 
|  | "cap-lints", | 
|  | "Set the most restrictive lint level. \ | 
|  | More restrictive lints are capped at this level. \ | 
|  | By default, it is at `forbid` level.", | 
|  | "LEVEL", | 
|  | ), | 
|  | opt(Unstable, Opt, "", "index-page", "Markdown file to be used as index page", "PATH"), | 
|  | opt( | 
|  | Unstable, | 
|  | FlagMulti, | 
|  | "", | 
|  | "enable-index-page", | 
|  | "To enable generation of the index page", | 
|  | "", | 
|  | ), | 
|  | opt( | 
|  | Unstable, | 
|  | Opt, | 
|  | "", | 
|  | "static-root-path", | 
|  | "Path string to force loading static files from in output pages. \ | 
|  | If not set, uses combinations of '../' to reach the documentation root.", | 
|  | "PATH", | 
|  | ), | 
|  | opt( | 
|  | Unstable, | 
|  | Opt, | 
|  | "", | 
|  | "persist-doctests", | 
|  | "Directory to persist doctest executables into", | 
|  | "PATH", | 
|  | ), | 
|  | opt( | 
|  | Unstable, | 
|  | FlagMulti, | 
|  | "", | 
|  | "show-coverage", | 
|  | "calculate percentage of public items with documentation", | 
|  | "", | 
|  | ), | 
|  | opt( | 
|  | Stable, | 
|  | Opt, | 
|  | "", | 
|  | "test-runtool", | 
|  | "", | 
|  | "The tool to run tests with when building for a different target than host", | 
|  | ), | 
|  | opt( | 
|  | Stable, | 
|  | Multi, | 
|  | "", | 
|  | "test-runtool-arg", | 
|  | "", | 
|  | "One argument (of possibly many) to pass to the runtool", | 
|  | ), | 
|  | opt( | 
|  | Unstable, | 
|  | Opt, | 
|  | "", | 
|  | "test-builder", | 
|  | "The rustc-like binary to use as the test builder", | 
|  | "PATH", | 
|  | ), | 
|  | opt( | 
|  | Unstable, | 
|  | Multi, | 
|  | "", | 
|  | "test-builder-wrapper", | 
|  | "Wrapper program to pass test-builder and arguments", | 
|  | "PATH", | 
|  | ), | 
|  | opt(Unstable, FlagMulti, "", "check", "Run rustdoc checks", ""), | 
|  | opt( | 
|  | Unstable, | 
|  | FlagMulti, | 
|  | "", | 
|  | "generate-redirect-map", | 
|  | "Generate JSON file at the top level instead of generating HTML redirection files", | 
|  | "", | 
|  | ), | 
|  | opt( | 
|  | Unstable, | 
|  | Multi, | 
|  | "", | 
|  | "emit", | 
|  | "Comma separated list of types of output for rustdoc to emit", | 
|  | "[unversioned-shared-resources,toolchain-shared-resources,invocation-specific,dep-info]", | 
|  | ), | 
|  | opt(Unstable, FlagMulti, "", "no-run", "Compile doctests without running them", ""), | 
|  | opt( | 
|  | Unstable, | 
|  | Multi, | 
|  | "", | 
|  | "remap-path-prefix", | 
|  | "Remap source names in compiler messages", | 
|  | "FROM=TO", | 
|  | ), | 
|  | opt( | 
|  | Unstable, | 
|  | FlagMulti, | 
|  | "", | 
|  | "show-type-layout", | 
|  | "Include the memory layout of types in the docs", | 
|  | "", | 
|  | ), | 
|  | opt(Unstable, Flag, "", "nocapture", "Don't capture stdout and stderr of tests", ""), | 
|  | opt( | 
|  | Unstable, | 
|  | Flag, | 
|  | "", | 
|  | "generate-link-to-definition", | 
|  | "Make the identifiers in the HTML source code pages navigable", | 
|  | "", | 
|  | ), | 
|  | opt( | 
|  | Unstable, | 
|  | Opt, | 
|  | "", | 
|  | "scrape-examples-output-path", | 
|  | "", | 
|  | "collect function call information and output at the given path", | 
|  | ), | 
|  | opt( | 
|  | Unstable, | 
|  | Multi, | 
|  | "", | 
|  | "scrape-examples-target-crate", | 
|  | "", | 
|  | "collect function call information for functions from the target crate", | 
|  | ), | 
|  | opt(Unstable, Flag, "", "scrape-tests", "Include test code when scraping examples", ""), | 
|  | opt( | 
|  | Unstable, | 
|  | Multi, | 
|  | "", | 
|  | "with-examples", | 
|  | "", | 
|  | "path to function call information (for displaying examples in the documentation)", | 
|  | ), | 
|  | opt( | 
|  | Unstable, | 
|  | Opt, | 
|  | "", | 
|  | "merge", | 
|  | "Controls how rustdoc handles files from previously documented crates in the doc root\n\ | 
|  | none = Do not write cross-crate information to the --out-dir\n\ | 
|  | shared = Append current crate's info to files found in the --out-dir\n\ | 
|  | finalize = Write current crate's info and --include-parts-dir info to the --out-dir, overwriting conflicting files", | 
|  | "none|shared|finalize", | 
|  | ), | 
|  | opt( | 
|  | Unstable, | 
|  | Opt, | 
|  | "", | 
|  | "parts-out-dir", | 
|  | "Writes trait implementations and other info for the current crate to provided path. Only use with --merge=none", | 
|  | "path/to/doc.parts/<crate-name>", | 
|  | ), | 
|  | opt( | 
|  | Unstable, | 
|  | Multi, | 
|  | "", | 
|  | "include-parts-dir", | 
|  | "Includes trait implementations and other crate info from provided path. Only use with --merge=finalize", | 
|  | "path/to/doc.parts/<crate-name>", | 
|  | ), | 
|  | opt(Unstable, Flag, "", "html-no-source", "Disable HTML source code pages generation", ""), | 
|  | opt( | 
|  | Unstable, | 
|  | Multi, | 
|  | "", | 
|  | "doctest-build-arg", | 
|  | "One argument (of possibly many) to be used when compiling doctests", | 
|  | "ARG", | 
|  | ), | 
|  | opt( | 
|  | Unstable, | 
|  | FlagMulti, | 
|  | "", | 
|  | "disable-minification", | 
|  | "disable the minification of CSS/JS files (perma-unstable, do not use with cached files)", | 
|  | "", | 
|  | ), | 
|  | // deprecated / removed options | 
|  | opt( | 
|  | Stable, | 
|  | Multi, | 
|  | "", | 
|  | "plugin-path", | 
|  | "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information", | 
|  | "DIR", | 
|  | ), | 
|  | opt( | 
|  | Stable, | 
|  | Multi, | 
|  | "", | 
|  | "passes", | 
|  | "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information", | 
|  | "PASSES", | 
|  | ), | 
|  | opt( | 
|  | Stable, | 
|  | Multi, | 
|  | "", | 
|  | "plugins", | 
|  | "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information", | 
|  | "PLUGINS", | 
|  | ), | 
|  | opt( | 
|  | Stable, | 
|  | FlagMulti, | 
|  | "", | 
|  | "no-defaults", | 
|  | "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information", | 
|  | "", | 
|  | ), | 
|  | opt( | 
|  | Stable, | 
|  | Opt, | 
|  | "r", | 
|  | "input-format", | 
|  | "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information", | 
|  | "[rust]", | 
|  | ), | 
|  | ] | 
|  | } | 
|  |  | 
|  | fn usage(argv0: &str) { | 
|  | let mut options = getopts::Options::new(); | 
|  | for option in opts() { | 
|  | option.apply(&mut options); | 
|  | } | 
|  | println!("{}", options.usage(&format!("{argv0} [options] <input>"))); | 
|  | println!("    @path               Read newline separated options from `path`\n"); | 
|  | println!( | 
|  | "More information available at {DOC_RUST_LANG_ORG_VERSION}/rustdoc/what-is-rustdoc.html", | 
|  | ); | 
|  | } | 
|  |  | 
|  | pub(crate) fn wrap_return(dcx: DiagCtxtHandle<'_>, res: Result<(), String>) { | 
|  | match res { | 
|  | Ok(()) => dcx.abort_if_errors(), | 
|  | Err(err) => dcx.fatal(err), | 
|  | } | 
|  | } | 
|  |  | 
|  | fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>( | 
|  | krate: clean::Crate, | 
|  | renderopts: config::RenderOptions, | 
|  | cache: formats::cache::Cache, | 
|  | tcx: TyCtxt<'tcx>, | 
|  | ) { | 
|  | match formats::run_format::<T>(krate, renderopts, cache, tcx) { | 
|  | Ok(_) => tcx.dcx().abort_if_errors(), | 
|  | Err(e) => { | 
|  | let mut msg = | 
|  | tcx.dcx().struct_fatal(format!("couldn't generate documentation: {}", e.error)); | 
|  | let file = e.file.display().to_string(); | 
|  | if !file.is_empty() { | 
|  | msg.note(format!("failed to create or modify \"{file}\"")); | 
|  | } | 
|  | msg.emit(); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Renders and writes cross-crate info files, like the search index. This function exists so that | 
|  | /// we can run rustdoc without a crate root in the `--merge=finalize` mode. Cross-crate info files | 
|  | /// discovered via `--include-parts-dir` are combined and written to the doc root. | 
|  | fn run_merge_finalize(opt: config::RenderOptions) -> Result<(), error::Error> { | 
|  | assert!( | 
|  | opt.should_merge.write_rendered_cci, | 
|  | "config.rs only allows us to return InputMode::NoInputMergeFinalize if --merge=finalize" | 
|  | ); | 
|  | assert!( | 
|  | !opt.should_merge.read_rendered_cci, | 
|  | "config.rs only allows us to return InputMode::NoInputMergeFinalize if --merge=finalize" | 
|  | ); | 
|  | let crates = html::render::CrateInfo::read_many(&opt.include_parts_dir)?; | 
|  | let include_sources = !opt.html_no_source; | 
|  | html::render::write_not_crate_specific( | 
|  | &crates, | 
|  | &opt.output, | 
|  | &opt, | 
|  | &opt.themes, | 
|  | opt.extension_css.as_deref(), | 
|  | &opt.resource_suffix, | 
|  | include_sources, | 
|  | )?; | 
|  | Ok(()) | 
|  | } | 
|  |  | 
|  | fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { | 
|  | // Throw away the first argument, the name of the binary. | 
|  | // In case of at_args being empty, as might be the case by | 
|  | // passing empty argument array to execve under some platforms, | 
|  | // just use an empty slice. | 
|  | // | 
|  | // This situation was possible before due to arg_expand_all being | 
|  | // called before removing the argument, enabling a crash by calling | 
|  | // the compiler with @empty_file as argv[0] and no more arguments. | 
|  | let at_args = at_args.get(1..).unwrap_or_default(); | 
|  |  | 
|  | let args = rustc_driver::args::arg_expand_all(early_dcx, at_args); | 
|  |  | 
|  | let mut options = getopts::Options::new(); | 
|  | for option in opts() { | 
|  | option.apply(&mut options); | 
|  | } | 
|  | let matches = match options.parse(&args) { | 
|  | Ok(m) => m, | 
|  | Err(err) => { | 
|  | early_dcx.early_fatal(err.to_string()); | 
|  | } | 
|  | }; | 
|  |  | 
|  | // Note that we discard any distinction between different non-zero exit | 
|  | // codes from `from_matches` here. | 
|  | let (input, options, render_options) = | 
|  | match config::Options::from_matches(early_dcx, &matches, args) { | 
|  | Some(opts) => opts, | 
|  | None => return, | 
|  | }; | 
|  |  | 
|  | let dcx = | 
|  | core::new_dcx(options.error_format, None, options.diagnostic_width, &options.unstable_opts); | 
|  | let dcx = dcx.handle(); | 
|  |  | 
|  | let input = match input { | 
|  | config::InputMode::HasFile(input) => input, | 
|  | config::InputMode::NoInputMergeFinalize => { | 
|  | return wrap_return( | 
|  | dcx, | 
|  | run_merge_finalize(render_options) | 
|  | .map_err(|e| format!("could not write merged cross-crate info: {e}")), | 
|  | ); | 
|  | } | 
|  | }; | 
|  |  | 
|  | let output_format = options.output_format; | 
|  |  | 
|  | match ( | 
|  | options.should_test || output_format == config::OutputFormat::Doctest, | 
|  | config::markdown_input(&input), | 
|  | ) { | 
|  | (true, Some(_)) => return wrap_return(dcx, doctest::test_markdown(&input, options)), | 
|  | (true, None) => return doctest::run(dcx, input, options), | 
|  | (false, Some(md_input)) => { | 
|  | let md_input = md_input.to_owned(); | 
|  | let edition = options.edition; | 
|  | let config = core::create_config(input, options, &render_options); | 
|  |  | 
|  | // `markdown::render` can invoke `doctest::make_test`, which | 
|  | // requires session globals and a thread pool, so we use | 
|  | // `run_compiler`. | 
|  | return wrap_return( | 
|  | dcx, | 
|  | interface::run_compiler(config, |_compiler| { | 
|  | markdown::render_and_write(&md_input, render_options, edition) | 
|  | }), | 
|  | ); | 
|  | } | 
|  | (false, None) => {} | 
|  | } | 
|  |  | 
|  | // need to move these items separately because we lose them by the time the closure is called, | 
|  | // but we can't create the dcx ahead of time because it's not Send | 
|  | let show_coverage = options.show_coverage; | 
|  | let run_check = options.run_check; | 
|  |  | 
|  | // First, parse the crate and extract all relevant information. | 
|  | info!("starting to run rustc"); | 
|  |  | 
|  | // Interpret the input file as a rust source file, passing it through the | 
|  | // compiler all the way through the analysis passes. The rustdoc output is | 
|  | // then generated from the cleaned AST of the crate. This runs all the | 
|  | // plug/cleaning passes. | 
|  | let crate_version = options.crate_version.clone(); | 
|  |  | 
|  | let scrape_examples_options = options.scrape_examples_options.clone(); | 
|  | let bin_crate = options.bin_crate; | 
|  |  | 
|  | let config = core::create_config(input, options, &render_options); | 
|  |  | 
|  | let registered_lints = config.register_lints.is_some(); | 
|  |  | 
|  | interface::run_compiler(config, |compiler| { | 
|  | let sess = &compiler.sess; | 
|  |  | 
|  | if sess.opts.describe_lints { | 
|  | rustc_driver::describe_lints(sess, registered_lints); | 
|  | return; | 
|  | } | 
|  |  | 
|  | let krate = rustc_interface::passes::parse(sess); | 
|  | rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| { | 
|  | if sess.dcx().has_errors().is_some() { | 
|  | sess.dcx().fatal("Compilation failed, aborting rustdoc"); | 
|  | } | 
|  |  | 
|  | let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || { | 
|  | core::run_global_ctxt(tcx, show_coverage, render_options, output_format) | 
|  | }); | 
|  | info!("finished with rustc"); | 
|  |  | 
|  | if let Some(options) = scrape_examples_options { | 
|  | return scrape_examples::run(krate, render_opts, cache, tcx, options, bin_crate); | 
|  | } | 
|  |  | 
|  | cache.crate_version = crate_version; | 
|  |  | 
|  | if show_coverage { | 
|  | // if we ran coverage, bail early, we don't need to also generate docs at this point | 
|  | // (also we didn't load in any of the useful passes) | 
|  | return; | 
|  | } | 
|  |  | 
|  | if render_opts.dep_info().is_some() { | 
|  | rustc_interface::passes::write_dep_info(tcx); | 
|  | } | 
|  |  | 
|  | if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir { | 
|  | dump_feature_usage_metrics(tcx, metrics_dir); | 
|  | } | 
|  |  | 
|  | if run_check { | 
|  | // Since we're in "check" mode, no need to generate anything beyond this point. | 
|  | return; | 
|  | } | 
|  |  | 
|  | info!("going to format"); | 
|  | match output_format { | 
|  | config::OutputFormat::Html => sess.time("render_html", || { | 
|  | run_renderer::<html::render::Context<'_>>(krate, render_opts, cache, tcx) | 
|  | }), | 
|  | config::OutputFormat::Json => sess.time("render_json", || { | 
|  | run_renderer::<json::JsonRenderer<'_>>(krate, render_opts, cache, tcx) | 
|  | }), | 
|  | // Already handled above with doctest runners. | 
|  | config::OutputFormat::Doctest => unreachable!(), | 
|  | } | 
|  | }) | 
|  | }) | 
|  | } | 
|  |  | 
|  | fn dump_feature_usage_metrics(tcxt: TyCtxt<'_>, metrics_dir: &Path) { | 
|  | let hash = tcxt.crate_hash(LOCAL_CRATE); | 
|  | let crate_name = tcxt.crate_name(LOCAL_CRATE); | 
|  | let metrics_file_name = format!("unstable_feature_usage_metrics-{crate_name}-{hash}.json"); | 
|  | let metrics_path = metrics_dir.join(metrics_file_name); | 
|  | if let Err(error) = tcxt.features().dump_feature_usage_metrics(metrics_path) { | 
|  | // FIXME(yaahc): once metrics can be enabled by default we will want "failure to emit | 
|  | // default metrics" to only produce a warning when metrics are enabled by default and emit | 
|  | // an error only when the user manually enables metrics | 
|  | tcxt.dcx().err(format!("cannot emit feature usage metrics: {error}")); | 
|  | } | 
|  | } |