Auto merge of #92844 - matthiaskrgr:rollup-z5wb6yi, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #90001 (Make rlib metadata strip works with MIPSr6 architecture) - #91687 (rustdoc: do not emit tuple variant fields if none are documented) - #91938 (Add `std::error::Report` type) - #92006 (Welcome opaque types into the fold) - #92142 ([code coverage] Fix missing dead code in modules that are never called) - #92277 (rustc_metadata: Stop passing `CrateMetadataRef` by reference (step 1)) - #92334 (rustdoc: Preserve rendering of macro_rules matchers when possible) - #92807 (Update cargo) - #92832 (Update RELEASES for 1.58.) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
f312a5e610
31 changed files with 1515 additions and 357 deletions
82
Cargo.lock
82
Cargo.lock
|
@ -24,6 +24,17 @@ dependencies = [
|
|||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98"
|
||||
dependencies = [
|
||||
"getrandom 0.2.0",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.18"
|
||||
|
@ -324,7 +335,7 @@ dependencies = [
|
|||
"cargo-test-macro",
|
||||
"cargo-test-support",
|
||||
"cargo-util",
|
||||
"clap",
|
||||
"clap 3.0.6",
|
||||
"crates-io",
|
||||
"crossbeam-utils 0.8.3",
|
||||
"curl",
|
||||
|
@ -604,13 +615,28 @@ dependencies = [
|
|||
"ansi_term 0.12.1",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"strsim",
|
||||
"textwrap",
|
||||
"strsim 0.8.0",
|
||||
"textwrap 0.11.0",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
"yaml-rust 0.3.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1957aa4a5fb388f0a0a73ce7556c5b42025b874e5cdc2c670775e346e97adec0"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
"os_str_bytes",
|
||||
"strsim 0.10.0",
|
||||
"termcolor",
|
||||
"textwrap 0.14.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clippy"
|
||||
version = "0.1.59"
|
||||
|
@ -641,7 +667,7 @@ version = "0.0.1"
|
|||
dependencies = [
|
||||
"bytecount",
|
||||
"cargo_metadata 0.14.0",
|
||||
"clap",
|
||||
"clap 2.34.0",
|
||||
"indoc",
|
||||
"itertools 0.10.1",
|
||||
"opener",
|
||||
|
@ -1579,6 +1605,7 @@ version = "0.11.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "362385356d610bd1e5a408ddf8d022041774b683f345a1d2cfcb4f60f8ae2db5"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
|
@ -1746,7 +1773,7 @@ name = "installer"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"clap 2.34.0",
|
||||
"flate2",
|
||||
"lazy_static",
|
||||
"num_cpus",
|
||||
|
@ -2191,7 +2218,7 @@ dependencies = [
|
|||
"ammonia",
|
||||
"anyhow",
|
||||
"chrono",
|
||||
"clap",
|
||||
"clap 2.34.0",
|
||||
"elasticlunr-rs",
|
||||
"env_logger 0.7.1",
|
||||
"handlebars",
|
||||
|
@ -2396,8 +2423,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"crc32fast",
|
||||
"indexmap",
|
||||
"memchr",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
|
@ -2415,6 +2440,18 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.28.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ce8b38d41f9f3618fc23f908faae61510f8d8ce2d99cbe910641e8f1971f084"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"hashbrown",
|
||||
"indexmap",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "odht"
|
||||
version = "0.3.1"
|
||||
|
@ -2512,6 +2549,15 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "output_vt100"
|
||||
version = "0.1.2"
|
||||
|
@ -2916,7 +2962,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "7fec2e85e7a30f8fd31b7cf288ad363b5e51fd2cb6f53b416b0cfaabd84e1ccb"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"clap",
|
||||
"clap 2.34.0",
|
||||
"derive_more",
|
||||
"env_logger 0.7.1",
|
||||
"humantime 2.0.1",
|
||||
|
@ -3271,7 +3317,7 @@ dependencies = [
|
|||
name = "rustbook"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"clap 2.34.0",
|
||||
"env_logger 0.7.1",
|
||||
"mdbook",
|
||||
]
|
||||
|
@ -3801,7 +3847,7 @@ dependencies = [
|
|||
"itertools 0.9.0",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"object 0.26.2",
|
||||
"object 0.28.1",
|
||||
"pathdiff",
|
||||
"regex",
|
||||
"rustc_apfloat",
|
||||
|
@ -5133,13 +5179,19 @@ version = "0.8.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "structopt"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"clap 2.34.0",
|
||||
"lazy_static",
|
||||
"structopt-derive",
|
||||
]
|
||||
|
@ -5310,6 +5362,12 @@ dependencies = [
|
|||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.30"
|
||||
|
|
10
RELEASES.md
10
RELEASES.md
|
@ -43,7 +43,6 @@ Stabilized APIs
|
|||
- [`Option::unwrap_unchecked`]
|
||||
- [`Result::unwrap_unchecked`]
|
||||
- [`Result::unwrap_err_unchecked`]
|
||||
- [`NonZero{unsigned}::is_power_of_two`]
|
||||
- [`File::options`]
|
||||
|
||||
These APIs are now usable in const contexts:
|
||||
|
@ -56,10 +55,6 @@ These APIs are now usable in const contexts:
|
|||
- [`Duration::checked_mul`]
|
||||
- [`Duration::saturating_mul`]
|
||||
- [`Duration::checked_div`]
|
||||
- [`MaybeUninit::as_ptr`]
|
||||
- [`MaybeUninit::as_mut_ptr`]
|
||||
- [`MaybeUninit::assume_init`]
|
||||
- [`MaybeUninit::assume_init_ref`]
|
||||
|
||||
Cargo
|
||||
-----
|
||||
|
@ -141,7 +136,6 @@ and related tools.
|
|||
[`Option::unwrap_unchecked`]: https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.unwrap_unchecked
|
||||
[`Result::unwrap_unchecked`]: https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.unwrap_unchecked
|
||||
[`Result::unwrap_err_unchecked`]: https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.unwrap_err_unchecked
|
||||
[`NonZero{unsigned}::is_power_of_two`]: https://doc.rust-lang.org/stable/std/num/struct.NonZeroU8.html#method.is_power_of_two
|
||||
[`File::options`]: https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.options
|
||||
[`unix::process::ExitStatusExt::core_dumped`]: https://doc.rust-lang.org/stable/std/os/unix/process/trait.ExitStatusExt.html#tymethod.core_dumped
|
||||
[`unix::process::ExitStatusExt::stopped_signal`]: https://doc.rust-lang.org/stable/std/os/unix/process/trait.ExitStatusExt.html#tymethod.stopped_signal
|
||||
|
@ -165,10 +159,6 @@ and related tools.
|
|||
[`Duration::div_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.div_f32
|
||||
[`Duration::div_duration_f64`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.div_duration_f64
|
||||
[`Duration::div_duration_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.div_duration_f32
|
||||
[`MaybeUninit::as_ptr`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.as_ptr
|
||||
[`MaybeUninit::as_mut_ptr`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.as_mut_ptr
|
||||
[`MaybeUninit::assume_init`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.assume_init
|
||||
[`MaybeUninit::assume_init_ref`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.assume_init_ref
|
||||
|
||||
Version 1.57.0 (2021-12-02)
|
||||
==========================
|
||||
|
|
|
@ -5,12 +5,13 @@ use crate::llvm;
|
|||
use llvm::coverageinfo::CounterMappingRegion;
|
||||
use rustc_codegen_ssa::coverageinfo::map::{Counter, CounterExpression};
|
||||
use rustc_codegen_ssa::traits::{ConstMethods, CoverageInfoMethods};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
|
||||
use rustc_hir::def_id::{DefId, DefIdSet};
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefIdSet;
|
||||
use rustc_llvm::RustString;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::mir::coverage::CodeRegion;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::Symbol;
|
||||
|
||||
use std::ffi::CString;
|
||||
|
||||
|
@ -46,7 +47,7 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
|
|||
// functions exist. Generate synthetic functions with a (required) single counter, and add the
|
||||
// MIR `Coverage` code regions to the `function_coverage_map`, before calling
|
||||
// `ctx.take_function_coverage_map()`.
|
||||
if !tcx.sess.instrument_coverage_except_unused_functions() {
|
||||
if cx.codegen_unit.is_code_coverage_dead_code_cgu() {
|
||||
add_unused_functions(cx);
|
||||
}
|
||||
|
||||
|
@ -271,26 +272,35 @@ fn save_function_record(
|
|||
/// `DefId`s (`tcx` query `mir_keys`) minus the codegenned `DefId`s (`tcx` query
|
||||
/// `codegened_and_inlined_items`).
|
||||
///
|
||||
/// *HOWEVER* the codegenned `DefId`s are partitioned across multiple `CodegenUnit`s (CGUs), and
|
||||
/// this function is processing a `function_coverage_map` for the functions (`Instance`/`DefId`)
|
||||
/// allocated to only one of those CGUs. We must NOT inject any unused functions's `CodeRegion`s
|
||||
/// more than once, so we have to pick a CGUs `function_coverage_map` into which the unused
|
||||
/// function will be inserted.
|
||||
/// These unused functions are then codegen'd in one of the CGUs which is marked as the
|
||||
/// "code coverage dead code cgu" during the partitioning process. This prevents us from generating
|
||||
/// code regions for the same function more than once which can lead to linker errors regarding
|
||||
/// duplicate symbols.
|
||||
fn add_unused_functions<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
|
||||
let tcx = cx.tcx;
|
||||
assert!(cx.codegen_unit.is_code_coverage_dead_code_cgu());
|
||||
|
||||
// FIXME(#79622): Can this solution be simplified and/or improved? Are there other sources
|
||||
// of compiler state data that might help (or better sources that could be exposed, but
|
||||
// aren't yet)?
|
||||
let tcx = cx.tcx;
|
||||
|
||||
let ignore_unused_generics = tcx.sess.instrument_coverage_except_unused_generics();
|
||||
|
||||
let all_def_ids: DefIdSet = tcx
|
||||
let eligible_def_ids: DefIdSet = tcx
|
||||
.mir_keys(())
|
||||
.iter()
|
||||
.filter_map(|local_def_id| {
|
||||
let def_id = local_def_id.to_def_id();
|
||||
if ignore_unused_generics && tcx.generics_of(def_id).requires_monomorphization(tcx) {
|
||||
let kind = tcx.def_kind(def_id);
|
||||
// `mir_keys` will give us `DefId`s for all kinds of things, not
|
||||
// just "functions", like consts, statics, etc. Filter those out.
|
||||
// If `ignore_unused_generics` was specified, filter out any
|
||||
// generic functions from consideration as well.
|
||||
if !matches!(
|
||||
kind,
|
||||
DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Generator
|
||||
) {
|
||||
return None;
|
||||
} else if ignore_unused_generics
|
||||
&& tcx.generics_of(def_id).requires_monomorphization(tcx)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
Some(local_def_id.to_def_id())
|
||||
|
@ -299,79 +309,17 @@ fn add_unused_functions<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
|
|||
|
||||
let codegenned_def_ids = tcx.codegened_and_inlined_items(());
|
||||
|
||||
let mut unused_def_ids_by_file: FxHashMap<Symbol, Vec<DefId>> = FxHashMap::default();
|
||||
for &non_codegenned_def_id in all_def_ids.difference(codegenned_def_ids) {
|
||||
// Make sure the non-codegenned (unused) function has at least one MIR
|
||||
// `Coverage` statement with a code region, and return its file name.
|
||||
if let Some(non_codegenned_file_name) = tcx.covered_file_name(non_codegenned_def_id) {
|
||||
let def_ids =
|
||||
unused_def_ids_by_file.entry(*non_codegenned_file_name).or_insert_with(Vec::new);
|
||||
def_ids.push(non_codegenned_def_id);
|
||||
for &non_codegenned_def_id in eligible_def_ids.difference(codegenned_def_ids) {
|
||||
let codegen_fn_attrs = tcx.codegen_fn_attrs(non_codegenned_def_id);
|
||||
|
||||
// If a function is marked `#[no_coverage]`, then skip generating a
|
||||
// dead code stub for it.
|
||||
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_COVERAGE) {
|
||||
debug!("skipping unused fn marked #[no_coverage]: {:?}", non_codegenned_def_id);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if unused_def_ids_by_file.is_empty() {
|
||||
// There are no unused functions with file names to add (in any CGU)
|
||||
return;
|
||||
}
|
||||
|
||||
// Each `CodegenUnit` (CGU) has its own function_coverage_map, and generates a specific binary
|
||||
// with its own coverage map.
|
||||
//
|
||||
// Each covered function `Instance` can be included in only one coverage map, produced from a
|
||||
// specific function_coverage_map, from a specific CGU.
|
||||
//
|
||||
// Since unused functions did not generate code, they are not associated with any CGU yet.
|
||||
//
|
||||
// To avoid injecting the unused functions in multiple coverage maps (for multiple CGUs)
|
||||
// determine which function_coverage_map has the responsibility for publishing unreachable
|
||||
// coverage, based on file name: For each unused function, find the CGU that generates the
|
||||
// first function (based on sorted `DefId`) from the same file.
|
||||
//
|
||||
// Add a new `FunctionCoverage` to the `function_coverage_map`, with unreachable code regions
|
||||
// for each region in it's MIR.
|
||||
|
||||
// Convert the `HashSet` of `codegenned_def_ids` to a sortable vector, and sort them.
|
||||
let mut sorted_codegenned_def_ids: Vec<DefId> = codegenned_def_ids.iter().copied().collect();
|
||||
sorted_codegenned_def_ids.sort_unstable();
|
||||
|
||||
let mut first_covered_def_id_by_file: FxHashMap<Symbol, DefId> = FxHashMap::default();
|
||||
for &def_id in sorted_codegenned_def_ids.iter() {
|
||||
if let Some(covered_file_name) = tcx.covered_file_name(def_id) {
|
||||
// Only add files known to have unused functions
|
||||
if unused_def_ids_by_file.contains_key(covered_file_name) {
|
||||
first_covered_def_id_by_file.entry(*covered_file_name).or_insert(def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the set of def_ids with coverage regions, known by *this* CoverageContext.
|
||||
let cgu_covered_def_ids: DefIdSet = match cx.coverage_context() {
|
||||
Some(ctx) => ctx
|
||||
.function_coverage_map
|
||||
.borrow()
|
||||
.keys()
|
||||
.map(|&instance| instance.def.def_id())
|
||||
.collect(),
|
||||
None => return,
|
||||
};
|
||||
|
||||
let cgu_covered_files: FxHashSet<Symbol> = first_covered_def_id_by_file
|
||||
.iter()
|
||||
.filter_map(
|
||||
|(&file_name, def_id)| {
|
||||
if cgu_covered_def_ids.contains(def_id) { Some(file_name) } else { None }
|
||||
},
|
||||
)
|
||||
.collect();
|
||||
|
||||
// For each file for which this CGU is responsible for adding unused function coverage,
|
||||
// get the `def_id`s for each unused function (if any), define a synthetic function with a
|
||||
// single LLVM coverage counter, and add the function's coverage `CodeRegion`s. to the
|
||||
// function_coverage_map.
|
||||
for covered_file_name in cgu_covered_files {
|
||||
for def_id in unused_def_ids_by_file.remove(&covered_file_name).into_iter().flatten() {
|
||||
cx.define_unused_fn(def_id);
|
||||
}
|
||||
debug!("generating unused fn: {:?}", non_codegenned_def_id);
|
||||
cx.define_unused_fn(non_codegenned_def_id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,6 @@ rustc_target = { path = "../rustc_target" }
|
|||
rustc_session = { path = "../rustc_session" }
|
||||
|
||||
[dependencies.object]
|
||||
version = "0.26.2"
|
||||
version = "0.28.0"
|
||||
default-features = false
|
||||
features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"]
|
||||
|
|
|
@ -95,7 +95,7 @@ fn search_for_metadata<'a>(
|
|||
.map_err(|e| format!("failed to read {} section in '{}': {}", section, path.display(), e))
|
||||
}
|
||||
|
||||
fn create_object_file(sess: &Session) -> Option<write::Object> {
|
||||
fn create_object_file(sess: &Session) -> Option<write::Object<'static>> {
|
||||
let endianness = match sess.target.options.endian {
|
||||
Endian::Little => Endianness::Little,
|
||||
Endian::Big => Endianness::Big,
|
||||
|
@ -135,12 +135,24 @@ fn create_object_file(sess: &Session) -> Option<write::Object> {
|
|||
Architecture::Mips => {
|
||||
// copied from `mipsel-linux-gnu-gcc foo.c -c` and
|
||||
// inspecting the resulting `e_flags` field.
|
||||
let e_flags = elf::EF_MIPS_ARCH_32R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC;
|
||||
let e_flags = elf::EF_MIPS_CPIC
|
||||
| elf::EF_MIPS_PIC
|
||||
| if sess.target.options.cpu.contains("r6") {
|
||||
elf::EF_MIPS_ARCH_32R6 | elf::EF_MIPS_NAN2008
|
||||
} else {
|
||||
elf::EF_MIPS_ARCH_32R2
|
||||
};
|
||||
file.flags = FileFlags::Elf { e_flags };
|
||||
}
|
||||
Architecture::Mips64 => {
|
||||
// copied from `mips64el-linux-gnuabi64-gcc foo.c -c`
|
||||
let e_flags = elf::EF_MIPS_ARCH_64R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC;
|
||||
let e_flags = elf::EF_MIPS_CPIC
|
||||
| elf::EF_MIPS_PIC
|
||||
| if sess.target.options.cpu.contains("r6") {
|
||||
elf::EF_MIPS_ARCH_64R6 | elf::EF_MIPS_NAN2008
|
||||
} else {
|
||||
elf::EF_MIPS_ARCH_64R2
|
||||
};
|
||||
file.flags = FileFlags::Elf { e_flags };
|
||||
}
|
||||
Architecture::Riscv64 if sess.target.options.features.contains("+d") => {
|
||||
|
|
|
@ -551,6 +551,22 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
|||
let predicate = predicate.subst(tcx, substs);
|
||||
debug!(?predicate);
|
||||
|
||||
let predicate = predicate.fold_with(&mut BottomUpFolder {
|
||||
tcx,
|
||||
ty_op: |ty| match *ty.kind() {
|
||||
// Replace all other mentions of the same opaque type with the hidden type,
|
||||
// as the bounds must hold on the hidden type after all.
|
||||
ty::Opaque(def_id2, substs2) if def_id == def_id2 && substs == substs2 => {
|
||||
ty_var
|
||||
}
|
||||
// Instantiate nested instances of `impl Trait`.
|
||||
ty::Opaque(..) => self.instantiate_opaque_types_in_map(ty),
|
||||
_ => ty,
|
||||
},
|
||||
lt_op: |lt| lt,
|
||||
ct_op: |ct| ct,
|
||||
});
|
||||
|
||||
// We can't normalize associated types from `rustc_infer`, but we can eagerly register inference variables for them.
|
||||
let predicate = predicate.fold_with(&mut BottomUpFolder {
|
||||
tcx,
|
||||
|
@ -575,10 +591,6 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
|||
return tcx.ty_error();
|
||||
}
|
||||
}
|
||||
// Change the predicate to refer to the type variable,
|
||||
// which will be the concrete type instead of the opaque type.
|
||||
// This also instantiates nested instances of `impl Trait`.
|
||||
let predicate = self.instantiate_opaque_types_in_map(predicate);
|
||||
|
||||
let cause =
|
||||
traits::ObligationCause::new(self.value_span, self.body_id, traits::OpaqueType);
|
||||
|
|
|
@ -218,40 +218,40 @@ impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a MetadataBlob, &'tcx Session) {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a CrateMetadataRef<'a> {
|
||||
impl<'a, 'tcx> Metadata<'a, 'tcx> for CrateMetadataRef<'a> {
|
||||
#[inline]
|
||||
fn blob(self) -> &'a MetadataBlob {
|
||||
&self.blob
|
||||
&self.cdata.blob
|
||||
}
|
||||
#[inline]
|
||||
fn cdata(self) -> Option<CrateMetadataRef<'a>> {
|
||||
Some(*self)
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadataRef<'a>, &'tcx Session) {
|
||||
impl<'a, 'tcx> Metadata<'a, 'tcx> for (CrateMetadataRef<'a>, &'tcx Session) {
|
||||
#[inline]
|
||||
fn blob(self) -> &'a MetadataBlob {
|
||||
&self.0.blob
|
||||
&self.0.cdata.blob
|
||||
}
|
||||
#[inline]
|
||||
fn cdata(self) -> Option<CrateMetadataRef<'a>> {
|
||||
Some(*self.0)
|
||||
Some(self.0)
|
||||
}
|
||||
#[inline]
|
||||
fn sess(self) -> Option<&'tcx Session> {
|
||||
Some(&self.1)
|
||||
Some(self.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadataRef<'a>, TyCtxt<'tcx>) {
|
||||
impl<'a, 'tcx> Metadata<'a, 'tcx> for (CrateMetadataRef<'a>, TyCtxt<'tcx>) {
|
||||
#[inline]
|
||||
fn blob(self) -> &'a MetadataBlob {
|
||||
&self.0.blob
|
||||
&self.0.cdata.blob
|
||||
}
|
||||
#[inline]
|
||||
fn cdata(self) -> Option<CrateMetadataRef<'a>> {
|
||||
Some(*self.0)
|
||||
Some(self.0)
|
||||
}
|
||||
#[inline]
|
||||
fn tcx(self) -> Option<TyCtxt<'tcx>> {
|
||||
|
@ -414,9 +414,9 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for SyntaxContext {
|
|||
Ok(cdata
|
||||
.root
|
||||
.syntax_contexts
|
||||
.get(&cdata, id)
|
||||
.get(cdata, id)
|
||||
.unwrap_or_else(|| panic!("Missing SyntaxContext {:?} for crate {:?}", id, cname))
|
||||
.decode((&cdata, sess)))
|
||||
.decode((cdata, sess)))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -442,15 +442,15 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnId {
|
|||
let expn_data = crate_data
|
||||
.root
|
||||
.expn_data
|
||||
.get(&crate_data, index)
|
||||
.get(crate_data, index)
|
||||
.unwrap()
|
||||
.decode((&crate_data, sess));
|
||||
.decode((crate_data, sess));
|
||||
let expn_hash = crate_data
|
||||
.root
|
||||
.expn_hashes
|
||||
.get(&crate_data, index)
|
||||
.get(crate_data, index)
|
||||
.unwrap()
|
||||
.decode((&crate_data, sess));
|
||||
.decode((crate_data, sess));
|
||||
(expn_data, expn_hash)
|
||||
});
|
||||
Ok(expn_id)
|
||||
|
@ -706,7 +706,7 @@ impl CrateRoot<'_> {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> CrateMetadataRef<'a> {
|
||||
fn raw_proc_macro(&self, id: DefIndex) -> &ProcMacro {
|
||||
fn raw_proc_macro(self, id: DefIndex) -> &'a ProcMacro {
|
||||
// DefIndex's in root.proc_macro_data have a one-to-one correspondence
|
||||
// with items in 'raw_proc_macros'.
|
||||
let pos = self
|
||||
|
@ -721,7 +721,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
&self.raw_proc_macros.unwrap()[pos]
|
||||
}
|
||||
|
||||
fn opt_item_ident(&self, item_index: DefIndex, sess: &Session) -> Option<Ident> {
|
||||
fn opt_item_ident(self, item_index: DefIndex, sess: &Session) -> Option<Ident> {
|
||||
let name = self.def_key(item_index).disambiguated_data.data.get_opt_name()?;
|
||||
let span = match self.root.tables.ident_span.get(self, item_index) {
|
||||
Some(lazy_span) => lazy_span.decode((self, sess)),
|
||||
|
@ -737,15 +737,15 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
Some(Ident::new(name, span))
|
||||
}
|
||||
|
||||
fn item_ident(&self, item_index: DefIndex, sess: &Session) -> Ident {
|
||||
fn item_ident(self, item_index: DefIndex, sess: &Session) -> Ident {
|
||||
self.opt_item_ident(item_index, sess).expect("no encoded ident for item")
|
||||
}
|
||||
|
||||
fn maybe_kind(&self, item_id: DefIndex) -> Option<EntryKind> {
|
||||
fn maybe_kind(self, item_id: DefIndex) -> Option<EntryKind> {
|
||||
self.root.tables.kind.get(self, item_id).map(|k| k.decode(self))
|
||||
}
|
||||
|
||||
fn kind(&self, item_id: DefIndex) -> EntryKind {
|
||||
fn kind(self, item_id: DefIndex) -> EntryKind {
|
||||
self.maybe_kind(item_id).unwrap_or_else(|| {
|
||||
bug!(
|
||||
"CrateMetadata::kind({:?}): id not found, in crate {:?} with number {}",
|
||||
|
@ -756,7 +756,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
fn def_kind(&self, item_id: DefIndex) -> DefKind {
|
||||
fn def_kind(self, item_id: DefIndex) -> DefKind {
|
||||
self.root.tables.def_kind.get(self, item_id).map(|k| k.decode(self)).unwrap_or_else(|| {
|
||||
bug!(
|
||||
"CrateMetadata::def_kind({:?}): id not found, in crate {:?} with number {}",
|
||||
|
@ -767,7 +767,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
fn get_span(&self, index: DefIndex, sess: &Session) -> Span {
|
||||
fn get_span(self, index: DefIndex, sess: &Session) -> Span {
|
||||
self.root
|
||||
.tables
|
||||
.span
|
||||
|
@ -776,7 +776,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
.decode((self, sess))
|
||||
}
|
||||
|
||||
fn load_proc_macro(&self, id: DefIndex, sess: &Session) -> SyntaxExtension {
|
||||
fn load_proc_macro(self, id: DefIndex, sess: &Session) -> SyntaxExtension {
|
||||
let (name, kind, helper_attrs) = match *self.raw_proc_macro(id) {
|
||||
ProcMacro::CustomDerive { trait_name, attributes, client } => {
|
||||
let helper_attrs =
|
||||
|
@ -807,7 +807,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
)
|
||||
}
|
||||
|
||||
fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef {
|
||||
fn get_trait_def(self, item_id: DefIndex, sess: &Session) -> ty::TraitDef {
|
||||
match self.kind(item_id) {
|
||||
EntryKind::Trait(data) => {
|
||||
let data = data.decode((self, sess));
|
||||
|
@ -837,7 +837,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
|
||||
fn get_variant(
|
||||
&self,
|
||||
self,
|
||||
kind: &EntryKind,
|
||||
index: DefIndex,
|
||||
parent_did: DefId,
|
||||
|
@ -886,7 +886,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
)
|
||||
}
|
||||
|
||||
fn get_adt_def(&self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> &'tcx ty::AdtDef {
|
||||
fn get_adt_def(self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> &'tcx ty::AdtDef {
|
||||
let kind = self.kind(item_id);
|
||||
let did = self.local_def_id(item_id);
|
||||
|
||||
|
@ -914,7 +914,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
|
||||
fn get_explicit_predicates(
|
||||
&self,
|
||||
self,
|
||||
item_id: DefIndex,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> ty::GenericPredicates<'tcx> {
|
||||
|
@ -922,7 +922,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
|
||||
fn get_inferred_outlives(
|
||||
&self,
|
||||
self,
|
||||
item_id: DefIndex,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
|
||||
|
@ -935,7 +935,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
|
||||
fn get_super_predicates(
|
||||
&self,
|
||||
self,
|
||||
item_id: DefIndex,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> ty::GenericPredicates<'tcx> {
|
||||
|
@ -943,7 +943,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
|
||||
fn get_explicit_item_bounds(
|
||||
&self,
|
||||
self,
|
||||
item_id: DefIndex,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
|
||||
|
@ -955,11 +955,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn get_generics(&self, item_id: DefIndex, sess: &Session) -> ty::Generics {
|
||||
fn get_generics(self, item_id: DefIndex, sess: &Session) -> ty::Generics {
|
||||
self.root.tables.generics.get(self, item_id).unwrap().decode((self, sess))
|
||||
}
|
||||
|
||||
fn get_type(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
|
||||
fn get_type(self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
|
||||
self.root
|
||||
.tables
|
||||
.ty
|
||||
|
@ -968,63 +968,63 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
.decode((self, tcx))
|
||||
}
|
||||
|
||||
fn get_stability(&self, id: DefIndex) -> Option<attr::Stability> {
|
||||
fn get_stability(self, id: DefIndex) -> Option<attr::Stability> {
|
||||
self.root.tables.stability.get(self, id).map(|stab| stab.decode(self))
|
||||
}
|
||||
|
||||
fn get_const_stability(&self, id: DefIndex) -> Option<attr::ConstStability> {
|
||||
fn get_const_stability(self, id: DefIndex) -> Option<attr::ConstStability> {
|
||||
self.root.tables.const_stability.get(self, id).map(|stab| stab.decode(self))
|
||||
}
|
||||
|
||||
fn get_deprecation(&self, id: DefIndex) -> Option<attr::Deprecation> {
|
||||
fn get_deprecation(self, id: DefIndex) -> Option<attr::Deprecation> {
|
||||
self.root.tables.deprecation.get(self, id).map(|depr| depr.decode(self))
|
||||
}
|
||||
|
||||
fn get_visibility(&self, id: DefIndex) -> ty::Visibility {
|
||||
fn get_visibility(self, id: DefIndex) -> ty::Visibility {
|
||||
self.root.tables.visibility.get(self, id).unwrap().decode(self)
|
||||
}
|
||||
|
||||
fn get_impl_data(&self, id: DefIndex) -> ImplData {
|
||||
fn get_impl_data(self, id: DefIndex) -> ImplData {
|
||||
match self.kind(id) {
|
||||
EntryKind::Impl(data) => data.decode(self),
|
||||
_ => bug!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_parent_impl(&self, id: DefIndex) -> Option<DefId> {
|
||||
fn get_parent_impl(self, id: DefIndex) -> Option<DefId> {
|
||||
self.get_impl_data(id).parent_impl
|
||||
}
|
||||
|
||||
fn get_impl_polarity(&self, id: DefIndex) -> ty::ImplPolarity {
|
||||
fn get_impl_polarity(self, id: DefIndex) -> ty::ImplPolarity {
|
||||
self.get_impl_data(id).polarity
|
||||
}
|
||||
|
||||
fn get_impl_defaultness(&self, id: DefIndex) -> hir::Defaultness {
|
||||
fn get_impl_defaultness(self, id: DefIndex) -> hir::Defaultness {
|
||||
self.get_impl_data(id).defaultness
|
||||
}
|
||||
|
||||
fn get_impl_constness(&self, id: DefIndex) -> hir::Constness {
|
||||
fn get_impl_constness(self, id: DefIndex) -> hir::Constness {
|
||||
self.get_impl_data(id).constness
|
||||
}
|
||||
|
||||
fn get_trait_item_def_id(&self, id: DefIndex) -> Option<DefId> {
|
||||
fn get_trait_item_def_id(self, id: DefIndex) -> Option<DefId> {
|
||||
self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode(self))
|
||||
}
|
||||
|
||||
fn get_coerce_unsized_info(&self, id: DefIndex) -> Option<ty::adjustment::CoerceUnsizedInfo> {
|
||||
fn get_coerce_unsized_info(self, id: DefIndex) -> Option<ty::adjustment::CoerceUnsizedInfo> {
|
||||
self.get_impl_data(id).coerce_unsized_info
|
||||
}
|
||||
|
||||
fn get_impl_trait(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Option<ty::TraitRef<'tcx>> {
|
||||
fn get_impl_trait(self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Option<ty::TraitRef<'tcx>> {
|
||||
self.root.tables.impl_trait_ref.get(self, id).map(|tr| tr.decode((self, tcx)))
|
||||
}
|
||||
|
||||
fn get_expn_that_defined(&self, id: DefIndex, sess: &Session) -> ExpnId {
|
||||
fn get_expn_that_defined(self, id: DefIndex, sess: &Session) -> ExpnId {
|
||||
self.root.tables.expn_that_defined.get(self, id).unwrap().decode((self, sess))
|
||||
}
|
||||
|
||||
fn get_const_param_default(
|
||||
&self,
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
id: DefIndex,
|
||||
) -> rustc_middle::ty::Const<'tcx> {
|
||||
|
@ -1032,14 +1032,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
|
||||
/// Iterates over all the stability attributes in the given crate.
|
||||
fn get_lib_features(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Option<Symbol>)] {
|
||||
fn get_lib_features(self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Option<Symbol>)] {
|
||||
// FIXME: For a proc macro crate, not sure whether we should return the "host"
|
||||
// features or an empty Vec. Both don't cause ICEs.
|
||||
tcx.arena.alloc_from_iter(self.root.lib_features.decode(self))
|
||||
}
|
||||
|
||||
/// Iterates over the language items in the given crate.
|
||||
fn get_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] {
|
||||
fn get_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] {
|
||||
if self.root.is_proc_macro_crate() {
|
||||
// Proc macro crates do not export any lang-items to the target.
|
||||
&[]
|
||||
|
@ -1054,7 +1054,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
|
||||
/// Iterates over the diagnostic items in the given crate.
|
||||
fn get_diagnostic_items(&self) -> DiagnosticItems {
|
||||
fn get_diagnostic_items(self) -> DiagnosticItems {
|
||||
if self.root.is_proc_macro_crate() {
|
||||
// Proc macro crates do not export any diagnostic-items to the target.
|
||||
Default::default()
|
||||
|
@ -1079,7 +1079,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
/// Module here is understood in name resolution sense - it can be a `mod` item,
|
||||
/// or a crate root, or an enum, or a trait.
|
||||
fn for_each_module_child(
|
||||
&self,
|
||||
self,
|
||||
id: DefIndex,
|
||||
mut callback: impl FnMut(ModChild),
|
||||
sess: &Session,
|
||||
|
@ -1177,15 +1177,15 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_ctfe_mir_available(&self, id: DefIndex) -> bool {
|
||||
fn is_ctfe_mir_available(self, id: DefIndex) -> bool {
|
||||
self.root.tables.mir_for_ctfe.get(self, id).is_some()
|
||||
}
|
||||
|
||||
fn is_item_mir_available(&self, id: DefIndex) -> bool {
|
||||
fn is_item_mir_available(self, id: DefIndex) -> bool {
|
||||
self.root.tables.mir.get(self, id).is_some()
|
||||
}
|
||||
|
||||
fn module_expansion(&self, id: DefIndex, sess: &Session) -> ExpnId {
|
||||
fn module_expansion(self, id: DefIndex, sess: &Session) -> ExpnId {
|
||||
match self.kind(id) {
|
||||
EntryKind::Mod(_) | EntryKind::Enum(_) | EntryKind::Trait(_) => {
|
||||
self.get_expn_that_defined(id, sess)
|
||||
|
@ -1194,7 +1194,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
|
||||
fn get_optimized_mir(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
|
||||
self.root
|
||||
.tables
|
||||
.mir
|
||||
|
@ -1205,7 +1205,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
.decode((self, tcx))
|
||||
}
|
||||
|
||||
fn get_mir_for_ctfe(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
|
||||
fn get_mir_for_ctfe(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
|
||||
self.root
|
||||
.tables
|
||||
.mir_for_ctfe
|
||||
|
@ -1217,7 +1217,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
|
||||
fn get_thir_abstract_const(
|
||||
&self,
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
id: DefIndex,
|
||||
) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorReported> {
|
||||
|
@ -1228,7 +1228,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
.map_or(Ok(None), |v| Ok(Some(v.decode((self, tcx)))))
|
||||
}
|
||||
|
||||
fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet<u32> {
|
||||
fn get_unused_generic_params(self, id: DefIndex) -> FiniteBitSet<u32> {
|
||||
self.root
|
||||
.tables
|
||||
.unused_generic_params
|
||||
|
@ -1237,7 +1237,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn get_promoted_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> IndexVec<Promoted, Body<'tcx>> {
|
||||
fn get_promoted_mir(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> IndexVec<Promoted, Body<'tcx>> {
|
||||
self.root
|
||||
.tables
|
||||
.promoted_mir
|
||||
|
@ -1248,7 +1248,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
.decode((self, tcx))
|
||||
}
|
||||
|
||||
fn mir_const_qualif(&self, id: DefIndex) -> mir::ConstQualifs {
|
||||
fn mir_const_qualif(self, id: DefIndex) -> mir::ConstQualifs {
|
||||
match self.kind(id) {
|
||||
EntryKind::AnonConst(qualif, _)
|
||||
| EntryKind::Const(qualif, _)
|
||||
|
@ -1263,14 +1263,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_fn_has_self_parameter(&self, id: DefIndex) -> bool {
|
||||
fn get_fn_has_self_parameter(self, id: DefIndex) -> bool {
|
||||
match self.kind(id) {
|
||||
EntryKind::AssocFn(data) => data.decode(self).has_self,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_associated_item_def_ids(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [DefId] {
|
||||
fn get_associated_item_def_ids(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [DefId] {
|
||||
if let Some(children) = self.root.tables.children.get(self, id) {
|
||||
tcx.arena.alloc_from_iter(
|
||||
children.decode((self, tcx.sess)).map(|child_index| self.local_def_id(child_index)),
|
||||
|
@ -1280,7 +1280,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_associated_item(&self, id: DefIndex, sess: &Session) -> ty::AssocItem {
|
||||
fn get_associated_item(self, id: DefIndex, sess: &Session) -> ty::AssocItem {
|
||||
let def_key = self.def_key(id);
|
||||
let parent = self.local_def_id(def_key.parent.unwrap());
|
||||
let ident = self.item_ident(id, sess);
|
||||
|
@ -1307,11 +1307,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_item_variances(&'a self, id: DefIndex) -> impl Iterator<Item = ty::Variance> + 'a {
|
||||
fn get_item_variances(self, id: DefIndex) -> impl Iterator<Item = ty::Variance> + 'a {
|
||||
self.root.tables.variances.get(self, id).unwrap_or_else(Lazy::empty).decode(self)
|
||||
}
|
||||
|
||||
fn get_ctor_def_id_and_kind(&self, node_id: DefIndex) -> Option<(DefId, CtorKind)> {
|
||||
fn get_ctor_def_id_and_kind(self, node_id: DefIndex) -> Option<(DefId, CtorKind)> {
|
||||
match self.kind(node_id) {
|
||||
EntryKind::Struct(data, _) | EntryKind::Variant(data) => {
|
||||
let vdata = data.decode(self);
|
||||
|
@ -1322,7 +1322,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
|
||||
fn get_item_attrs(
|
||||
&'a self,
|
||||
self,
|
||||
id: DefIndex,
|
||||
sess: &'a Session,
|
||||
) -> impl Iterator<Item = ast::Attribute> + 'a {
|
||||
|
@ -1346,7 +1346,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
.decode((self, sess))
|
||||
}
|
||||
|
||||
fn get_struct_field_names(&self, id: DefIndex, sess: &Session) -> Vec<Spanned<Symbol>> {
|
||||
fn get_struct_field_names(self, id: DefIndex, sess: &Session) -> Vec<Spanned<Symbol>> {
|
||||
self.root
|
||||
.tables
|
||||
.children
|
||||
|
@ -1357,7 +1357,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn get_struct_field_visibilities(&self, id: DefIndex) -> Vec<Visibility> {
|
||||
fn get_struct_field_visibilities(self, id: DefIndex) -> Vec<Visibility> {
|
||||
self.root
|
||||
.tables
|
||||
.children
|
||||
|
@ -1369,7 +1369,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
|
||||
fn get_inherent_implementations_for_type(
|
||||
&self,
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
id: DefIndex,
|
||||
) -> &'tcx [DefId] {
|
||||
|
@ -1384,20 +1384,20 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
)
|
||||
}
|
||||
|
||||
fn get_traits(&'a self) -> impl Iterator<Item = DefId> + 'a {
|
||||
self.root.traits.decode(self).map(|index| self.local_def_id(index))
|
||||
fn get_traits(self) -> impl Iterator<Item = DefId> + 'a {
|
||||
self.root.traits.decode(self).map(move |index| self.local_def_id(index))
|
||||
}
|
||||
|
||||
fn get_trait_impls(&'a self) -> impl Iterator<Item = (DefId, Option<SimplifiedType>)> + 'a {
|
||||
self.trait_impls.values().flat_map(move |impls| {
|
||||
fn get_trait_impls(self) -> impl Iterator<Item = (DefId, Option<SimplifiedType>)> + 'a {
|
||||
self.cdata.trait_impls.values().flat_map(move |impls| {
|
||||
impls
|
||||
.decode(self)
|
||||
.map(|(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty))
|
||||
.map(move |(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty))
|
||||
})
|
||||
}
|
||||
|
||||
fn get_implementations_of_trait(
|
||||
&self,
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_def_id: DefId,
|
||||
) -> &'tcx [(DefId, Option<SimplifiedType>)] {
|
||||
|
@ -1424,7 +1424,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_trait_of_item(&self, id: DefIndex) -> Option<DefId> {
|
||||
fn get_trait_of_item(self, id: DefIndex) -> Option<DefId> {
|
||||
let def_key = self.def_key(id);
|
||||
match def_key.disambiguated_data.data {
|
||||
DefPathData::TypeNs(..) | DefPathData::ValueNs(..) => (),
|
||||
|
@ -1437,7 +1437,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
fn get_native_libraries(&self, sess: &Session) -> Vec<NativeLib> {
|
||||
fn get_native_libraries(self, sess: &Session) -> Vec<NativeLib> {
|
||||
if self.root.is_proc_macro_crate() {
|
||||
// Proc macro crates do not have any *target* native libraries.
|
||||
vec![]
|
||||
|
@ -1446,7 +1446,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_proc_macro_quoted_span(&self, index: usize, sess: &Session) -> Span {
|
||||
fn get_proc_macro_quoted_span(self, index: usize, sess: &Session) -> Span {
|
||||
self.root
|
||||
.tables
|
||||
.proc_macro_quoted_spans
|
||||
|
@ -1455,7 +1455,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
.decode((self, sess))
|
||||
}
|
||||
|
||||
fn get_foreign_modules(&self, tcx: TyCtxt<'tcx>) -> Lrc<FxHashMap<DefId, ForeignModule>> {
|
||||
fn get_foreign_modules(self, tcx: TyCtxt<'tcx>) -> Lrc<FxHashMap<DefId, ForeignModule>> {
|
||||
if self.root.is_proc_macro_crate() {
|
||||
// Proc macro crates do not have any *target* foreign modules.
|
||||
Lrc::new(FxHashMap::default())
|
||||
|
@ -1467,7 +1467,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
|
||||
fn get_dylib_dependency_formats(
|
||||
&self,
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> &'tcx [(CrateNum, LinkagePreference)] {
|
||||
tcx.arena.alloc_from_iter(
|
||||
|
@ -1478,7 +1478,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
)
|
||||
}
|
||||
|
||||
fn get_missing_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] {
|
||||
fn get_missing_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] {
|
||||
if self.root.is_proc_macro_crate() {
|
||||
// Proc macro crates do not depend on any target weak lang-items.
|
||||
&[]
|
||||
|
@ -1487,7 +1487,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_fn_param_names(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [Ident] {
|
||||
fn get_fn_param_names(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [Ident] {
|
||||
let param_names = match self.kind(id) {
|
||||
EntryKind::Fn(data) | EntryKind::ForeignFn(data) => data.decode(self).param_names,
|
||||
EntryKind::AssocFn(data) => data.decode(self).fn_data.param_names,
|
||||
|
@ -1497,7 +1497,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
|
||||
fn exported_symbols(
|
||||
&self,
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] {
|
||||
if self.root.is_proc_macro_crate() {
|
||||
|
@ -1509,7 +1509,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_rendered_const(&self, id: DefIndex) -> String {
|
||||
fn get_rendered_const(self, id: DefIndex) -> String {
|
||||
match self.kind(id) {
|
||||
EntryKind::AnonConst(_, data)
|
||||
| EntryKind::Const(_, data)
|
||||
|
@ -1518,7 +1518,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_macro(&self, id: DefIndex, sess: &Session) -> MacroDef {
|
||||
fn get_macro(self, id: DefIndex, sess: &Session) -> MacroDef {
|
||||
match self.kind(id) {
|
||||
EntryKind::MacroDef(macro_def) => macro_def.decode((self, sess)),
|
||||
_ => bug!(),
|
||||
|
@ -1527,7 +1527,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
|
||||
// This replicates some of the logic of the crate-local `is_const_fn_raw` query, because we
|
||||
// don't serialize constness for tuple variant and tuple struct constructors.
|
||||
fn is_const_fn_raw(&self, id: DefIndex) -> bool {
|
||||
fn is_const_fn_raw(self, id: DefIndex) -> bool {
|
||||
let constness = match self.kind(id) {
|
||||
EntryKind::AssocFn(data) => data.decode(self).fn_data.constness,
|
||||
EntryKind::Fn(data) => data.decode(self).constness,
|
||||
|
@ -1538,7 +1538,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
constness == hir::Constness::Const
|
||||
}
|
||||
|
||||
fn asyncness(&self, id: DefIndex) -> hir::IsAsync {
|
||||
fn asyncness(self, id: DefIndex) -> hir::IsAsync {
|
||||
match self.kind(id) {
|
||||
EntryKind::Fn(data) => data.decode(self).asyncness,
|
||||
EntryKind::AssocFn(data) => data.decode(self).fn_data.asyncness,
|
||||
|
@ -1547,7 +1547,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_foreign_item(&self, id: DefIndex) -> bool {
|
||||
fn is_foreign_item(self, id: DefIndex) -> bool {
|
||||
match self.kind(id) {
|
||||
EntryKind::ForeignImmStatic | EntryKind::ForeignMutStatic | EntryKind::ForeignFn(_) => {
|
||||
true
|
||||
|
@ -1556,7 +1556,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn static_mutability(&self, id: DefIndex) -> Option<hir::Mutability> {
|
||||
fn static_mutability(self, id: DefIndex) -> Option<hir::Mutability> {
|
||||
match self.kind(id) {
|
||||
EntryKind::ImmStatic | EntryKind::ForeignImmStatic => Some(hir::Mutability::Not),
|
||||
EntryKind::MutStatic | EntryKind::ForeignMutStatic => Some(hir::Mutability::Mut),
|
||||
|
@ -1564,19 +1564,19 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn generator_kind(&self, id: DefIndex) -> Option<hir::GeneratorKind> {
|
||||
fn generator_kind(self, id: DefIndex) -> Option<hir::GeneratorKind> {
|
||||
match self.kind(id) {
|
||||
EntryKind::Generator(data) => Some(data),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn fn_sig(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> {
|
||||
fn fn_sig(self, id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> {
|
||||
self.root.tables.fn_sig.get(self, id).unwrap().decode((self, tcx))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn def_key(&self, index: DefIndex) -> DefKey {
|
||||
fn def_key(self, index: DefIndex) -> DefKey {
|
||||
*self
|
||||
.def_key_cache
|
||||
.lock()
|
||||
|
@ -1585,13 +1585,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
|
||||
// Returns the path leading to the thing with this `id`.
|
||||
fn def_path(&self, id: DefIndex) -> DefPath {
|
||||
fn def_path(self, id: DefIndex) -> DefPath {
|
||||
debug!("def_path(cnum={:?}, id={:?})", self.cnum, id);
|
||||
DefPath::make(self.cnum, id, |parent| self.def_key(parent))
|
||||
}
|
||||
|
||||
fn def_path_hash_unlocked(
|
||||
&self,
|
||||
self,
|
||||
index: DefIndex,
|
||||
def_path_hashes: &mut FxHashMap<DefIndex, DefPathHash>,
|
||||
) -> DefPathHash {
|
||||
|
@ -1601,17 +1601,17 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn def_path_hash(&self, index: DefIndex) -> DefPathHash {
|
||||
fn def_path_hash(self, index: DefIndex) -> DefPathHash {
|
||||
let mut def_path_hashes = self.def_path_hash_cache.lock();
|
||||
self.def_path_hash_unlocked(index, &mut def_path_hashes)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn def_path_hash_to_def_index(&self, hash: DefPathHash) -> DefIndex {
|
||||
fn def_path_hash_to_def_index(self, hash: DefPathHash) -> DefIndex {
|
||||
self.def_path_hash_map.def_path_hash_to_def_index(&hash)
|
||||
}
|
||||
|
||||
fn expn_hash_to_expn_id(&self, sess: &Session, index_guess: u32, hash: ExpnHash) -> ExpnId {
|
||||
fn expn_hash_to_expn_id(self, sess: &Session, index_guess: u32, hash: ExpnHash) -> ExpnId {
|
||||
debug_assert_eq!(ExpnId::from_hash(hash), None);
|
||||
let index_guess = ExpnIndex::from_u32(index_guess);
|
||||
let old_hash = self.root.expn_hashes.get(self, index_guess).map(|lazy| lazy.decode(self));
|
||||
|
@ -1669,7 +1669,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
///
|
||||
/// Proc macro crates don't currently export spans, so this function does not have
|
||||
/// to work for them.
|
||||
fn imported_source_files(&self, sess: &Session) -> &'a [ImportedSourceFile] {
|
||||
fn imported_source_files(self, sess: &Session) -> &'a [ImportedSourceFile] {
|
||||
// Translate the virtual `/rustc/$hash` prefix back to a real directory
|
||||
// that should hold actual sources, where possible.
|
||||
//
|
||||
|
|
|
@ -247,6 +247,9 @@ pub struct CodegenUnit<'tcx> {
|
|||
items: FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)>,
|
||||
size_estimate: Option<usize>,
|
||||
primary: bool,
|
||||
/// True if this is CGU is used to hold code coverage information for dead code,
|
||||
/// false otherwise.
|
||||
is_code_coverage_dead_code_cgu: bool,
|
||||
}
|
||||
|
||||
/// Specifies the linkage type for a `MonoItem`.
|
||||
|
@ -277,7 +280,13 @@ pub enum Visibility {
|
|||
impl<'tcx> CodegenUnit<'tcx> {
|
||||
#[inline]
|
||||
pub fn new(name: Symbol) -> CodegenUnit<'tcx> {
|
||||
CodegenUnit { name, items: Default::default(), size_estimate: None, primary: false }
|
||||
CodegenUnit {
|
||||
name,
|
||||
items: Default::default(),
|
||||
size_estimate: None,
|
||||
primary: false,
|
||||
is_code_coverage_dead_code_cgu: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> Symbol {
|
||||
|
@ -304,6 +313,15 @@ impl<'tcx> CodegenUnit<'tcx> {
|
|||
&mut self.items
|
||||
}
|
||||
|
||||
pub fn is_code_coverage_dead_code_cgu(&self) -> bool {
|
||||
self.is_code_coverage_dead_code_cgu
|
||||
}
|
||||
|
||||
/// Marks this CGU as the one used to contain code coverage information for dead code.
|
||||
pub fn make_code_coverage_dead_code_cgu(&mut self) {
|
||||
self.is_code_coverage_dead_code_cgu = true;
|
||||
}
|
||||
|
||||
pub fn mangle_name(human_readable_name: &str) -> String {
|
||||
// We generate a 80 bit hash from the name. This should be enough to
|
||||
// avoid collisions and is still reasonably short for filenames.
|
||||
|
@ -404,9 +422,11 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for CodegenUnit<'tcx> {
|
|||
// The size estimate is not relevant to the hash
|
||||
size_estimate: _,
|
||||
primary: _,
|
||||
is_code_coverage_dead_code_cgu,
|
||||
} = *self;
|
||||
|
||||
name.hash_stable(hcx, hasher);
|
||||
is_code_coverage_dead_code_cgu.hash_stable(hcx, hasher);
|
||||
|
||||
let mut items: Vec<(Fingerprint, _)> = items
|
||||
.iter()
|
||||
|
|
|
@ -386,16 +386,6 @@ rustc_queries! {
|
|||
storage(ArenaCacheSelector<'tcx>)
|
||||
}
|
||||
|
||||
/// Returns the name of the file that contains the function body, if instrumented for coverage.
|
||||
query covered_file_name(key: DefId) -> Option<Symbol> {
|
||||
desc {
|
||||
|tcx| "retrieving the covered file name, if instrumented, for `{}`",
|
||||
tcx.def_path_str(key)
|
||||
}
|
||||
storage(ArenaCacheSelector<'tcx>)
|
||||
cache_on_disk_if { key.is_local() }
|
||||
}
|
||||
|
||||
/// Returns the `CodeRegions` for a function that has instrumented coverage, in case the
|
||||
/// function was optimized out before codegen, and before being added to the Coverage Map.
|
||||
query covered_code_regions(key: DefId) -> Vec<&'tcx mir::coverage::CodeRegion> {
|
||||
|
|
|
@ -9,7 +9,6 @@ use rustc_span::def_id::DefId;
|
|||
/// A `query` provider for retrieving coverage information injected into MIR.
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
providers.coverageinfo = |tcx, def_id| coverageinfo(tcx, def_id);
|
||||
providers.covered_file_name = |tcx, def_id| covered_file_name(tcx, def_id);
|
||||
providers.covered_code_regions = |tcx, def_id| covered_code_regions(tcx, def_id);
|
||||
}
|
||||
|
||||
|
@ -137,25 +136,6 @@ fn coverageinfo<'tcx>(tcx: TyCtxt<'tcx>, instance_def: ty::InstanceDef<'tcx>) ->
|
|||
coverage_visitor.info
|
||||
}
|
||||
|
||||
fn covered_file_name(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
|
||||
if tcx.is_mir_available(def_id) {
|
||||
let body = mir_body(tcx, def_id);
|
||||
for bb_data in body.basic_blocks().iter() {
|
||||
for statement in bb_data.statements.iter() {
|
||||
if let StatementKind::Coverage(box ref coverage) = statement.kind {
|
||||
if let Some(code_region) = coverage.code_region.as_ref() {
|
||||
if is_inlined(body, statement) {
|
||||
continue;
|
||||
}
|
||||
return Some(code_region.file_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
fn covered_code_regions<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<&'tcx CodeRegion> {
|
||||
let body = mir_body(tcx, def_id);
|
||||
body.basic_blocks()
|
||||
|
|
|
@ -201,6 +201,40 @@ pub fn partition<'tcx>(
|
|||
partitioner.internalize_symbols(cx, &mut post_inlining);
|
||||
}
|
||||
|
||||
let instrument_dead_code =
|
||||
tcx.sess.instrument_coverage() && !tcx.sess.instrument_coverage_except_unused_functions();
|
||||
|
||||
if instrument_dead_code {
|
||||
assert!(
|
||||
post_inlining.codegen_units.len() > 0,
|
||||
"There must be at least one CGU that code coverage data can be generated in."
|
||||
);
|
||||
|
||||
// Find the smallest CGU that has exported symbols and put the dead
|
||||
// function stubs in that CGU. We look for exported symbols to increase
|
||||
// the likelihood the linker won't throw away the dead functions.
|
||||
// FIXME(#92165): In order to truly resolve this, we need to make sure
|
||||
// the object file (CGU) containing the dead function stubs is included
|
||||
// in the final binary. This will probably require forcing these
|
||||
// function symbols to be included via `-u` or `/include` linker args.
|
||||
let mut cgus: Vec<_> = post_inlining.codegen_units.iter_mut().collect();
|
||||
cgus.sort_by_key(|cgu| cgu.size_estimate());
|
||||
|
||||
let dead_code_cgu = if let Some(cgu) = cgus
|
||||
.into_iter()
|
||||
.rev()
|
||||
.filter(|cgu| cgu.items().iter().any(|(_, (linkage, _))| *linkage == Linkage::External))
|
||||
.next()
|
||||
{
|
||||
cgu
|
||||
} else {
|
||||
// If there are no CGUs that have externally linked items,
|
||||
// then we just pick the first CGU as a fallback.
|
||||
&mut post_inlining.codegen_units[0]
|
||||
};
|
||||
dead_code_cgu.make_code_coverage_dead_code_cgu();
|
||||
}
|
||||
|
||||
// Finally, sort by codegen unit name, so that we get deterministic results.
|
||||
let PostInliningPartitioning {
|
||||
codegen_units: mut result,
|
||||
|
|
|
@ -4,7 +4,9 @@ use crate::infer::canonical::{
|
|||
use crate::infer::{InferCtxt, InferOk};
|
||||
use crate::traits::query::Fallible;
|
||||
use crate::traits::ObligationCause;
|
||||
use rustc_infer::infer::canonical::Canonical;
|
||||
use rustc_infer::infer::canonical::{Canonical, Certainty};
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::PredicateObligations;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
|
||||
use std::fmt;
|
||||
|
@ -17,7 +19,6 @@ pub mod implied_outlives_bounds;
|
|||
pub mod normalize;
|
||||
pub mod outlives;
|
||||
pub mod prove_predicate;
|
||||
use self::prove_predicate::ProvePredicate;
|
||||
pub mod subtype;
|
||||
|
||||
pub use rustc_middle::traits::query::type_op::*;
|
||||
|
@ -80,9 +81,14 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<'tcx> + 'tcx {
|
|||
query_key: ParamEnvAnd<'tcx, Self>,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
|
||||
) -> Fallible<(Self::QueryResponse, Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>)> {
|
||||
) -> Fallible<(
|
||||
Self::QueryResponse,
|
||||
Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>,
|
||||
PredicateObligations<'tcx>,
|
||||
Certainty,
|
||||
)> {
|
||||
if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) {
|
||||
return Ok((result, None));
|
||||
return Ok((result, None, vec![], Certainty::Proven));
|
||||
}
|
||||
|
||||
// FIXME(#33684) -- We need to use
|
||||
|
@ -104,20 +110,7 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<'tcx> + 'tcx {
|
|||
output_query_region_constraints,
|
||||
)?;
|
||||
|
||||
// Typically, instantiating NLL query results does not
|
||||
// create obligations. However, in some cases there
|
||||
// are unresolved type variables, and unify them *can*
|
||||
// create obligations. In that case, we have to go
|
||||
// fulfill them. We do this via a (recursive) query.
|
||||
for obligation in obligations {
|
||||
let ((), _) = ProvePredicate::fully_perform_into(
|
||||
obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
|
||||
infcx,
|
||||
output_query_region_constraints,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok((value, Some(canonical_self)))
|
||||
Ok((value, Some(canonical_self), obligations, canonical_result.value.certainty))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,9 +122,39 @@ where
|
|||
|
||||
fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
|
||||
let mut region_constraints = QueryRegionConstraints::default();
|
||||
let (output, canonicalized_query) =
|
||||
let (output, canonicalized_query, mut obligations, _) =
|
||||
Q::fully_perform_into(self, infcx, &mut region_constraints)?;
|
||||
|
||||
// Typically, instantiating NLL query results does not
|
||||
// create obligations. However, in some cases there
|
||||
// are unresolved type variables, and unify them *can*
|
||||
// create obligations. In that case, we have to go
|
||||
// fulfill them. We do this via a (recursive) query.
|
||||
while !obligations.is_empty() {
|
||||
trace!("{:#?}", obligations);
|
||||
let mut progress = false;
|
||||
for obligation in std::mem::take(&mut obligations) {
|
||||
let obligation = infcx.resolve_vars_if_possible(obligation);
|
||||
match ProvePredicate::fully_perform_into(
|
||||
obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
|
||||
infcx,
|
||||
&mut region_constraints,
|
||||
) {
|
||||
Ok(((), _, new, certainty)) => {
|
||||
obligations.extend(new);
|
||||
progress = true;
|
||||
if let Certainty::Ambiguous = certainty {
|
||||
obligations.push(obligation);
|
||||
}
|
||||
}
|
||||
Err(_) => obligations.push(obligation),
|
||||
}
|
||||
}
|
||||
if !progress {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
}
|
||||
|
||||
// Promote the final query-region-constraints into a
|
||||
// (optional) ref-counted vector:
|
||||
let region_constraints =
|
||||
|
|
|
@ -25,7 +25,7 @@ use crate::backtrace::Backtrace;
|
|||
use crate::borrow::Cow;
|
||||
use crate::cell;
|
||||
use crate::char;
|
||||
use crate::fmt::{self, Debug, Display};
|
||||
use crate::fmt::{self, Debug, Display, Write};
|
||||
use crate::mem::transmute;
|
||||
use crate::num;
|
||||
use crate::str;
|
||||
|
@ -63,7 +63,7 @@ pub trait Error: Debug + Display {
|
|||
///
|
||||
/// #[derive(Debug)]
|
||||
/// struct SuperError {
|
||||
/// side: SuperErrorSideKick,
|
||||
/// source: SuperErrorSideKick,
|
||||
/// }
|
||||
///
|
||||
/// impl fmt::Display for SuperError {
|
||||
|
@ -74,7 +74,7 @@ pub trait Error: Debug + Display {
|
|||
///
|
||||
/// impl Error for SuperError {
|
||||
/// fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
/// Some(&self.side)
|
||||
/// Some(&self.source)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
|
@ -90,7 +90,7 @@ pub trait Error: Debug + Display {
|
|||
/// impl Error for SuperErrorSideKick {}
|
||||
///
|
||||
/// fn get_super_error() -> Result<(), SuperError> {
|
||||
/// Err(SuperError { side: SuperErrorSideKick })
|
||||
/// Err(SuperError { source: SuperErrorSideKick })
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
|
@ -810,3 +810,642 @@ impl dyn Error + Send + Sync {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// An error reporter that print's an error and its sources.
|
||||
///
|
||||
/// Report also exposes configuration options for formatting the error chain, either entirely on a
|
||||
/// single line, or in multi-line format with each cause in the error chain on a new line.
|
||||
///
|
||||
/// `Report` only requires that the wrapped error implements `Error`. It doesn't require that the
|
||||
/// wrapped error be `Send`, `Sync`, or `'static`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(error_reporter)]
|
||||
/// use std::error::{Error, Report};
|
||||
/// use std::fmt;
|
||||
///
|
||||
/// #[derive(Debug)]
|
||||
/// struct SuperError {
|
||||
/// source: SuperErrorSideKick,
|
||||
/// }
|
||||
///
|
||||
/// impl fmt::Display for SuperError {
|
||||
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// write!(f, "SuperError is here!")
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl Error for SuperError {
|
||||
/// fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
/// Some(&self.source)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// #[derive(Debug)]
|
||||
/// struct SuperErrorSideKick;
|
||||
///
|
||||
/// impl fmt::Display for SuperErrorSideKick {
|
||||
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// write!(f, "SuperErrorSideKick is here!")
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl Error for SuperErrorSideKick {}
|
||||
///
|
||||
/// fn get_super_error() -> Result<(), SuperError> {
|
||||
/// Err(SuperError { source: SuperErrorSideKick })
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// match get_super_error() {
|
||||
/// Err(e) => println!("Error: {}", Report::new(e)),
|
||||
/// _ => println!("No error"),
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This example produces the following output:
|
||||
///
|
||||
/// ```console
|
||||
/// Error: SuperError is here!: SuperErrorSideKick is here!
|
||||
/// ```
|
||||
///
|
||||
/// ## Output consistency
|
||||
///
|
||||
/// Report prints the same output via `Display` and `Debug`, so it works well with
|
||||
/// [`Result::unwrap`]/[`Result::expect`] which print their `Err` variant via `Debug`:
|
||||
///
|
||||
/// ```should_panic
|
||||
/// #![feature(error_reporter)]
|
||||
/// use std::error::Report;
|
||||
/// # use std::error::Error;
|
||||
/// # use std::fmt;
|
||||
/// # #[derive(Debug)]
|
||||
/// # struct SuperError {
|
||||
/// # source: SuperErrorSideKick,
|
||||
/// # }
|
||||
/// # impl fmt::Display for SuperError {
|
||||
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// # write!(f, "SuperError is here!")
|
||||
/// # }
|
||||
/// # }
|
||||
/// # impl Error for SuperError {
|
||||
/// # fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
/// # Some(&self.source)
|
||||
/// # }
|
||||
/// # }
|
||||
/// # #[derive(Debug)]
|
||||
/// # struct SuperErrorSideKick;
|
||||
/// # impl fmt::Display for SuperErrorSideKick {
|
||||
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// # write!(f, "SuperErrorSideKick is here!")
|
||||
/// # }
|
||||
/// # }
|
||||
/// # impl Error for SuperErrorSideKick {}
|
||||
/// # fn get_super_error() -> Result<(), SuperError> {
|
||||
/// # Err(SuperError { source: SuperErrorSideKick })
|
||||
/// # }
|
||||
///
|
||||
/// get_super_error().map_err(Report::new).unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// This example produces the following output:
|
||||
///
|
||||
/// ```console
|
||||
/// thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!', src/error.rs:34:40
|
||||
/// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||
/// ```
|
||||
///
|
||||
/// ## Return from `main`
|
||||
///
|
||||
/// `Report` also implements `From` for all types that implement [`Error`], this when combined with
|
||||
/// the `Debug` output means `Report` is an ideal starting place for formatting errors returned
|
||||
/// from `main`.
|
||||
///
|
||||
/// ```should_panic
|
||||
/// #![feature(error_reporter)]
|
||||
/// use std::error::Report;
|
||||
/// # use std::error::Error;
|
||||
/// # use std::fmt;
|
||||
/// # #[derive(Debug)]
|
||||
/// # struct SuperError {
|
||||
/// # source: SuperErrorSideKick,
|
||||
/// # }
|
||||
/// # impl fmt::Display for SuperError {
|
||||
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// # write!(f, "SuperError is here!")
|
||||
/// # }
|
||||
/// # }
|
||||
/// # impl Error for SuperError {
|
||||
/// # fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
/// # Some(&self.source)
|
||||
/// # }
|
||||
/// # }
|
||||
/// # #[derive(Debug)]
|
||||
/// # struct SuperErrorSideKick;
|
||||
/// # impl fmt::Display for SuperErrorSideKick {
|
||||
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// # write!(f, "SuperErrorSideKick is here!")
|
||||
/// # }
|
||||
/// # }
|
||||
/// # impl Error for SuperErrorSideKick {}
|
||||
/// # fn get_super_error() -> Result<(), SuperError> {
|
||||
/// # Err(SuperError { source: SuperErrorSideKick })
|
||||
/// # }
|
||||
///
|
||||
/// fn main() -> Result<(), Report> {
|
||||
/// get_super_error()?;
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This example produces the following output:
|
||||
///
|
||||
/// ```console
|
||||
/// Error: SuperError is here!: SuperErrorSideKick is here!
|
||||
/// ```
|
||||
///
|
||||
/// **Note**: `Report`s constructed via `?` and `From` will be configured to use the single line
|
||||
/// output format, if you want to make sure your `Report`s are pretty printed and include backtrace
|
||||
/// you will need to manually convert and enable those flags.
|
||||
///
|
||||
/// ```should_panic
|
||||
/// #![feature(error_reporter)]
|
||||
/// use std::error::Report;
|
||||
/// # use std::error::Error;
|
||||
/// # use std::fmt;
|
||||
/// # #[derive(Debug)]
|
||||
/// # struct SuperError {
|
||||
/// # source: SuperErrorSideKick,
|
||||
/// # }
|
||||
/// # impl fmt::Display for SuperError {
|
||||
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// # write!(f, "SuperError is here!")
|
||||
/// # }
|
||||
/// # }
|
||||
/// # impl Error for SuperError {
|
||||
/// # fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
/// # Some(&self.source)
|
||||
/// # }
|
||||
/// # }
|
||||
/// # #[derive(Debug)]
|
||||
/// # struct SuperErrorSideKick;
|
||||
/// # impl fmt::Display for SuperErrorSideKick {
|
||||
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// # write!(f, "SuperErrorSideKick is here!")
|
||||
/// # }
|
||||
/// # }
|
||||
/// # impl Error for SuperErrorSideKick {}
|
||||
/// # fn get_super_error() -> Result<(), SuperError> {
|
||||
/// # Err(SuperError { source: SuperErrorSideKick })
|
||||
/// # }
|
||||
///
|
||||
/// fn main() -> Result<(), Report> {
|
||||
/// get_super_error()
|
||||
/// .map_err(Report::from)
|
||||
/// .map_err(|r| r.pretty(true).show_backtrace(true))?;
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This example produces the following output:
|
||||
///
|
||||
/// ```console
|
||||
/// Error: SuperError is here!
|
||||
///
|
||||
/// Caused by:
|
||||
/// SuperErrorSideKick is here!
|
||||
/// ```
|
||||
#[unstable(feature = "error_reporter", issue = "90172")]
|
||||
pub struct Report<E = Box<dyn Error>> {
|
||||
/// The error being reported.
|
||||
error: E,
|
||||
/// Whether a backtrace should be included as part of the report.
|
||||
show_backtrace: bool,
|
||||
/// Whether the report should be pretty-printed.
|
||||
pretty: bool,
|
||||
}
|
||||
|
||||
impl<E> Report<E>
|
||||
where
|
||||
Report<E>: From<E>,
|
||||
{
|
||||
/// Create a new `Report` from an input error.
|
||||
#[unstable(feature = "error_reporter", issue = "90172")]
|
||||
pub fn new(error: E) -> Report<E> {
|
||||
Self::from(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> Report<E> {
|
||||
/// Enable pretty-printing the report across multiple lines.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(error_reporter)]
|
||||
/// use std::error::Report;
|
||||
/// # use std::error::Error;
|
||||
/// # use std::fmt;
|
||||
/// # #[derive(Debug)]
|
||||
/// # struct SuperError {
|
||||
/// # source: SuperErrorSideKick,
|
||||
/// # }
|
||||
/// # impl fmt::Display for SuperError {
|
||||
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// # write!(f, "SuperError is here!")
|
||||
/// # }
|
||||
/// # }
|
||||
/// # impl Error for SuperError {
|
||||
/// # fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
/// # Some(&self.source)
|
||||
/// # }
|
||||
/// # }
|
||||
/// # #[derive(Debug)]
|
||||
/// # struct SuperErrorSideKick;
|
||||
/// # impl fmt::Display for SuperErrorSideKick {
|
||||
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// # write!(f, "SuperErrorSideKick is here!")
|
||||
/// # }
|
||||
/// # }
|
||||
/// # impl Error for SuperErrorSideKick {}
|
||||
///
|
||||
/// let error = SuperError { source: SuperErrorSideKick };
|
||||
/// let report = Report::new(error).pretty(true);
|
||||
/// eprintln!("Error: {:?}", report);
|
||||
/// ```
|
||||
///
|
||||
/// This example produces the following output:
|
||||
///
|
||||
/// ```console
|
||||
/// Error: SuperError is here!
|
||||
///
|
||||
/// Caused by:
|
||||
/// SuperErrorSideKick is here!
|
||||
/// ```
|
||||
///
|
||||
/// When there are multiple source errors the causes will be numbered in order of iteration
|
||||
/// starting from the outermost error.
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(error_reporter)]
|
||||
/// use std::error::Report;
|
||||
/// # use std::error::Error;
|
||||
/// # use std::fmt;
|
||||
/// # #[derive(Debug)]
|
||||
/// # struct SuperError {
|
||||
/// # source: SuperErrorSideKick,
|
||||
/// # }
|
||||
/// # impl fmt::Display for SuperError {
|
||||
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// # write!(f, "SuperError is here!")
|
||||
/// # }
|
||||
/// # }
|
||||
/// # impl Error for SuperError {
|
||||
/// # fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
/// # Some(&self.source)
|
||||
/// # }
|
||||
/// # }
|
||||
/// # #[derive(Debug)]
|
||||
/// # struct SuperErrorSideKick {
|
||||
/// # source: SuperErrorSideKickSideKick,
|
||||
/// # }
|
||||
/// # impl fmt::Display for SuperErrorSideKick {
|
||||
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// # write!(f, "SuperErrorSideKick is here!")
|
||||
/// # }
|
||||
/// # }
|
||||
/// # impl Error for SuperErrorSideKick {
|
||||
/// # fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
/// # Some(&self.source)
|
||||
/// # }
|
||||
/// # }
|
||||
/// # #[derive(Debug)]
|
||||
/// # struct SuperErrorSideKickSideKick;
|
||||
/// # impl fmt::Display for SuperErrorSideKickSideKick {
|
||||
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// # write!(f, "SuperErrorSideKickSideKick is here!")
|
||||
/// # }
|
||||
/// # }
|
||||
/// # impl Error for SuperErrorSideKickSideKick { }
|
||||
///
|
||||
/// let source = SuperErrorSideKickSideKick;
|
||||
/// let source = SuperErrorSideKick { source };
|
||||
/// let error = SuperError { source };
|
||||
/// let report = Report::new(error).pretty(true);
|
||||
/// eprintln!("Error: {:?}", report);
|
||||
/// ```
|
||||
///
|
||||
/// This example produces the following output:
|
||||
///
|
||||
/// ```console
|
||||
/// Error: SuperError is here!
|
||||
///
|
||||
/// Caused by:
|
||||
/// 0: SuperErrorSideKick is here!
|
||||
/// 1: SuperErrorSideKickSideKick is here!
|
||||
/// ```
|
||||
#[unstable(feature = "error_reporter", issue = "90172")]
|
||||
pub fn pretty(mut self, pretty: bool) -> Self {
|
||||
self.pretty = pretty;
|
||||
self
|
||||
}
|
||||
|
||||
/// Display backtrace if available when using pretty output format.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// **Note**: Report will search for the first `Backtrace` it can find starting from the
|
||||
/// outermost error. In this example it will display the backtrace from the second error in the
|
||||
/// chain, `SuperErrorSideKick`.
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(error_reporter)]
|
||||
/// #![feature(backtrace)]
|
||||
/// # use std::error::Error;
|
||||
/// # use std::fmt;
|
||||
/// use std::error::Report;
|
||||
/// use std::backtrace::Backtrace;
|
||||
///
|
||||
/// # #[derive(Debug)]
|
||||
/// # struct SuperError {
|
||||
/// # source: SuperErrorSideKick,
|
||||
/// # }
|
||||
/// # impl fmt::Display for SuperError {
|
||||
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// # write!(f, "SuperError is here!")
|
||||
/// # }
|
||||
/// # }
|
||||
/// # impl Error for SuperError {
|
||||
/// # fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
/// # Some(&self.source)
|
||||
/// # }
|
||||
/// # }
|
||||
/// #[derive(Debug)]
|
||||
/// struct SuperErrorSideKick {
|
||||
/// backtrace: Backtrace,
|
||||
/// }
|
||||
///
|
||||
/// impl SuperErrorSideKick {
|
||||
/// fn new() -> SuperErrorSideKick {
|
||||
/// SuperErrorSideKick { backtrace: Backtrace::force_capture() }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl Error for SuperErrorSideKick {
|
||||
/// fn backtrace(&self) -> Option<&Backtrace> {
|
||||
/// Some(&self.backtrace)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // The rest of the example is unchanged ...
|
||||
/// # impl fmt::Display for SuperErrorSideKick {
|
||||
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// # write!(f, "SuperErrorSideKick is here!")
|
||||
/// # }
|
||||
/// # }
|
||||
///
|
||||
/// let source = SuperErrorSideKick::new();
|
||||
/// let error = SuperError { source };
|
||||
/// let report = Report::new(error).pretty(true).show_backtrace(true);
|
||||
/// eprintln!("Error: {:?}", report);
|
||||
/// ```
|
||||
///
|
||||
/// This example produces something similar to the following output:
|
||||
///
|
||||
/// ```console
|
||||
/// Error: SuperError is here!
|
||||
///
|
||||
/// Caused by:
|
||||
/// SuperErrorSideKick is here!
|
||||
///
|
||||
/// Stack backtrace:
|
||||
/// 0: rust_out::main::_doctest_main_src_error_rs_1158_0::SuperErrorSideKick::new
|
||||
/// 1: rust_out::main::_doctest_main_src_error_rs_1158_0
|
||||
/// 2: rust_out::main
|
||||
/// 3: core::ops::function::FnOnce::call_once
|
||||
/// 4: std::sys_common::backtrace::__rust_begin_short_backtrace
|
||||
/// 5: std::rt::lang_start::{{closure}}
|
||||
/// 6: std::panicking::try
|
||||
/// 7: std::rt::lang_start_internal
|
||||
/// 8: std::rt::lang_start
|
||||
/// 9: main
|
||||
/// 10: __libc_start_main
|
||||
/// 11: _start
|
||||
/// ```
|
||||
#[unstable(feature = "error_reporter", issue = "90172")]
|
||||
pub fn show_backtrace(mut self, show_backtrace: bool) -> Self {
|
||||
self.show_backtrace = show_backtrace;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> Report<E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
fn backtrace(&self) -> Option<&Backtrace> {
|
||||
// have to grab the backtrace on the first error directly since that error may not be
|
||||
// 'static
|
||||
let backtrace = self.error.backtrace();
|
||||
let backtrace = backtrace.or_else(|| {
|
||||
self.error
|
||||
.source()
|
||||
.map(|source| source.chain().find_map(|source| source.backtrace()))
|
||||
.flatten()
|
||||
});
|
||||
backtrace
|
||||
}
|
||||
|
||||
/// Format the report as a single line.
|
||||
#[unstable(feature = "error_reporter", issue = "90172")]
|
||||
fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.error)?;
|
||||
|
||||
let sources = self.error.source().into_iter().flat_map(<dyn Error>::chain);
|
||||
|
||||
for cause in sources {
|
||||
write!(f, ": {}", cause)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Format the report as multiple lines, with each error cause on its own line.
|
||||
#[unstable(feature = "error_reporter", issue = "90172")]
|
||||
fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let error = &self.error;
|
||||
|
||||
write!(f, "{}", error)?;
|
||||
|
||||
if let Some(cause) = error.source() {
|
||||
write!(f, "\n\nCaused by:")?;
|
||||
|
||||
let multiple = cause.source().is_some();
|
||||
|
||||
for (ind, error) in cause.chain().enumerate() {
|
||||
writeln!(f)?;
|
||||
let mut indented = Indented { inner: f };
|
||||
if multiple {
|
||||
write!(indented, "{: >4}: {}", ind, error)?;
|
||||
} else {
|
||||
write!(indented, " {}", error)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.show_backtrace {
|
||||
let backtrace = self.backtrace();
|
||||
|
||||
if let Some(backtrace) = backtrace {
|
||||
let backtrace = backtrace.to_string();
|
||||
|
||||
f.write_str("\n\nStack backtrace:\n")?;
|
||||
f.write_str(backtrace.trim_end())?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Report<Box<dyn Error>> {
|
||||
fn backtrace(&self) -> Option<&Backtrace> {
|
||||
// have to grab the backtrace on the first error directly since that error may not be
|
||||
// 'static
|
||||
let backtrace = self.error.backtrace();
|
||||
let backtrace = backtrace.or_else(|| {
|
||||
self.error
|
||||
.source()
|
||||
.map(|source| source.chain().find_map(|source| source.backtrace()))
|
||||
.flatten()
|
||||
});
|
||||
backtrace
|
||||
}
|
||||
|
||||
/// Format the report as a single line.
|
||||
#[unstable(feature = "error_reporter", issue = "90172")]
|
||||
fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.error)?;
|
||||
|
||||
let sources = self.error.source().into_iter().flat_map(<dyn Error>::chain);
|
||||
|
||||
for cause in sources {
|
||||
write!(f, ": {}", cause)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Format the report as multiple lines, with each error cause on its own line.
|
||||
#[unstable(feature = "error_reporter", issue = "90172")]
|
||||
fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let error = &self.error;
|
||||
|
||||
write!(f, "{}", error)?;
|
||||
|
||||
if let Some(cause) = error.source() {
|
||||
write!(f, "\n\nCaused by:")?;
|
||||
|
||||
let multiple = cause.source().is_some();
|
||||
|
||||
for (ind, error) in cause.chain().enumerate() {
|
||||
writeln!(f)?;
|
||||
let mut indented = Indented { inner: f };
|
||||
if multiple {
|
||||
write!(indented, "{: >4}: {}", ind, error)?;
|
||||
} else {
|
||||
write!(indented, " {}", error)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.show_backtrace {
|
||||
let backtrace = self.backtrace();
|
||||
|
||||
if let Some(backtrace) = backtrace {
|
||||
let backtrace = backtrace.to_string();
|
||||
|
||||
f.write_str("\n\nStack backtrace:\n")?;
|
||||
f.write_str(backtrace.trim_end())?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "error_reporter", issue = "90172")]
|
||||
impl<E> From<E> for Report<E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
fn from(error: E) -> Self {
|
||||
Report { error, show_backtrace: false, pretty: false }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "error_reporter", issue = "90172")]
|
||||
impl<'a, E> From<E> for Report<Box<dyn Error + 'a>>
|
||||
where
|
||||
E: Error + 'a,
|
||||
{
|
||||
fn from(error: E) -> Self {
|
||||
let error = box error;
|
||||
Report { error, show_backtrace: false, pretty: false }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "error_reporter", issue = "90172")]
|
||||
impl<E> fmt::Display for Report<E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if self.pretty { self.fmt_multiline(f) } else { self.fmt_singleline(f) }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "error_reporter", issue = "90172")]
|
||||
impl fmt::Display for Report<Box<dyn Error>> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if self.pretty { self.fmt_multiline(f) } else { self.fmt_singleline(f) }
|
||||
}
|
||||
}
|
||||
|
||||
// This type intentionally outputs the same format for `Display` and `Debug`for
|
||||
// situations where you unwrap a `Report` or return it from main.
|
||||
#[unstable(feature = "error_reporter", issue = "90172")]
|
||||
impl<E> fmt::Debug for Report<E>
|
||||
where
|
||||
Report<E>: fmt::Display,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper type for indenting the inner source.
|
||||
struct Indented<'a, D> {
|
||||
inner: &'a mut D,
|
||||
}
|
||||
|
||||
impl<T> Write for Indented<'_, T>
|
||||
where
|
||||
T: Write,
|
||||
{
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
for (i, line) in s.split('\n').enumerate() {
|
||||
if i > 0 {
|
||||
self.inner.write_char('\n')?;
|
||||
self.inner.write_str(" ")?;
|
||||
}
|
||||
|
||||
self.inner.write_str(line)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,3 +35,408 @@ fn downcasting() {
|
|||
Err(e) => assert_eq!(*e.downcast::<A>().unwrap(), A),
|
||||
}
|
||||
}
|
||||
|
||||
use crate::backtrace::Backtrace;
|
||||
use crate::error::Report;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct SuperError {
|
||||
source: SuperErrorSideKick,
|
||||
}
|
||||
|
||||
impl fmt::Display for SuperError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "SuperError is here!")
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for SuperError {
|
||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
Some(&self.source)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct SuperErrorSideKick;
|
||||
|
||||
impl fmt::Display for SuperErrorSideKick {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "SuperErrorSideKick is here!")
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for SuperErrorSideKick {}
|
||||
|
||||
#[test]
|
||||
fn single_line_formatting() {
|
||||
let error = SuperError { source: SuperErrorSideKick };
|
||||
let report = Report::new(&error);
|
||||
let actual = report.to_string();
|
||||
let expected = String::from("SuperError is here!: SuperErrorSideKick is here!");
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_line_formatting() {
|
||||
let error = SuperError { source: SuperErrorSideKick };
|
||||
let report = Report::new(&error).pretty(true);
|
||||
let actual = report.to_string();
|
||||
let expected = String::from(
|
||||
"\
|
||||
SuperError is here!
|
||||
|
||||
Caused by:
|
||||
SuperErrorSideKick is here!",
|
||||
);
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_with_no_sources_formats_single_line_correctly() {
|
||||
let report = Report::new(SuperErrorSideKick);
|
||||
let actual = report.to_string();
|
||||
let expected = String::from("SuperErrorSideKick is here!");
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_with_no_sources_formats_multi_line_correctly() {
|
||||
let report = Report::new(SuperErrorSideKick).pretty(true);
|
||||
let actual = report.to_string();
|
||||
let expected = String::from("SuperErrorSideKick is here!");
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_with_backtrace_outputs_correctly_with_one_source() {
|
||||
let trace = Backtrace::force_capture();
|
||||
let expected = format!(
|
||||
"\
|
||||
The source of the error
|
||||
|
||||
Caused by:
|
||||
Error with backtrace
|
||||
|
||||
Stack backtrace:
|
||||
{}",
|
||||
trace
|
||||
);
|
||||
let error = GenericError::new("Error with backtrace");
|
||||
let mut error = GenericError::new_with_source("The source of the error", error);
|
||||
error.backtrace = Some(trace);
|
||||
let report = Report::new(error).pretty(true).show_backtrace(true);
|
||||
|
||||
println!("Error: {}", report);
|
||||
assert_eq!(expected.trim_end(), report.to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_with_backtrace_outputs_correctly_with_two_sources() {
|
||||
let trace = Backtrace::force_capture();
|
||||
let expected = format!(
|
||||
"\
|
||||
Error with two sources
|
||||
|
||||
Caused by:
|
||||
0: The source of the error
|
||||
1: Error with backtrace
|
||||
|
||||
Stack backtrace:
|
||||
{}",
|
||||
trace
|
||||
);
|
||||
let mut error = GenericError::new("Error with backtrace");
|
||||
error.backtrace = Some(trace);
|
||||
let error = GenericError::new_with_source("The source of the error", error);
|
||||
let error = GenericError::new_with_source("Error with two sources", error);
|
||||
let report = Report::new(error).pretty(true).show_backtrace(true);
|
||||
|
||||
println!("Error: {}", report);
|
||||
assert_eq!(expected.trim_end(), report.to_string());
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct GenericError<D> {
|
||||
message: D,
|
||||
backtrace: Option<Backtrace>,
|
||||
source: Option<Box<dyn Error + 'static>>,
|
||||
}
|
||||
|
||||
impl<D> GenericError<D> {
|
||||
fn new(message: D) -> GenericError<D> {
|
||||
Self { message, backtrace: None, source: None }
|
||||
}
|
||||
|
||||
fn new_with_source<E>(message: D, source: E) -> GenericError<D>
|
||||
where
|
||||
E: Error + 'static,
|
||||
{
|
||||
let source: Box<dyn Error + 'static> = Box::new(source);
|
||||
let source = Some(source);
|
||||
GenericError { message, backtrace: None, source }
|
||||
}
|
||||
}
|
||||
|
||||
impl<D> fmt::Display for GenericError<D>
|
||||
where
|
||||
D: fmt::Display,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(&self.message, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<D> Error for GenericError<D>
|
||||
where
|
||||
D: fmt::Debug + fmt::Display,
|
||||
{
|
||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
self.source.as_deref()
|
||||
}
|
||||
|
||||
fn backtrace(&self) -> Option<&Backtrace> {
|
||||
self.backtrace.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_formats_single_line_with_rude_display_impl() {
|
||||
#[derive(Debug)]
|
||||
struct MyMessage;
|
||||
|
||||
impl fmt::Display for MyMessage {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("line 1\nline 2")?;
|
||||
f.write_str("\nline 3\nline 4\n")?;
|
||||
f.write_str("line 5\nline 6")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
let error = GenericError::new(MyMessage);
|
||||
let error = GenericError::new_with_source(MyMessage, error);
|
||||
let error = GenericError::new_with_source(MyMessage, error);
|
||||
let error = GenericError::new_with_source(MyMessage, error);
|
||||
let report = Report::new(error);
|
||||
let expected = "\
|
||||
line 1
|
||||
line 2
|
||||
line 3
|
||||
line 4
|
||||
line 5
|
||||
line 6: line 1
|
||||
line 2
|
||||
line 3
|
||||
line 4
|
||||
line 5
|
||||
line 6: line 1
|
||||
line 2
|
||||
line 3
|
||||
line 4
|
||||
line 5
|
||||
line 6: line 1
|
||||
line 2
|
||||
line 3
|
||||
line 4
|
||||
line 5
|
||||
line 6";
|
||||
|
||||
let actual = report.to_string();
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_formats_multi_line_with_rude_display_impl() {
|
||||
#[derive(Debug)]
|
||||
struct MyMessage;
|
||||
|
||||
impl fmt::Display for MyMessage {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("line 1\nline 2")?;
|
||||
f.write_str("\nline 3\nline 4\n")?;
|
||||
f.write_str("line 5\nline 6")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
let error = GenericError::new(MyMessage);
|
||||
let error = GenericError::new_with_source(MyMessage, error);
|
||||
let error = GenericError::new_with_source(MyMessage, error);
|
||||
let error = GenericError::new_with_source(MyMessage, error);
|
||||
let report = Report::new(error).pretty(true);
|
||||
let expected = "line 1
|
||||
line 2
|
||||
line 3
|
||||
line 4
|
||||
line 5
|
||||
line 6
|
||||
|
||||
Caused by:
|
||||
0: line 1
|
||||
line 2
|
||||
line 3
|
||||
line 4
|
||||
line 5
|
||||
line 6
|
||||
1: line 1
|
||||
line 2
|
||||
line 3
|
||||
line 4
|
||||
line 5
|
||||
line 6
|
||||
2: line 1
|
||||
line 2
|
||||
line 3
|
||||
line 4
|
||||
line 5
|
||||
line 6";
|
||||
|
||||
let actual = report.to_string();
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn errors_that_start_with_newline_formats_correctly() {
|
||||
#[derive(Debug)]
|
||||
struct MyMessage;
|
||||
|
||||
impl fmt::Display for MyMessage {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("\nThe message\n")
|
||||
}
|
||||
}
|
||||
|
||||
let error = GenericError::new(MyMessage);
|
||||
let error = GenericError::new_with_source(MyMessage, error);
|
||||
let error = GenericError::new_with_source(MyMessage, error);
|
||||
let report = Report::new(error).pretty(true);
|
||||
let expected = "
|
||||
The message
|
||||
|
||||
|
||||
Caused by:
|
||||
0: \
|
||||
\n The message
|
||||
\
|
||||
\n 1: \
|
||||
\n The message
|
||||
";
|
||||
|
||||
let actual = report.to_string();
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn errors_with_multiple_writes_on_same_line_dont_insert_erroneous_newlines() {
|
||||
#[derive(Debug)]
|
||||
struct MyMessage;
|
||||
|
||||
impl fmt::Display for MyMessage {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("The message")?;
|
||||
f.write_str(" goes on")?;
|
||||
f.write_str(" and on.")
|
||||
}
|
||||
}
|
||||
|
||||
let error = GenericError::new(MyMessage);
|
||||
let error = GenericError::new_with_source(MyMessage, error);
|
||||
let error = GenericError::new_with_source(MyMessage, error);
|
||||
let report = Report::new(error).pretty(true);
|
||||
let expected = "\
|
||||
The message goes on and on.
|
||||
|
||||
Caused by:
|
||||
0: The message goes on and on.
|
||||
1: The message goes on and on.";
|
||||
|
||||
let actual = report.to_string();
|
||||
println!("{}", actual);
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn errors_with_string_interpolation_formats_correctly() {
|
||||
#[derive(Debug)]
|
||||
struct MyMessage(usize);
|
||||
|
||||
impl fmt::Display for MyMessage {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Got an error code: ({}). ", self.0)?;
|
||||
write!(f, "What would you like to do in response?")
|
||||
}
|
||||
}
|
||||
|
||||
let error = GenericError::new(MyMessage(10));
|
||||
let error = GenericError::new_with_source(MyMessage(20), error);
|
||||
let report = Report::new(error).pretty(true);
|
||||
let expected = "\
|
||||
Got an error code: (20). What would you like to do in response?
|
||||
|
||||
Caused by:
|
||||
Got an error code: (10). What would you like to do in response?";
|
||||
let actual = report.to_string();
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_lines_mid_message() {
|
||||
#[derive(Debug)]
|
||||
struct MyMessage;
|
||||
|
||||
impl fmt::Display for MyMessage {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("line 1\n\nline 2")
|
||||
}
|
||||
}
|
||||
|
||||
let error = GenericError::new(MyMessage);
|
||||
let error = GenericError::new_with_source(MyMessage, error);
|
||||
let error = GenericError::new_with_source(MyMessage, error);
|
||||
let report = Report::new(error).pretty(true);
|
||||
let expected = "\
|
||||
line 1
|
||||
|
||||
line 2
|
||||
|
||||
Caused by:
|
||||
0: line 1
|
||||
\
|
||||
\n line 2
|
||||
1: line 1
|
||||
\
|
||||
\n line 2";
|
||||
|
||||
let actual = report.to_string();
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn only_one_source() {
|
||||
#[derive(Debug)]
|
||||
struct MyMessage;
|
||||
|
||||
impl fmt::Display for MyMessage {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("line 1\nline 2")
|
||||
}
|
||||
}
|
||||
|
||||
let error = GenericError::new(MyMessage);
|
||||
let error = GenericError::new_with_source(MyMessage, error);
|
||||
let report = Report::new(error).pretty(true);
|
||||
let expected = "\
|
||||
line 1
|
||||
line 2
|
||||
|
||||
Caused by:
|
||||
line 1
|
||||
line 2";
|
||||
|
||||
let actual = report.to_string();
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
|||
use rustc_middle::mir::interpret::ConstValue;
|
||||
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
|
||||
use rustc_middle::ty::{self, DefIdTree, TyCtxt};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::source_map::FilePathMapping;
|
||||
use rustc_span::symbol::{kw, sym, Symbol};
|
||||
use std::fmt::Write as _;
|
||||
use std::mem;
|
||||
|
@ -486,20 +488,67 @@ crate const DOC_RUST_LANG_ORG_CHANNEL: &str = env!("DOC_RUST_LANG_ORG_CHANNEL");
|
|||
/// Render a sequence of macro arms in a format suitable for displaying to the user
|
||||
/// as part of an item declaration.
|
||||
pub(super) fn render_macro_arms<'a>(
|
||||
tcx: TyCtxt<'_>,
|
||||
matchers: impl Iterator<Item = &'a TokenTree>,
|
||||
arm_delim: &str,
|
||||
) -> String {
|
||||
let mut out = String::new();
|
||||
for matcher in matchers {
|
||||
writeln!(out, " {} => {{ ... }}{}", render_macro_matcher(matcher), arm_delim).unwrap();
|
||||
writeln!(out, " {} => {{ ... }}{}", render_macro_matcher(tcx, matcher), arm_delim)
|
||||
.unwrap();
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/// Render a macro matcher in a format suitable for displaying to the user
|
||||
/// as part of an item declaration.
|
||||
pub(super) fn render_macro_matcher(matcher: &TokenTree) -> String {
|
||||
rustc_ast_pretty::pprust::tt_to_string(matcher)
|
||||
pub(super) fn render_macro_matcher(tcx: TyCtxt<'_>, matcher: &TokenTree) -> String {
|
||||
if let Some(snippet) = snippet_equal_to_token(tcx, matcher) {
|
||||
snippet
|
||||
} else {
|
||||
rustc_ast_pretty::pprust::tt_to_string(matcher)
|
||||
}
|
||||
}
|
||||
|
||||
/// Find the source snippet for this token's Span, reparse it, and return the
|
||||
/// snippet if the reparsed TokenTree matches the argument TokenTree.
|
||||
fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option<String> {
|
||||
// Find what rustc thinks is the source snippet.
|
||||
// This may not actually be anything meaningful if this matcher was itself
|
||||
// generated by a macro.
|
||||
let source_map = tcx.sess.source_map();
|
||||
let span = matcher.span();
|
||||
let snippet = source_map.span_to_snippet(span).ok()?;
|
||||
|
||||
// Create a Parser.
|
||||
let sess = ParseSess::new(FilePathMapping::empty());
|
||||
let file_name = source_map.span_to_filename(span);
|
||||
let mut parser =
|
||||
match rustc_parse::maybe_new_parser_from_source_str(&sess, file_name, snippet.clone()) {
|
||||
Ok(parser) => parser,
|
||||
Err(diagnostics) => {
|
||||
for mut diagnostic in diagnostics {
|
||||
diagnostic.cancel();
|
||||
}
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
// Reparse a single token tree.
|
||||
let mut reparsed_trees = match parser.parse_all_token_trees() {
|
||||
Ok(reparsed_trees) => reparsed_trees,
|
||||
Err(mut diagnostic) => {
|
||||
diagnostic.cancel();
|
||||
return None;
|
||||
}
|
||||
};
|
||||
if reparsed_trees.len() != 1 {
|
||||
return None;
|
||||
}
|
||||
let reparsed_tree = reparsed_trees.pop().unwrap();
|
||||
|
||||
// Compare against the original tree.
|
||||
if reparsed_tree.eq_unspanned(matcher) { Some(snippet) } else { None }
|
||||
}
|
||||
|
||||
pub(super) fn display_macro_source(
|
||||
|
@ -514,21 +563,21 @@ pub(super) fn display_macro_source(
|
|||
let matchers = tts.chunks(4).map(|arm| &arm[0]);
|
||||
|
||||
if def.macro_rules {
|
||||
format!("macro_rules! {} {{\n{}}}", name, render_macro_arms(matchers, ";"))
|
||||
format!("macro_rules! {} {{\n{}}}", name, render_macro_arms(cx.tcx, matchers, ";"))
|
||||
} else {
|
||||
if matchers.len() <= 1 {
|
||||
format!(
|
||||
"{}macro {}{} {{\n ...\n}}",
|
||||
vis.to_src_with_space(cx.tcx, def_id),
|
||||
name,
|
||||
matchers.map(render_macro_matcher).collect::<String>(),
|
||||
matchers.map(|matcher| render_macro_matcher(cx.tcx, matcher)).collect::<String>(),
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"{}macro {} {{\n{}}}",
|
||||
vis.to_src_with_space(cx.tcx, def_id),
|
||||
name,
|
||||
render_macro_arms(matchers, ","),
|
||||
render_macro_arms(cx.tcx, matchers, ","),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1126,18 +1126,27 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
|
|||
w.write_str("</h3>");
|
||||
|
||||
use crate::clean::Variant;
|
||||
if let Some((extra, fields)) = match *variant.kind {
|
||||
clean::VariantItem(Variant::Struct(ref s)) => Some(("", &s.fields)),
|
||||
clean::VariantItem(Variant::Tuple(ref fields)) => Some(("Tuple ", fields)),
|
||||
|
||||
let heading_and_fields = match &*variant.kind {
|
||||
clean::VariantItem(Variant::Struct(s)) => Some(("Fields", &s.fields)),
|
||||
// Documentation on tuple variant fields is rare, so to reduce noise we only emit
|
||||
// the section if at least one field is documented.
|
||||
clean::VariantItem(Variant::Tuple(fields))
|
||||
if fields.iter().any(|f| f.doc_value().is_some()) =>
|
||||
{
|
||||
Some(("Tuple Fields", fields))
|
||||
}
|
||||
_ => None,
|
||||
} {
|
||||
};
|
||||
|
||||
if let Some((heading, fields)) = heading_and_fields {
|
||||
let variant_id = cx.derive_id(format!(
|
||||
"{}.{}.fields",
|
||||
ItemType::Variant,
|
||||
variant.name.as_ref().unwrap()
|
||||
));
|
||||
write!(w, "<div class=\"sub-variant\" id=\"{id}\">", id = variant_id);
|
||||
write!(w, "<h4>{extra}Fields</h4>", extra = extra,);
|
||||
write!(w, "<h4>{heading}</h4>", heading = heading);
|
||||
document_non_exhaustive(w, variant);
|
||||
for field in fields {
|
||||
match *field.kind {
|
||||
|
|
|
@ -64,7 +64,7 @@ endif
|
|||
# if and when we allow `llvm-cov` to produce results for multiple files. Note, the path separators
|
||||
# appear to be normalized to `/` in those files, thankfully.)
|
||||
LLVM_COV_IGNORE_FILES=\
|
||||
--ignore-filename-regex='(uses_crate.rs|uses_inline_crate.rs)'
|
||||
--ignore-filename-regex='(uses_crate.rs|uses_inline_crate.rs|unused_mod.rs)'
|
||||
|
||||
all: $(patsubst $(SOURCEDIR)/lib/%.rs,%,$(wildcard $(SOURCEDIR)/lib/*.rs)) $(patsubst $(SOURCEDIR)/%.rs,%,$(wildcard $(SOURCEDIR)/*.rs))
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
1| 0|pub fn never_called_function() {
|
||||
2| 0| println!("I am never called");
|
||||
3| 0|}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
pub fn never_called_function() {
|
||||
println!("I am never called");
|
||||
}
|
6
src/test/run-make-fulldeps/coverage/unused_mod.rs
Normal file
6
src/test/run-make-fulldeps/coverage/unused_mod.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
#[path = "lib/unused_mod_helper.rs"]
|
||||
mod unused_module;
|
||||
|
||||
fn main() {
|
||||
println!("hello world!");
|
||||
}
|
|
@ -9,7 +9,7 @@ pub macro my_macro() {
|
|||
|
||||
}
|
||||
|
||||
// @has decl_macro/macro.my_macro_2.html //pre 'pub macro my_macro_2($($tok : tt) *) {'
|
||||
// @has decl_macro/macro.my_macro_2.html //pre 'pub macro my_macro_2($($tok:tt)*) {'
|
||||
// @has - //pre '...'
|
||||
// @has - //pre '}'
|
||||
pub macro my_macro_2($($tok:tt)*) {
|
||||
|
@ -18,8 +18,8 @@ pub macro my_macro_2($($tok:tt)*) {
|
|||
|
||||
// @has decl_macro/macro.my_macro_multi.html //pre 'pub macro my_macro_multi {'
|
||||
// @has - //pre '(_) => { ... },'
|
||||
// @has - //pre '($foo : ident.$bar : expr) => { ... },'
|
||||
// @has - //pre '($($foo : literal), +) => { ... },'
|
||||
// @has - //pre '($foo:ident . $bar:expr) => { ... },'
|
||||
// @has - //pre '($($foo:literal),+) => { ... },'
|
||||
// @has - //pre '}'
|
||||
pub macro my_macro_multi {
|
||||
(_) => {
|
||||
|
@ -33,7 +33,7 @@ pub macro my_macro_multi {
|
|||
}
|
||||
}
|
||||
|
||||
// @has decl_macro/macro.by_example_single.html //pre 'pub macro by_example_single($foo : expr) {'
|
||||
// @has decl_macro/macro.by_example_single.html //pre 'pub macro by_example_single($foo:expr) {'
|
||||
// @has - //pre '...'
|
||||
// @has - //pre '}'
|
||||
pub macro by_example_single {
|
||||
|
@ -42,12 +42,12 @@ pub macro by_example_single {
|
|||
|
||||
mod a {
|
||||
mod b {
|
||||
// @has decl_macro/a/b/macro.by_example_vis.html //pre 'pub(super) macro by_example_vis($foo : expr) {'
|
||||
// @has decl_macro/a/b/macro.by_example_vis.html //pre 'pub(super) macro by_example_vis($foo:expr) {'
|
||||
pub(in super) macro by_example_vis {
|
||||
($foo:expr) => {}
|
||||
}
|
||||
mod c {
|
||||
// @has decl_macro/a/b/c/macro.by_example_vis_named.html //pre 'pub(in a) macro by_example_vis_named($foo : expr) {'
|
||||
// @has decl_macro/a/b/c/macro.by_example_vis_named.html //pre 'pub(in a) macro by_example_vis_named($foo:expr) {'
|
||||
pub(in a) macro by_example_vis_named {
|
||||
($foo:expr) => {}
|
||||
}
|
||||
|
|
|
@ -18,17 +18,18 @@ pub enum FooEnum {
|
|||
// @has - '//*[@id="variant.MixedHiddenFirst"]//code' 'MixedHiddenFirst(_, S)'
|
||||
// @count - '//*[@id="variant.MixedHiddenFirst.field.0"]' 0
|
||||
// @has - '//*[@id="variant.MixedHiddenFirst.field.1"]' '1: S'
|
||||
MixedHiddenFirst(#[doc(hidden)] H, S),
|
||||
MixedHiddenFirst(#[doc(hidden)] H, /** dox */ S),
|
||||
// @has - '//*[@id="variant.MixedHiddenLast"]//code' 'MixedHiddenLast(S, _)'
|
||||
// @has - '//*[@id="variant.MixedHiddenLast.field.0"]' '0: S'
|
||||
// @count - '//*[@id="variant.MixedHiddenLast.field.1"]' 0
|
||||
MixedHiddenLast(S, #[doc(hidden)] H),
|
||||
MixedHiddenLast(/** dox */ S, #[doc(hidden)] H),
|
||||
// @has - '//*[@id="variant.HiddenStruct"]//code' 'HiddenStruct'
|
||||
// @count - '//*[@id="variant.HiddenStruct.field.h"]' 0
|
||||
// @has - '//*[@id="variant.HiddenStruct.field.s"]' 's: S'
|
||||
HiddenStruct {
|
||||
#[doc(hidden)]
|
||||
h: H,
|
||||
/// dox
|
||||
s: S,
|
||||
},
|
||||
}
|
||||
|
|
14
src/test/rustdoc/macro-generated-macro.rs
Normal file
14
src/test/rustdoc/macro-generated-macro.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
macro_rules! outer {
|
||||
($($matcher:tt)*) => {
|
||||
#[macro_export]
|
||||
macro_rules! inner {
|
||||
(<= $($matcher)* =>) => {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// @has macro_generated_macro/macro.inner.html //pre 'macro_rules! inner {'
|
||||
// @has - //pre '(<= type $($i : ident) :: * + $e : expr =>) => { ... };'
|
||||
outer!(type $($i:ident)::* + $e:expr);
|
||||
|
||||
inner!(<= type foo::bar + x.sort() =>);
|
|
@ -1,7 +1,7 @@
|
|||
// @has macros/macro.my_macro.html //pre 'macro_rules! my_macro {'
|
||||
// @has - //pre '() => { ... };'
|
||||
// @has - //pre '($a : tt) => { ... };'
|
||||
// @has - //pre '($e : expr) => { ... };'
|
||||
// @has - //pre '($a:tt) => { ... };'
|
||||
// @has - //pre '($e:expr) => { ... };'
|
||||
#[macro_export]
|
||||
macro_rules! my_macro {
|
||||
() => [];
|
||||
|
@ -12,8 +12,8 @@ macro_rules! my_macro {
|
|||
// Check that exported macro defined in a module are shown at crate root.
|
||||
// @has macros/macro.my_sub_macro.html //pre 'macro_rules! my_sub_macro {'
|
||||
// @has - //pre '() => { ... };'
|
||||
// @has - //pre '($a : tt) => { ... };'
|
||||
// @has - //pre '($e : expr) => { ... };'
|
||||
// @has - //pre '($a:tt) => { ... };'
|
||||
// @has - //pre '($e:expr) => { ... };'
|
||||
mod sub {
|
||||
#[macro_export]
|
||||
macro_rules! my_sub_macro {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
extern crate reexports;
|
||||
|
||||
// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {'
|
||||
// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {'
|
||||
pub use reexports::addr_of;
|
||||
// @!has 'foo/macro.addr_of_crate.html'
|
||||
pub(crate) use reexports::addr_of_crate;
|
||||
|
@ -61,11 +61,11 @@ use reexports::UnionLocal;
|
|||
|
||||
pub mod outer {
|
||||
pub mod inner {
|
||||
// @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {'
|
||||
// @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {'
|
||||
pub use reexports::addr_of;
|
||||
// @has 'foo/outer/inner/macro.addr_of_crate.html' '//*[@class="docblock item-decl"]' 'pub(crate) macro addr_of_crate($place : expr) {'
|
||||
// @has 'foo/outer/inner/macro.addr_of_crate.html' '//*[@class="docblock item-decl"]' 'pub(crate) macro addr_of_crate($place:expr) {'
|
||||
pub(crate) use reexports::addr_of_crate;
|
||||
// @has 'foo/outer/inner/macro.addr_of_super.html' '//*[@class="docblock item-decl"]' 'pub(in outer) macro addr_of_super($place : expr) {'
|
||||
// @has 'foo/outer/inner/macro.addr_of_super.html' '//*[@class="docblock item-decl"]' 'pub(in outer) macro addr_of_super($place:expr) {'
|
||||
pub(super) use reexports::addr_of_super;
|
||||
// @!has 'foo/outer/inner/macro.addr_of_self.html'
|
||||
pub(self) use reexports::addr_of_self;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
extern crate reexports;
|
||||
|
||||
// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {'
|
||||
// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {'
|
||||
pub use reexports::addr_of;
|
||||
// @!has 'foo/macro.addr_of_crate.html'
|
||||
pub(crate) use reexports::addr_of_crate;
|
||||
|
@ -60,7 +60,7 @@ use reexports::UnionLocal;
|
|||
|
||||
pub mod outer {
|
||||
pub mod inner {
|
||||
// @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {'
|
||||
// @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {'
|
||||
pub use reexports::addr_of;
|
||||
// @!has 'foo/outer/inner/macro.addr_of_crate.html'
|
||||
pub(crate) use reexports::addr_of_crate;
|
||||
|
|
|
@ -24,6 +24,9 @@ pub struct Foo(
|
|||
// @has - '//*[@id="variant.BarVariant.field.0"]' '0: String'
|
||||
// @has - '//*[@id="variant.BarVariant.fields"]//*[@class="docblock"]' 'Hello docs'
|
||||
// @matches - '//*[@id="variant.FooVariant.fields"]/h4' '^Fields$'
|
||||
// @has - '//*[@id="variant.BazVariant.fields"]//*[@class="docblock"]' 'dox'
|
||||
// @has - '//*[@id="variant.OtherVariant.fields"]//*[@class="docblock"]' 'dox'
|
||||
// @!matches - '//*[@id="variant.QuuxVariant.fields"]/h4' '^Tuple Fields$'
|
||||
pub enum Bar {
|
||||
BarVariant(
|
||||
/// Hello docs
|
||||
|
@ -33,4 +36,15 @@ pub enum Bar {
|
|||
/// hello
|
||||
x: u32,
|
||||
},
|
||||
BazVariant(
|
||||
String,
|
||||
/// dox
|
||||
u32,
|
||||
),
|
||||
OtherVariant(
|
||||
/// dox
|
||||
String,
|
||||
u32,
|
||||
),
|
||||
QuuxVariant(String),
|
||||
}
|
||||
|
|
|
@ -15,9 +15,5 @@ impl<W> Trait<W> for () {}
|
|||
|
||||
fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
|
||||
//~^ ERROR non-defining opaque type use in defining scope
|
||||
//~| ERROR non-defining opaque type use in defining scope
|
||||
//~| ERROR non-defining opaque type use in defining scope
|
||||
//~| ERROR `T` is part of concrete type but not used in parameter list
|
||||
//~| ERROR `T` is part of concrete type but not used in parameter list
|
||||
()
|
||||
}
|
||||
|
|
|
@ -1,34 +1,8 @@
|
|||
error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
|
||||
--> $DIR/bound_reduction2.rs:16:60
|
||||
|
|
||||
LL | fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
|
||||
| ____________________________________________________________^
|
||||
LL | |
|
||||
LL | |
|
||||
LL | |
|
||||
... |
|
||||
LL | | ()
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
|
||||
--> $DIR/bound_reduction2.rs:16:60
|
||||
|
|
||||
LL | fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
|
||||
| ____________________________________________________________^
|
||||
LL | |
|
||||
LL | |
|
||||
LL | |
|
||||
... |
|
||||
LL | | ()
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: non-defining opaque type use in defining scope
|
||||
--> $DIR/bound_reduction2.rs:16:1
|
||||
--> $DIR/bound_reduction2.rs:16:46
|
||||
|
|
||||
LL | fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
note: used non-generic type `<T as TraitWithAssoc>::Assoc` for generic parameter
|
||||
--> $DIR/bound_reduction2.rs:9:10
|
||||
|
@ -36,35 +10,11 @@ note: used non-generic type `<T as TraitWithAssoc>::Assoc` for generic parameter
|
|||
LL | type Foo<V> = impl Trait<V>;
|
||||
| ^
|
||||
|
||||
error: non-defining opaque type use in defining scope
|
||||
--> $DIR/bound_reduction2.rs:16:1
|
||||
|
|
||||
LL | fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: used non-generic type `_` for generic parameter
|
||||
--> $DIR/bound_reduction2.rs:9:10
|
||||
|
|
||||
LL | type Foo<V> = impl Trait<V>;
|
||||
| ^
|
||||
|
||||
error: non-defining opaque type use in defining scope
|
||||
--> $DIR/bound_reduction2.rs:16:1
|
||||
|
|
||||
LL | fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: used non-generic type `_` for generic parameter
|
||||
--> $DIR/bound_reduction2.rs:9:10
|
||||
|
|
||||
LL | type Foo<V> = impl Trait<V>;
|
||||
| ^
|
||||
|
||||
error: could not find defining uses
|
||||
--> $DIR/bound_reduction2.rs:9:15
|
||||
|
|
||||
LL | type Foo<V> = impl Trait<V>;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 358e79fe56fe374649275ca7aebaafd57ade0e8d
|
||||
Subproject commit 06b9d31743210b788b130c8a484c2838afa6fc27
|
|
@ -73,6 +73,7 @@ const RESTRICTED_DEPENDENCY_CRATES: &[&str] = &["rustc_driver", "rustc_codegen_l
|
|||
const PERMITTED_DEPENDENCIES: &[&str] = &[
|
||||
"addr2line",
|
||||
"adler",
|
||||
"ahash",
|
||||
"aho-corasick",
|
||||
"annotate-snippets",
|
||||
"ansi_term",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue