mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-15 13:36:49 +00:00
Auto merge of #83855 - Dylan-DPC:rollup-oww62sh, r=Dylan-DPC
Rollup of 8 pull requests Successful merges: - #73945 (Add an unstable --json=unused-externs flag to print unused externs) - #81619 (Implement `SourceIterator` and `InPlaceIterable` for `ResultShunt`) - #82726 (BTree: move blocks around in node.rs) - #83521 (2229: Fix diagnostic issue when using FakeReads in closures) - #83532 (Fix compiletest on FreeBSD) - #83793 (rustdoc: highlight macros more efficiently) - #83809 (Remove unneeded INITIAL_IDS const) - #83827 (cleanup leak after test to make miri happy) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
8ad6a443cf
@ -195,6 +195,9 @@ pub trait Emitter {
|
||||
|
||||
fn emit_future_breakage_report(&mut self, _diags: Vec<(FutureBreakage, Diagnostic)>) {}
|
||||
|
||||
/// Emit list of unused externs
|
||||
fn emit_unused_externs(&mut self, _lint_level: &str, _unused_externs: &[&str]) {}
|
||||
|
||||
/// Checks if should show explanations about "rustc --explain"
|
||||
fn should_show_explain(&self) -> bool {
|
||||
true
|
||||
|
@ -159,6 +159,19 @@ impl Emitter for JsonEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_unused_externs(&mut self, lint_level: &str, unused_externs: &[&str]) {
|
||||
let data = UnusedExterns { lint_level, unused_extern_names: unused_externs };
|
||||
let result = if self.pretty {
|
||||
writeln!(&mut self.dst, "{}", as_pretty_json(&data))
|
||||
} else {
|
||||
writeln!(&mut self.dst, "{}", as_json(&data))
|
||||
}
|
||||
.and_then(|_| self.dst.flush());
|
||||
if let Err(e) = result {
|
||||
panic!("failed to print unused externs: {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
fn source_map(&self) -> Option<&Lrc<SourceMap>> {
|
||||
Some(&self.sm)
|
||||
}
|
||||
@ -322,6 +335,18 @@ struct FutureIncompatReport {
|
||||
future_incompat_report: Vec<FutureBreakageItem>,
|
||||
}
|
||||
|
||||
// NOTE: Keep this in sync with the equivalent structs in rustdoc's
|
||||
// doctest component (as well as cargo).
|
||||
// We could unify this struct the one in rustdoc but they have different
|
||||
// ownership semantics, so doing so would create wasteful allocations.
|
||||
#[derive(Encodable)]
|
||||
struct UnusedExterns<'a, 'b, 'c> {
|
||||
/// The severity level of the unused dependencies lint
|
||||
lint_level: &'a str,
|
||||
/// List of unused externs by their names.
|
||||
unused_extern_names: &'b [&'c str],
|
||||
}
|
||||
|
||||
impl Diagnostic {
|
||||
fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> Diagnostic {
|
||||
let sugg = diag.suggestions.iter().map(|sugg| Diagnostic {
|
||||
|
@ -765,6 +765,10 @@ impl Handler {
|
||||
self.inner.borrow_mut().emitter.emit_future_breakage_report(diags)
|
||||
}
|
||||
|
||||
pub fn emit_unused_externs(&self, lint_level: &str, unused_externs: &[&str]) {
|
||||
self.inner.borrow_mut().emit_unused_externs(lint_level, unused_externs)
|
||||
}
|
||||
|
||||
pub fn delay_as_bug(&self, diagnostic: Diagnostic) {
|
||||
self.inner.borrow_mut().delay_as_bug(diagnostic)
|
||||
}
|
||||
@ -839,6 +843,10 @@ impl HandlerInner {
|
||||
self.emitter.emit_artifact_notification(path, artifact_type);
|
||||
}
|
||||
|
||||
fn emit_unused_externs(&mut self, lint_level: &str, unused_externs: &[&str]) {
|
||||
self.emitter.emit_unused_externs(lint_level, unused_externs);
|
||||
}
|
||||
|
||||
fn treat_err_as_bug(&self) -> bool {
|
||||
self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() >= c.get())
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
use rustc_hir::definitions::Definitions;
|
||||
use rustc_hir::Crate;
|
||||
use rustc_lint::LintStore;
|
||||
use rustc_metadata::creader::CStore;
|
||||
use rustc_middle::arena::Arena;
|
||||
use rustc_middle::dep_graph::DepGraph;
|
||||
use rustc_middle::middle;
|
||||
@ -831,6 +832,12 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
|
||||
});
|
||||
|
||||
sess.time("looking_for_derive_registrar", || proc_macro_decls::find(tcx));
|
||||
|
||||
let cstore = tcx
|
||||
.cstore_as_any()
|
||||
.downcast_ref::<CStore>()
|
||||
.expect("`tcx.cstore` is not a `CStore`");
|
||||
cstore.report_unused_deps(tcx);
|
||||
},
|
||||
{
|
||||
par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
|
||||
|
@ -46,6 +46,9 @@ pub struct CStore {
|
||||
/// This map is used to verify we get no hash conflicts between
|
||||
/// `StableCrateId` values.
|
||||
stable_crate_ids: FxHashMap<StableCrateId, CrateNum>,
|
||||
|
||||
/// Unused externs of the crate
|
||||
unused_externs: Vec<Symbol>,
|
||||
}
|
||||
|
||||
pub struct CrateLoader<'a> {
|
||||
@ -190,6 +193,27 @@ impl CStore {
|
||||
crate fn has_global_allocator(&self) -> bool {
|
||||
self.has_global_allocator
|
||||
}
|
||||
|
||||
pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) {
|
||||
// We put the check for the option before the lint_level_at_node call
|
||||
// because the call mutates internal state and introducing it
|
||||
// leads to some ui tests failing.
|
||||
if !tcx.sess.opts.json_unused_externs {
|
||||
return;
|
||||
}
|
||||
let level = tcx
|
||||
.lint_level_at_node(lint::builtin::UNUSED_CRATE_DEPENDENCIES, rustc_hir::CRATE_HIR_ID)
|
||||
.0;
|
||||
if level != lint::Level::Allow {
|
||||
let unused_externs =
|
||||
self.unused_externs.iter().map(|ident| ident.to_ident_string()).collect::<Vec<_>>();
|
||||
let unused_externs = unused_externs.iter().map(String::as_str).collect::<Vec<&str>>();
|
||||
tcx.sess
|
||||
.parse_sess
|
||||
.span_diagnostic
|
||||
.emit_unused_externs(level.as_str(), &unused_externs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> CrateLoader<'a> {
|
||||
@ -217,6 +241,7 @@ impl<'a> CrateLoader<'a> {
|
||||
allocator_kind: None,
|
||||
has_global_allocator: false,
|
||||
stable_crate_ids,
|
||||
unused_externs: Vec::new(),
|
||||
},
|
||||
used_extern_options: Default::default(),
|
||||
}
|
||||
@ -904,11 +929,17 @@ impl<'a> CrateLoader<'a> {
|
||||
// Don't worry about pathless `--extern foo` sysroot references
|
||||
continue;
|
||||
}
|
||||
if self.used_extern_options.contains(&Symbol::intern(name)) {
|
||||
let name_interned = Symbol::intern(name);
|
||||
if self.used_extern_options.contains(&name_interned) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Got a real unused --extern
|
||||
if self.sess.opts.json_unused_externs {
|
||||
self.cstore.unused_externs.push(name_interned);
|
||||
continue;
|
||||
}
|
||||
|
||||
let diag = match self.sess.opts.extern_dep_specs.get(name) {
|
||||
Some(loc) => BuiltinLintDiagnostics::ExternDepSpec(name.clone(), loc.into()),
|
||||
None => {
|
||||
@ -941,9 +972,9 @@ impl<'a> CrateLoader<'a> {
|
||||
self.inject_allocator_crate(krate);
|
||||
self.inject_panic_runtime(krate);
|
||||
|
||||
info!("{:?}", CrateDump(&self.cstore));
|
||||
|
||||
self.report_unused_deps(krate);
|
||||
|
||||
info!("{:?}", CrateDump(&self.cstore));
|
||||
}
|
||||
|
||||
pub fn process_extern_crate(
|
||||
|
@ -1482,7 +1482,7 @@ pub enum StatementKind<'tcx> {
|
||||
///
|
||||
/// Note that this also is emitted for regular `let` bindings to ensure that locals that are
|
||||
/// never accessed still get some sanity checks for, e.g., `let x: ! = ..;`
|
||||
FakeRead(FakeReadCause, Box<Place<'tcx>>),
|
||||
FakeRead(Box<(FakeReadCause, Place<'tcx>)>),
|
||||
|
||||
/// Write the discriminant for a variant to the enum Place.
|
||||
SetDiscriminant { place: Box<Place<'tcx>>, variant_index: VariantIdx },
|
||||
@ -1575,7 +1575,12 @@ pub enum FakeReadCause {
|
||||
|
||||
/// `let x: !; match x {}` doesn't generate any read of x so we need to
|
||||
/// generate a read of x to check that it is initialized and safe.
|
||||
ForMatchedPlace,
|
||||
///
|
||||
/// If a closure pattern matches a Place starting with an Upvar, then we introduce a
|
||||
/// FakeRead for that Place outside the closure, in such a case this option would be
|
||||
/// Some(closure_def_id).
|
||||
/// Otherwise, the value of the optional DefId will be None.
|
||||
ForMatchedPlace(Option<DefId>),
|
||||
|
||||
/// A fake read of the RefWithinGuard version of a bind-by-value variable
|
||||
/// in a match guard to ensure that it's value hasn't change by the time
|
||||
@ -1594,7 +1599,12 @@ pub enum FakeReadCause {
|
||||
/// but in some cases it can affect the borrow checker, as in #53695.
|
||||
/// Therefore, we insert a "fake read" here to ensure that we get
|
||||
/// appropriate errors.
|
||||
ForLet,
|
||||
///
|
||||
/// If a closure pattern matches a Place starting with an Upvar, then we introduce a
|
||||
/// FakeRead for that Place outside the closure, in such a case this option would be
|
||||
/// Some(closure_def_id).
|
||||
/// Otherwise, the value of the optional DefId will be None.
|
||||
ForLet(Option<DefId>),
|
||||
|
||||
/// If we have an index expression like
|
||||
///
|
||||
@ -1618,7 +1628,9 @@ impl Debug for Statement<'_> {
|
||||
use self::StatementKind::*;
|
||||
match self.kind {
|
||||
Assign(box (ref place, ref rv)) => write!(fmt, "{:?} = {:?}", place, rv),
|
||||
FakeRead(ref cause, ref place) => write!(fmt, "FakeRead({:?}, {:?})", cause, place),
|
||||
FakeRead(box (ref cause, ref place)) => {
|
||||
write!(fmt, "FakeRead({:?}, {:?})", cause, place)
|
||||
}
|
||||
Retag(ref kind, ref place) => write!(
|
||||
fmt,
|
||||
"Retag({}{:?})",
|
||||
|
@ -380,7 +380,7 @@ macro_rules! make_mir_visitor {
|
||||
) => {
|
||||
self.visit_assign(place, rvalue, location);
|
||||
}
|
||||
StatementKind::FakeRead(_, place) => {
|
||||
StatementKind::FakeRead(box (_, place)) => {
|
||||
self.visit_place(
|
||||
place,
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
|
||||
|
@ -1728,7 +1728,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for FakeReadCauseFinder<'tcx> {
|
||||
fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) {
|
||||
match statement {
|
||||
Statement { kind: StatementKind::FakeRead(cause, box place), .. }
|
||||
Statement { kind: StatementKind::FakeRead(box (cause, place)), .. }
|
||||
if *place == self.place =>
|
||||
{
|
||||
self.cause = Some(*cause);
|
||||
|
@ -515,7 +515,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
let block = &self.body.basic_blocks()[location.block];
|
||||
|
||||
let kind = if let Some(&Statement {
|
||||
kind: StatementKind::FakeRead(FakeReadCause::ForLet, _),
|
||||
kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), _)),
|
||||
..
|
||||
}) = block.statements.get(location.statement_index)
|
||||
{
|
||||
|
@ -7,8 +7,8 @@ use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::LangItemGroup;
|
||||
use rustc_hir::GeneratorKind;
|
||||
use rustc_middle::mir::{
|
||||
AggregateKind, Constant, Field, Local, LocalInfo, LocalKind, Location, Operand, Place,
|
||||
PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
|
||||
AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand,
|
||||
Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
|
||||
};
|
||||
use rustc_middle::ty::print::Print;
|
||||
use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
|
||||
@ -795,6 +795,24 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
// StatementKind::FakeRead only contains a def_id if they are introduced as a result
|
||||
// of pattern matching within a closure.
|
||||
if let StatementKind::FakeRead(box (cause, ref place)) = stmt.kind {
|
||||
match cause {
|
||||
FakeReadCause::ForMatchedPlace(Some(closure_def_id))
|
||||
| FakeReadCause::ForLet(Some(closure_def_id)) => {
|
||||
debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place);
|
||||
let places = &[Operand::Move(*place)];
|
||||
if let Some((args_span, generator_kind, var_span)) =
|
||||
self.closure_span(closure_def_id, moved_place, places)
|
||||
{
|
||||
return ClosureUse { generator_kind, args_span, var_span };
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let normal_ret =
|
||||
if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) {
|
||||
PatUse(stmt.source_info.span)
|
||||
|
@ -63,7 +63,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||
|
||||
self.mutate_place(location, *lhs, Shallow(None), JustWrite);
|
||||
}
|
||||
StatementKind::FakeRead(_, _) => {
|
||||
StatementKind::FakeRead(box (_, _)) => {
|
||||
// Only relevant for initialized/liveness/safety checks.
|
||||
}
|
||||
StatementKind::SetDiscriminant { place, variant_index: _ } => {
|
||||
|
@ -574,7 +574,7 @@ impl<'cx, 'tcx> dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tc
|
||||
|
||||
self.mutate_place(location, (*lhs, span), Shallow(None), JustWrite, flow_state);
|
||||
}
|
||||
StatementKind::FakeRead(_, box ref place) => {
|
||||
StatementKind::FakeRead(box (_, ref place)) => {
|
||||
// Read for match doesn't access any memory and is used to
|
||||
// assert that a place is safe and live. So we don't have to
|
||||
// do any checks here.
|
||||
|
@ -293,8 +293,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||
}
|
||||
self.gather_rvalue(rval);
|
||||
}
|
||||
StatementKind::FakeRead(_, place) => {
|
||||
self.create_move_path(**place);
|
||||
StatementKind::FakeRead(box (_, place)) => {
|
||||
self.create_move_path(*place);
|
||||
}
|
||||
StatementKind::LlvmInlineAsm(ref asm) => {
|
||||
for (output, kind) in iter::zip(&*asm.outputs, &asm.asm.outputs) {
|
||||
|
@ -683,10 +683,10 @@ pub(super) fn filtered_statement_span(
|
||||
// and `_1` is the `Place` for `somenum`.
|
||||
//
|
||||
// If and when the Issue is resolved, remove this special case match pattern:
|
||||
StatementKind::FakeRead(cause, _) if cause == FakeReadCause::ForGuardBinding => None,
|
||||
StatementKind::FakeRead(box (cause, _)) if cause == FakeReadCause::ForGuardBinding => None,
|
||||
|
||||
// Retain spans from all other statements
|
||||
StatementKind::FakeRead(_, _) // Not including `ForGuardBinding`
|
||||
StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding`
|
||||
| StatementKind::CopyNonOverlapping(..)
|
||||
| StatementKind::Assign(_)
|
||||
| StatementKind::SetDiscriminant { .. }
|
||||
|
@ -80,7 +80,7 @@ impl<'tcx> CFG<'tcx> {
|
||||
cause: FakeReadCause,
|
||||
place: Place<'tcx>,
|
||||
) {
|
||||
let kind = StatementKind::FakeRead(cause, box place);
|
||||
let kind = StatementKind::FakeRead(box (cause, place));
|
||||
let stmt = Statement { source_info, kind };
|
||||
self.push(block, stmt);
|
||||
}
|
||||
|
@ -179,24 +179,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
// match x { _ => () } // fake read of `x`
|
||||
// };
|
||||
// ```
|
||||
// FIXME(RFC2229): Remove feature gate once diagnostics are improved
|
||||
if this.tcx.features().capture_disjoint_fields {
|
||||
for (thir_place, cause, hir_id) in fake_reads.into_iter() {
|
||||
let place_builder =
|
||||
unpack!(block = this.as_place_builder(block, thir_place));
|
||||
for (thir_place, cause, hir_id) in fake_reads.into_iter() {
|
||||
let place_builder = unpack!(block = this.as_place_builder(block, thir_place));
|
||||
|
||||
if let Ok(place_builder_resolved) =
|
||||
place_builder.try_upvars_resolved(this.tcx, this.typeck_results)
|
||||
{
|
||||
let mir_place =
|
||||
place_builder_resolved.into_place(this.tcx, this.typeck_results);
|
||||
this.cfg.push_fake_read(
|
||||
block,
|
||||
this.source_info(this.tcx.hir().span(*hir_id)),
|
||||
*cause,
|
||||
mir_place,
|
||||
);
|
||||
}
|
||||
if let Ok(place_builder_resolved) =
|
||||
place_builder.try_upvars_resolved(this.tcx, this.typeck_results)
|
||||
{
|
||||
let mir_place =
|
||||
place_builder_resolved.into_place(this.tcx, this.typeck_results);
|
||||
this.cfg.push_fake_read(
|
||||
block,
|
||||
this.source_info(this.tcx.hir().span(*hir_id)),
|
||||
*cause,
|
||||
mir_place,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,7 +139,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
// uninhabited value. If we get never patterns, those will check that
|
||||
// the place is initialized, and so this read would only be used to
|
||||
// check safety.
|
||||
let cause_matched_place = FakeReadCause::ForMatchedPlace;
|
||||
let cause_matched_place = FakeReadCause::ForMatchedPlace(None);
|
||||
let source_info = self.source_info(scrutinee_span);
|
||||
|
||||
if let Ok(scrutinee_builder) =
|
||||
@ -400,7 +400,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
|
||||
// Inject a fake read, see comments on `FakeReadCause::ForLet`.
|
||||
let source_info = self.source_info(irrefutable_pat.span);
|
||||
self.cfg.push_fake_read(block, source_info, FakeReadCause::ForLet, place);
|
||||
self.cfg.push_fake_read(block, source_info, FakeReadCause::ForLet(None), place);
|
||||
|
||||
self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard);
|
||||
block.unit()
|
||||
@ -435,7 +435,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
|
||||
// Inject a fake read, see comments on `FakeReadCause::ForLet`.
|
||||
let pattern_source_info = self.source_info(irrefutable_pat.span);
|
||||
let cause_let = FakeReadCause::ForLet;
|
||||
let cause_let = FakeReadCause::ForLet(None);
|
||||
self.cfg.push_fake_read(block, pattern_source_info, cause_let, place);
|
||||
|
||||
let ty_source_info = self.source_info(user_ty_span);
|
||||
|
@ -456,6 +456,10 @@ impl Externs {
|
||||
pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
|
||||
self.0.iter()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternEntry {
|
||||
@ -698,6 +702,7 @@ impl Default for Options {
|
||||
remap_path_prefix: Vec::new(),
|
||||
edition: DEFAULT_EDITION,
|
||||
json_artifact_notifications: false,
|
||||
json_unused_externs: false,
|
||||
pretty: None,
|
||||
}
|
||||
}
|
||||
@ -1196,15 +1201,23 @@ pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/// Possible json config files
|
||||
pub struct JsonConfig {
|
||||
pub json_rendered: HumanReadableErrorType,
|
||||
pub json_artifact_notifications: bool,
|
||||
pub json_unused_externs: bool,
|
||||
}
|
||||
|
||||
/// Parse the `--json` flag.
|
||||
///
|
||||
/// The first value returned is how to render JSON diagnostics, and the second
|
||||
/// is whether or not artifact notifications are enabled.
|
||||
pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
|
||||
pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
|
||||
let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
|
||||
HumanReadableErrorType::Default;
|
||||
let mut json_color = ColorConfig::Never;
|
||||
let mut json_artifact_notifications = false;
|
||||
let mut json_unused_externs = false;
|
||||
for option in matches.opt_strs("json") {
|
||||
// For now conservatively forbid `--color` with `--json` since `--json`
|
||||
// won't actually be emitting any colors and anything colorized is
|
||||
@ -1221,6 +1234,7 @@ pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool)
|
||||
"diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
|
||||
"diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
|
||||
"artifacts" => json_artifact_notifications = true,
|
||||
"unused-externs" => json_unused_externs = true,
|
||||
s => early_error(
|
||||
ErrorOutputType::default(),
|
||||
&format!("unknown `--json` option `{}`", s),
|
||||
@ -1228,7 +1242,12 @@ pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool)
|
||||
}
|
||||
}
|
||||
}
|
||||
(json_rendered(json_color), json_artifact_notifications)
|
||||
|
||||
JsonConfig {
|
||||
json_rendered: json_rendered(json_color),
|
||||
json_artifact_notifications,
|
||||
json_unused_externs,
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses the `--error-format` flag.
|
||||
@ -1806,7 +1825,8 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||
|
||||
let edition = parse_crate_edition(matches);
|
||||
|
||||
let (json_rendered, json_artifact_notifications) = parse_json(matches);
|
||||
let JsonConfig { json_rendered, json_artifact_notifications, json_unused_externs } =
|
||||
parse_json(matches);
|
||||
|
||||
let error_format = parse_error_format(matches, color, json_rendered);
|
||||
|
||||
@ -1819,6 +1839,14 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||
let mut debugging_opts = build_debugging_options(matches, error_format);
|
||||
check_debug_option_stability(&debugging_opts, error_format, json_rendered);
|
||||
|
||||
if !debugging_opts.unstable_options && json_unused_externs {
|
||||
early_error(
|
||||
error_format,
|
||||
"the `-Z unstable-options` flag must also be passed to enable \
|
||||
the flag `--json=unused-externs`",
|
||||
);
|
||||
}
|
||||
|
||||
let output_types = parse_output_types(&debugging_opts, matches, error_format);
|
||||
|
||||
let mut cg = build_codegen_options(matches, error_format);
|
||||
@ -1979,6 +2007,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||
remap_path_prefix,
|
||||
edition,
|
||||
json_artifact_notifications,
|
||||
json_unused_externs,
|
||||
pretty,
|
||||
}
|
||||
}
|
||||
|
@ -147,6 +147,9 @@ top_level_options!(
|
||||
// by the compiler.
|
||||
json_artifact_notifications: bool [TRACKED],
|
||||
|
||||
// `true` if we're emitting a JSON blob containing the unused externs
|
||||
json_unused_externs: bool [UNTRACKED],
|
||||
|
||||
pretty: Option<PpMode> [UNTRACKED],
|
||||
}
|
||||
);
|
||||
|
@ -280,9 +280,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||
if needs_to_be_read {
|
||||
self.borrow_expr(&discr, ty::ImmBorrow);
|
||||
} else {
|
||||
let closure_def_id = match discr_place.place.base {
|
||||
PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id.to_def_id()),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
self.delegate.fake_read(
|
||||
discr_place.place.clone(),
|
||||
FakeReadCause::ForMatchedPlace,
|
||||
FakeReadCause::ForMatchedPlace(closure_def_id),
|
||||
discr_place.hir_id,
|
||||
);
|
||||
|
||||
@ -578,9 +583,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn walk_arm(&mut self, discr_place: &PlaceWithHirId<'tcx>, arm: &hir::Arm<'_>) {
|
||||
let closure_def_id = match discr_place.place.base {
|
||||
PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id.to_def_id()),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
self.delegate.fake_read(
|
||||
discr_place.place.clone(),
|
||||
FakeReadCause::ForMatchedPlace,
|
||||
FakeReadCause::ForMatchedPlace(closure_def_id),
|
||||
discr_place.hir_id,
|
||||
);
|
||||
self.walk_pat(discr_place, &arm.pat);
|
||||
@ -595,9 +605,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||
/// Walks a pat that occurs in isolation (i.e., top-level of fn argument or
|
||||
/// let binding, and *not* a match arm or nested pat.)
|
||||
fn walk_irrefutable_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) {
|
||||
let closure_def_id = match discr_place.place.base {
|
||||
PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id.to_def_id()),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
self.delegate.fake_read(
|
||||
discr_place.place.clone(),
|
||||
FakeReadCause::ForLet,
|
||||
FakeReadCause::ForLet(closure_def_id),
|
||||
discr_place.hir_id,
|
||||
);
|
||||
self.walk_pat(discr_place, pat);
|
||||
|
@ -128,106 +128,6 @@ impl<K, V> InternalNode<K, V> {
|
||||
/// is not a separate type and has no destructor.
|
||||
type BoxedNode<K, V> = NonNull<LeafNode<K, V>>;
|
||||
|
||||
/// The root node of an owned tree.
|
||||
///
|
||||
/// Note that this does not have a destructor, and must be cleaned up manually.
|
||||
pub type Root<K, V> = NodeRef<marker::Owned, K, V, marker::LeafOrInternal>;
|
||||
|
||||
impl<K, V> Root<K, V> {
|
||||
/// Returns a new owned tree, with its own root node that is initially empty.
|
||||
pub fn new() -> Self {
|
||||
NodeRef::new_leaf().forget_type()
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> NodeRef<marker::Owned, K, V, marker::Leaf> {
|
||||
fn new_leaf() -> Self {
|
||||
Self::from_new_leaf(LeafNode::new())
|
||||
}
|
||||
|
||||
fn from_new_leaf(leaf: Box<LeafNode<K, V>>) -> Self {
|
||||
NodeRef { height: 0, node: NonNull::from(Box::leak(leaf)), _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> NodeRef<marker::Owned, K, V, marker::Internal> {
|
||||
fn new_internal(child: Root<K, V>) -> Self {
|
||||
let mut new_node = unsafe { InternalNode::new() };
|
||||
new_node.edges[0].write(child.node);
|
||||
unsafe { NodeRef::from_new_internal(new_node, child.height + 1) }
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// `height` must not be zero.
|
||||
unsafe fn from_new_internal(internal: Box<InternalNode<K, V>>, height: usize) -> Self {
|
||||
debug_assert!(height > 0);
|
||||
let node = NonNull::from(Box::leak(internal)).cast();
|
||||
let mut this = NodeRef { height, node, _marker: PhantomData };
|
||||
this.borrow_mut().correct_all_childrens_parent_links();
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, Type> NodeRef<marker::Owned, K, V, Type> {
|
||||
/// Mutably borrows the owned root node. Unlike `reborrow_mut`, this is safe
|
||||
/// because the return value cannot be used to destroy the root, and there
|
||||
/// cannot be other references to the tree.
|
||||
pub fn borrow_mut(&mut self) -> NodeRef<marker::Mut<'_>, K, V, Type> {
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
|
||||
/// Slightly mutably borrows the owned root node.
|
||||
pub fn borrow_valmut(&mut self) -> NodeRef<marker::ValMut<'_>, K, V, Type> {
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
|
||||
/// Irreversibly transitions to a reference that permits traversal and offers
|
||||
/// destructive methods and little else.
|
||||
pub fn into_dying(self) -> NodeRef<marker::Dying, K, V, Type> {
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
|
||||
/// Adds a new internal node with a single edge pointing to the previous root node,
|
||||
/// make that new node the root node, and return it. This increases the height by 1
|
||||
/// and is the opposite of `pop_internal_level`.
|
||||
pub fn push_internal_level(&mut self) -> NodeRef<marker::Mut<'_>, K, V, marker::Internal> {
|
||||
super::mem::take_mut(self, |old_root| NodeRef::new_internal(old_root).forget_type());
|
||||
|
||||
// `self.borrow_mut()`, except that we just forgot we're internal now:
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
|
||||
/// Removes the internal root node, using its first child as the new root node.
|
||||
/// As it is intended only to be called when the root node has only one child,
|
||||
/// no cleanup is done on any of the keys, values and other children.
|
||||
/// This decreases the height by 1 and is the opposite of `push_internal_level`.
|
||||
///
|
||||
/// Requires exclusive access to the `Root` object but not to the root node;
|
||||
/// it will not invalidate other handles or references to the root node.
|
||||
///
|
||||
/// Panics if there is no internal level, i.e., if the root node is a leaf.
|
||||
pub fn pop_internal_level(&mut self) {
|
||||
assert!(self.height > 0);
|
||||
|
||||
let top = self.node;
|
||||
|
||||
// SAFETY: we asserted to be internal.
|
||||
let internal_self = unsafe { self.borrow_mut().cast_to_internal_unchecked() };
|
||||
// SAFETY: we borrowed `self` exclusively and its borrow type is exclusive.
|
||||
let internal_node = unsafe { &mut *NodeRef::as_internal_ptr(&internal_self) };
|
||||
// SAFETY: the first edge is always initialized.
|
||||
self.node = unsafe { internal_node.edges[0].assume_init_read() };
|
||||
self.height -= 1;
|
||||
self.clear_parent_link();
|
||||
|
||||
unsafe {
|
||||
Global.deallocate(top.cast(), Layout::new::<InternalNode<K, V>>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// N.B. `NodeRef` is always covariant in `K` and `V`, even when the `BorrowType`
|
||||
// is `Mut`. This is technically wrong, but cannot result in any unsafety due to
|
||||
// internal use of `NodeRef` because we stay completely generic over `K` and `V`.
|
||||
@ -292,6 +192,11 @@ pub struct NodeRef<BorrowType, K, V, Type> {
|
||||
_marker: PhantomData<(BorrowType, Type)>,
|
||||
}
|
||||
|
||||
/// The root node of an owned tree.
|
||||
///
|
||||
/// Note that this does not have a destructor, and must be cleaned up manually.
|
||||
pub type Root<K, V> = NodeRef<marker::Owned, K, V, marker::LeafOrInternal>;
|
||||
|
||||
impl<'a, K: 'a, V: 'a, Type> Copy for NodeRef<marker::Immut<'a>, K, V, Type> {}
|
||||
impl<'a, K: 'a, V: 'a, Type> Clone for NodeRef<marker::Immut<'a>, K, V, Type> {
|
||||
fn clone(&self) -> Self {
|
||||
@ -307,6 +212,34 @@ unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef<marker::ValMu
|
||||
unsafe impl<K: Send, V: Send, Type> Send for NodeRef<marker::Owned, K, V, Type> {}
|
||||
unsafe impl<K: Send, V: Send, Type> Send for NodeRef<marker::Dying, K, V, Type> {}
|
||||
|
||||
impl<K, V> NodeRef<marker::Owned, K, V, marker::Leaf> {
|
||||
fn new_leaf() -> Self {
|
||||
Self::from_new_leaf(LeafNode::new())
|
||||
}
|
||||
|
||||
fn from_new_leaf(leaf: Box<LeafNode<K, V>>) -> Self {
|
||||
NodeRef { height: 0, node: NonNull::from(Box::leak(leaf)), _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> NodeRef<marker::Owned, K, V, marker::Internal> {
|
||||
fn new_internal(child: Root<K, V>) -> Self {
|
||||
let mut new_node = unsafe { InternalNode::new() };
|
||||
new_node.edges[0].write(child.node);
|
||||
unsafe { NodeRef::from_new_internal(new_node, child.height + 1) }
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// `height` must not be zero.
|
||||
unsafe fn from_new_internal(internal: Box<InternalNode<K, V>>, height: usize) -> Self {
|
||||
debug_assert!(height > 0);
|
||||
let node = NonNull::from(Box::leak(internal)).cast();
|
||||
let mut this = NodeRef { height, node, _marker: PhantomData };
|
||||
this.borrow_mut().correct_all_childrens_parent_links();
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Internal> {
|
||||
/// Unpack a node reference that was packed as `NodeRef::parent`.
|
||||
fn from_internal(node: NonNull<InternalNode<K, V>>, height: usize) -> Self {
|
||||
@ -420,6 +353,19 @@ impl<BorrowType: marker::BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type>
|
||||
}
|
||||
}
|
||||
|
||||
impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
|
||||
/// Could be a public implementation of PartialEq, but only used in this module.
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let Self { node, height, _marker } = self;
|
||||
if node.eq(&other.node) {
|
||||
debug_assert_eq!(*height, other.height);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
|
||||
/// Exposes the leaf portion of any leaf or internal node in an immutable tree.
|
||||
fn into_leaf(self) -> &'a LeafNode<K, V> {
|
||||
@ -461,20 +407,6 @@ impl<K, V> NodeRef<marker::Dying, K, V, marker::LeafOrInternal> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
|
||||
/// Unsafely asserts to the compiler the static information that this node is a `Leaf`.
|
||||
unsafe fn cast_to_leaf_unchecked(self) -> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
|
||||
debug_assert!(self.height == 0);
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
|
||||
/// Unsafely asserts to the compiler the static information that this node is an `Internal`.
|
||||
unsafe fn cast_to_internal_unchecked(self) -> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
|
||||
debug_assert!(self.height > 0);
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
|
||||
/// Temporarily takes out another, mutable reference to the same node. Beware, as
|
||||
/// this method is very dangerous, doubly so since it may not immediately appear
|
||||
@ -577,6 +509,22 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
|
||||
/// # Safety
|
||||
/// Every item returned by `range` is a valid edge index for the node.
|
||||
unsafe fn correct_childrens_parent_links<R: Iterator<Item = usize>>(&mut self, range: R) {
|
||||
for i in range {
|
||||
debug_assert!(i <= self.len());
|
||||
unsafe { Handle::new_edge(self.reborrow_mut(), i) }.correct_parent_link();
|
||||
}
|
||||
}
|
||||
|
||||
fn correct_all_childrens_parent_links(&mut self) {
|
||||
let len = self.len();
|
||||
unsafe { self.correct_childrens_parent_links(0..=len) };
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
|
||||
/// Sets the node's link to its parent edge,
|
||||
/// without invalidating other references to the node.
|
||||
@ -596,6 +544,71 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
|
||||
/// Returns a new owned tree, with its own root node that is initially empty.
|
||||
pub fn new() -> Self {
|
||||
NodeRef::new_leaf().forget_type()
|
||||
}
|
||||
|
||||
/// Adds a new internal node with a single edge pointing to the previous root node,
|
||||
/// make that new node the root node, and return it. This increases the height by 1
|
||||
/// and is the opposite of `pop_internal_level`.
|
||||
pub fn push_internal_level(&mut self) -> NodeRef<marker::Mut<'_>, K, V, marker::Internal> {
|
||||
super::mem::take_mut(self, |old_root| NodeRef::new_internal(old_root).forget_type());
|
||||
|
||||
// `self.borrow_mut()`, except that we just forgot we're internal now:
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
|
||||
/// Removes the internal root node, using its first child as the new root node.
|
||||
/// As it is intended only to be called when the root node has only one child,
|
||||
/// no cleanup is done on any of the keys, values and other children.
|
||||
/// This decreases the height by 1 and is the opposite of `push_internal_level`.
|
||||
///
|
||||
/// Requires exclusive access to the `Root` object but not to the root node;
|
||||
/// it will not invalidate other handles or references to the root node.
|
||||
///
|
||||
/// Panics if there is no internal level, i.e., if the root node is a leaf.
|
||||
pub fn pop_internal_level(&mut self) {
|
||||
assert!(self.height > 0);
|
||||
|
||||
let top = self.node;
|
||||
|
||||
// SAFETY: we asserted to be internal.
|
||||
let internal_self = unsafe { self.borrow_mut().cast_to_internal_unchecked() };
|
||||
// SAFETY: we borrowed `self` exclusively and its borrow type is exclusive.
|
||||
let internal_node = unsafe { &mut *NodeRef::as_internal_ptr(&internal_self) };
|
||||
// SAFETY: the first edge is always initialized.
|
||||
self.node = unsafe { internal_node.edges[0].assume_init_read() };
|
||||
self.height -= 1;
|
||||
self.clear_parent_link();
|
||||
|
||||
unsafe {
|
||||
Global.deallocate(top.cast(), Layout::new::<InternalNode<K, V>>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, Type> NodeRef<marker::Owned, K, V, Type> {
|
||||
/// Mutably borrows the owned root node. Unlike `reborrow_mut`, this is safe
|
||||
/// because the return value cannot be used to destroy the root, and there
|
||||
/// cannot be other references to the tree.
|
||||
pub fn borrow_mut(&mut self) -> NodeRef<marker::Mut<'_>, K, V, Type> {
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
|
||||
/// Slightly mutably borrows the owned root node.
|
||||
pub fn borrow_valmut(&mut self) -> NodeRef<marker::ValMut<'_>, K, V, Type> {
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
|
||||
/// Irreversibly transitions to a reference that permits traversal and offers
|
||||
/// destructive methods and little else.
|
||||
pub fn into_dying(self) -> NodeRef<marker::Dying, K, V, Type> {
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
|
||||
/// Adds a key-value pair to the end of the node.
|
||||
pub fn push(&mut self, key: K, val: V) {
|
||||
@ -610,22 +623,6 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
|
||||
/// # Safety
|
||||
/// Every item returned by `range` is a valid edge index for the node.
|
||||
unsafe fn correct_childrens_parent_links<R: Iterator<Item = usize>>(&mut self, range: R) {
|
||||
for i in range {
|
||||
debug_assert!(i <= self.len());
|
||||
unsafe { Handle::new_edge(self.reborrow_mut(), i) }.correct_parent_link();
|
||||
}
|
||||
}
|
||||
|
||||
fn correct_all_childrens_parent_links(&mut self) {
|
||||
let len = self.len();
|
||||
unsafe { self.correct_childrens_parent_links(0..=len) };
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
|
||||
/// Adds a key-value pair, and an edge to go to the right of that pair,
|
||||
/// to the end of the node.
|
||||
@ -645,6 +642,20 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Leaf> {
|
||||
/// Removes any static information asserting that this node is a `Leaf` node.
|
||||
pub fn forget_type(self) -> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Internal> {
|
||||
/// Removes any static information asserting that this node is an `Internal` node.
|
||||
pub fn forget_type(self) -> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
|
||||
/// Checks whether a node is an `Internal` node or a `Leaf` node.
|
||||
pub fn force(
|
||||
@ -669,6 +680,20 @@ impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
|
||||
/// Unsafely asserts to the compiler the static information that this node is a `Leaf`.
|
||||
unsafe fn cast_to_leaf_unchecked(self) -> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
|
||||
debug_assert!(self.height == 0);
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
|
||||
/// Unsafely asserts to the compiler the static information that this node is an `Internal`.
|
||||
unsafe fn cast_to_internal_unchecked(self) -> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
|
||||
debug_assert!(self.height > 0);
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
/// A reference to a specific key-value pair or edge within a node. The `Node` parameter
|
||||
/// must be a `NodeRef`, while the `Type` can either be `KV` (signifying a handle on a key-value
|
||||
/// pair) or `Edge` (signifying a handle on an edge).
|
||||
@ -722,19 +747,6 @@ impl<BorrowType, K, V, NodeType> Handle<NodeRef<BorrowType, K, V, NodeType>, mar
|
||||
}
|
||||
}
|
||||
|
||||
impl<BorrowType, K, V, NodeType> NodeRef<BorrowType, K, V, NodeType> {
|
||||
/// Could be a public implementation of PartialEq, but only used in this module.
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let Self { node, height, _marker } = self;
|
||||
if node.eq(&other.node) {
|
||||
debug_assert_eq!(*height, other.height);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<BorrowType, K, V, NodeType, HandleType> PartialEq
|
||||
for Handle<NodeRef<BorrowType, K, V, NodeType>, HandleType>
|
||||
{
|
||||
@ -754,16 +766,6 @@ impl<BorrowType, K, V, NodeType, HandleType>
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V, Type> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, Type> {
|
||||
/// Unsafely asserts to the compiler the static information that the handle's node is a `Leaf`.
|
||||
pub unsafe fn cast_to_leaf_unchecked(
|
||||
self,
|
||||
) -> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, Type> {
|
||||
let node = unsafe { self.node.cast_to_leaf_unchecked() };
|
||||
Handle { node, idx: self.idx, _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V, NodeType, HandleType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, HandleType> {
|
||||
/// Temporarily takes out another, mutable handle on the same location. Beware, as
|
||||
/// this method is very dangerous, doubly so since it may not immediately appear
|
||||
@ -1466,20 +1468,6 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Leaf> {
|
||||
/// Removes any static information asserting that this node is a `Leaf` node.
|
||||
pub fn forget_type(self) -> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Internal> {
|
||||
/// Removes any static information asserting that this node is an `Internal` node.
|
||||
pub fn forget_type(self) -> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
|
||||
pub fn forget_node_type(
|
||||
self,
|
||||
@ -1531,6 +1519,16 @@ impl<BorrowType, K, V, Type> Handle<NodeRef<BorrowType, K, V, marker::LeafOrInte
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V, Type> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, Type> {
|
||||
/// Unsafely asserts to the compiler the static information that the handle's node is a `Leaf`.
|
||||
pub unsafe fn cast_to_leaf_unchecked(
|
||||
self,
|
||||
) -> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, Type> {
|
||||
let node = unsafe { self.node.cast_to_leaf_unchecked() };
|
||||
Handle { node, idx: self.idx, _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::Edge> {
|
||||
/// Move the suffix after `self` from one node to another one. `right` must be empty.
|
||||
/// The first edge of `right` remains unchanged.
|
||||
|
@ -1004,9 +1004,9 @@ fn test_from_iter_specialization_with_iterator_adapters() {
|
||||
.map_while(Option::Some)
|
||||
.peekable()
|
||||
.skip(1)
|
||||
.map(|e| std::num::NonZeroUsize::new(e));
|
||||
.map(|e| if e != usize::MAX { Ok(std::num::NonZeroUsize::new(e)) } else { Err(()) });
|
||||
assert_in_place_trait(&iter);
|
||||
let sink = iter.collect::<Vec<_>>();
|
||||
let sink = iter.collect::<Result<Vec<_>, _>>().unwrap();
|
||||
let sinkptr = sink.as_ptr();
|
||||
assert_eq!(srcptr, sinkptr as *const usize);
|
||||
}
|
||||
@ -1078,12 +1078,21 @@ fn test_from_iter_specialization_panic_during_drop_leaks() {
|
||||
}
|
||||
}
|
||||
|
||||
let mut to_free: *mut Droppable = core::ptr::null_mut();
|
||||
let mut cap = 0;
|
||||
|
||||
let _ = std::panic::catch_unwind(AssertUnwindSafe(|| {
|
||||
let v = vec![Droppable::DroppedTwice(Box::new(123)), Droppable::PanicOnDrop];
|
||||
let mut v = vec![Droppable::DroppedTwice(Box::new(123)), Droppable::PanicOnDrop];
|
||||
to_free = v.as_mut_ptr();
|
||||
cap = v.capacity();
|
||||
let _ = v.into_iter().take(0).collect::<Vec<_>>();
|
||||
}));
|
||||
|
||||
assert_eq!(unsafe { DROP_COUNTER }, 1);
|
||||
// clean up the leak to keep miri happy
|
||||
unsafe {
|
||||
drop(Vec::from_raw_parts(to_free, 0, cap));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -194,3 +194,26 @@ where
|
||||
self.try_fold(init, ok(fold)).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<S: Iterator, I, E> SourceIter for ResultShunt<'_, I, E>
|
||||
where
|
||||
I: SourceIter<Source = S>,
|
||||
{
|
||||
type Source = S;
|
||||
|
||||
#[inline]
|
||||
unsafe fn as_inner(&mut self) -> &mut S {
|
||||
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
|
||||
unsafe { SourceIter::as_inner(&mut self.iter) }
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: ResultShunt::next calls I::find, which has to advance `iter` in order to
|
||||
// return `Some(_)`. Since `iter` has type `I: InPlaceIterable` it's guaranteed that
|
||||
// at least one item will be moved out from the underlying source.
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<I, T, E> InPlaceIterable for ResultShunt<'_, I, E> where
|
||||
I: Iterator<Item = Result<T, E>> + InPlaceIterable
|
||||
{
|
||||
}
|
||||
|
@ -154,6 +154,8 @@ crate struct Options {
|
||||
/// If this option is set to `true`, rustdoc will only run checks and not generate
|
||||
/// documentation.
|
||||
crate run_check: bool,
|
||||
/// Whether doctests should emit unused externs
|
||||
crate json_unused_externs: bool,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Options {
|
||||
@ -352,7 +354,8 @@ impl Options {
|
||||
}
|
||||
|
||||
let color = config::parse_color(&matches);
|
||||
let (json_rendered, _artifacts) = config::parse_json(&matches);
|
||||
let config::JsonConfig { json_rendered, json_unused_externs, .. } =
|
||||
config::parse_json(&matches);
|
||||
let error_format = config::parse_error_format(&matches, color, json_rendered);
|
||||
|
||||
let codegen_options = build_codegen_options(matches, error_format);
|
||||
@ -507,7 +510,6 @@ impl Options {
|
||||
let edition = config::parse_crate_edition(&matches);
|
||||
|
||||
let mut id_map = html::markdown::IdMap::new();
|
||||
id_map.populate(&html::render::INITIAL_IDS);
|
||||
let external_html = match ExternalHtml::load(
|
||||
&matches.opt_strs("html-in-header"),
|
||||
&matches.opt_strs("html-before-content"),
|
||||
@ -687,6 +689,7 @@ impl Options {
|
||||
},
|
||||
crate_name,
|
||||
output_format,
|
||||
json_unused_externs,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{ColorConfig, ErrorReported};
|
||||
use rustc_hir as hir;
|
||||
@ -23,6 +23,8 @@ use std::panic;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{self, Command, Stdio};
|
||||
use std::str;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use crate::clean::Attributes;
|
||||
use crate::config::Options;
|
||||
@ -104,8 +106,10 @@ crate fn run(options: Options) -> Result<(), ErrorReported> {
|
||||
|
||||
let mut test_args = options.test_args.clone();
|
||||
let display_warnings = options.display_warnings;
|
||||
let externs = options.externs.clone();
|
||||
let json_unused_externs = options.json_unused_externs;
|
||||
|
||||
let tests = interface::run_compiler(config, |compiler| {
|
||||
let res = interface::run_compiler(config, |compiler| {
|
||||
compiler.enter(|queries| {
|
||||
let _lower_to_hir = queries.lower_to_hir()?;
|
||||
|
||||
@ -151,12 +155,15 @@ crate fn run(options: Options) -> Result<(), ErrorReported> {
|
||||
});
|
||||
compiler.session().abort_if_errors();
|
||||
|
||||
let ret: Result<_, ErrorReported> = Ok(collector.tests);
|
||||
let unused_extern_reports = collector.unused_extern_reports.clone();
|
||||
let compiling_test_count = collector.compiling_test_count.load(Ordering::SeqCst);
|
||||
let ret: Result<_, ErrorReported> =
|
||||
Ok((collector.tests, unused_extern_reports, compiling_test_count));
|
||||
ret
|
||||
})
|
||||
});
|
||||
let tests = match tests {
|
||||
Ok(tests) => tests,
|
||||
let (tests, unused_extern_reports, compiling_test_count) = match res {
|
||||
Ok(res) => res,
|
||||
Err(ErrorReported) => return Err(ErrorReported),
|
||||
};
|
||||
|
||||
@ -168,6 +175,44 @@ crate fn run(options: Options) -> Result<(), ErrorReported> {
|
||||
Some(testing::Options::new().display_output(display_warnings)),
|
||||
);
|
||||
|
||||
// Collect and warn about unused externs, but only if we've gotten
|
||||
// reports for each doctest
|
||||
if json_unused_externs {
|
||||
let unused_extern_reports: Vec<_> =
|
||||
std::mem::take(&mut unused_extern_reports.lock().unwrap());
|
||||
if unused_extern_reports.len() == compiling_test_count {
|
||||
let extern_names = externs.iter().map(|(name, _)| name).collect::<FxHashSet<&String>>();
|
||||
let mut unused_extern_names = unused_extern_reports
|
||||
.iter()
|
||||
.map(|uexts| uexts.unused_extern_names.iter().collect::<FxHashSet<&String>>())
|
||||
.fold(extern_names, |uextsa, uextsb| {
|
||||
uextsa.intersection(&uextsb).map(|v| *v).collect::<FxHashSet<&String>>()
|
||||
})
|
||||
.iter()
|
||||
.map(|v| (*v).clone())
|
||||
.collect::<Vec<String>>();
|
||||
unused_extern_names.sort();
|
||||
// Take the most severe lint level
|
||||
let lint_level = unused_extern_reports
|
||||
.iter()
|
||||
.map(|uexts| uexts.lint_level.as_str())
|
||||
.max_by_key(|v| match *v {
|
||||
"warn" => 1,
|
||||
"deny" => 2,
|
||||
"forbid" => 3,
|
||||
// The allow lint level is not expected,
|
||||
// as if allow is specified, no message
|
||||
// is to be emitted.
|
||||
v => unreachable!("Invalid lint level '{}'", v),
|
||||
})
|
||||
.unwrap_or("warn")
|
||||
.to_string();
|
||||
let uext = UnusedExterns { lint_level, unused_extern_names };
|
||||
let unused_extern_json = serde_json::to_string(&uext).unwrap();
|
||||
eprintln!("{}", unused_extern_json);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -235,6 +280,18 @@ impl DirState {
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Keep this in sync with the equivalent structs in rustc
|
||||
// and cargo.
|
||||
// We could unify this struct the one in rustc but they have different
|
||||
// ownership semantics, so doing so would create wasteful allocations.
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
struct UnusedExterns {
|
||||
/// Lint level of the unused_crate_dependencies lint
|
||||
lint_level: String,
|
||||
/// List of unused externs by their names.
|
||||
unused_extern_names: Vec<String>,
|
||||
}
|
||||
|
||||
fn run_test(
|
||||
test: &str,
|
||||
cratename: &str,
|
||||
@ -253,6 +310,7 @@ fn run_test(
|
||||
outdir: DirState,
|
||||
path: PathBuf,
|
||||
test_id: &str,
|
||||
report_unused_externs: impl Fn(UnusedExterns),
|
||||
) -> Result<(), TestFailure> {
|
||||
let (test, line_offset, supports_color) =
|
||||
make_test(test, Some(cratename), as_test_harness, opts, edition, Some(test_id));
|
||||
@ -278,6 +336,12 @@ fn run_test(
|
||||
if as_test_harness {
|
||||
compiler.arg("--test");
|
||||
}
|
||||
if options.json_unused_externs && !compile_fail {
|
||||
compiler.arg("--error-format=json");
|
||||
compiler.arg("--json").arg("unused-externs");
|
||||
compiler.arg("-Z").arg("unstable-options");
|
||||
compiler.arg("-W").arg("unused_crate_dependencies");
|
||||
}
|
||||
for lib_str in &options.lib_strs {
|
||||
compiler.arg("-L").arg(&lib_str);
|
||||
}
|
||||
@ -337,7 +401,26 @@ fn run_test(
|
||||
eprint!("{}", self.0);
|
||||
}
|
||||
}
|
||||
let out = str::from_utf8(&output.stderr).unwrap();
|
||||
let mut out_lines = str::from_utf8(&output.stderr)
|
||||
.unwrap()
|
||||
.lines()
|
||||
.filter(|l| {
|
||||
if let Ok(uext) = serde_json::from_str::<UnusedExterns>(l) {
|
||||
report_unused_externs(uext);
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Add a \n to the end to properly terminate the last line,
|
||||
// but only if there was output to be printed
|
||||
if out_lines.len() > 0 {
|
||||
out_lines.push("");
|
||||
}
|
||||
|
||||
let out = out_lines.join("\n");
|
||||
let _bomb = Bomb(&out);
|
||||
match (output.status.success(), compile_fail) {
|
||||
(true, true) => {
|
||||
@ -721,6 +804,8 @@ crate struct Collector {
|
||||
source_map: Option<Lrc<SourceMap>>,
|
||||
filename: Option<PathBuf>,
|
||||
visited_tests: FxHashMap<(String, usize), usize>,
|
||||
unused_extern_reports: Arc<Mutex<Vec<UnusedExterns>>>,
|
||||
compiling_test_count: AtomicUsize,
|
||||
}
|
||||
|
||||
impl Collector {
|
||||
@ -745,6 +830,8 @@ impl Collector {
|
||||
source_map,
|
||||
filename,
|
||||
visited_tests: FxHashMap::default(),
|
||||
unused_extern_reports: Default::default(),
|
||||
compiling_test_count: AtomicUsize::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
@ -791,6 +878,10 @@ impl Tester for Collector {
|
||||
let runtool_args = self.options.runtool_args.clone();
|
||||
let target = self.options.target.clone();
|
||||
let target_str = target.to_string();
|
||||
let unused_externs = self.unused_extern_reports.clone();
|
||||
if !config.compile_fail {
|
||||
self.compiling_test_count.fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
// FIXME(#44940): if doctests ever support path remapping, then this filename
|
||||
// needs to be the result of `SourceMap::span_to_unmapped_path`.
|
||||
@ -846,6 +937,9 @@ impl Tester for Collector {
|
||||
test_type: testing::TestType::DocTest,
|
||||
},
|
||||
testfn: testing::DynTestFn(box move || {
|
||||
let report_unused_externs = |uext| {
|
||||
unused_externs.lock().unwrap().push(uext);
|
||||
};
|
||||
let res = run_test(
|
||||
&test,
|
||||
&cratename,
|
||||
@ -864,6 +958,7 @@ impl Tester for Collector {
|
||||
outdir,
|
||||
path,
|
||||
&test_id,
|
||||
report_unused_externs,
|
||||
);
|
||||
|
||||
if let Err(err) = res {
|
||||
|
@ -189,7 +189,9 @@ impl<'a> Classifier<'a> {
|
||||
// leading identifier.
|
||||
TokenKind::Bang if self.in_macro => {
|
||||
self.in_macro = false;
|
||||
Class::Macro
|
||||
sink(Highlight::Token { text, class: None });
|
||||
sink(Highlight::ExitSpan);
|
||||
return;
|
||||
}
|
||||
|
||||
// Assume that '&' or '*' is the reference or dereference operator
|
||||
@ -298,7 +300,9 @@ impl<'a> Classifier<'a> {
|
||||
},
|
||||
TokenKind::Ident | TokenKind::RawIdent if lookahead == Some(TokenKind::Bang) => {
|
||||
self.in_macro = true;
|
||||
Class::Macro
|
||||
sink(Highlight::EnterSpan { class: Class::Macro });
|
||||
sink(Highlight::Token { text, class: None });
|
||||
return;
|
||||
}
|
||||
TokenKind::Ident => match text {
|
||||
"ref" | "mut" => Class::RefKeyWord,
|
||||
|
@ -1,3 +1,3 @@
|
||||
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">foo</span>() {
|
||||
<span class="macro">println</span><span class="macro">!</span>(<span class="string">"foo"</span>);
|
||||
<span class="macro">println!</span>(<span class="string">"foo"</span>);
|
||||
}
|
||||
|
@ -17,11 +17,11 @@
|
||||
<span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="kw-2">&</span><span class="ident">foo</span>;
|
||||
<span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="op">&&</span><span class="ident">foo</span>;
|
||||
<span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="kw-2">*</span><span class="ident">foo</span>;
|
||||
<span class="macro">mac</span><span class="macro">!</span>(<span class="ident">foo</span>, <span class="kw-2">&</span><span class="kw-2">mut</span> <span class="ident">bar</span>);
|
||||
<span class="macro">assert</span><span class="macro">!</span>(<span class="self">self</span>.<span class="ident">length</span> <span class="op"><</span> <span class="ident">N</span> <span class="op">&&</span> <span class="ident">index</span> <span class="op"><</span><span class="op">=</span> <span class="self">self</span>.<span class="ident">length</span>);
|
||||
<span class="macro">mac!</span>(<span class="ident">foo</span>, <span class="kw-2">&</span><span class="kw-2">mut</span> <span class="ident">bar</span>);
|
||||
<span class="macro">assert!</span>(<span class="self">self</span>.<span class="ident">length</span> <span class="op"><</span> <span class="ident">N</span> <span class="op">&&</span> <span class="ident">index</span> <span class="op"><</span><span class="op">=</span> <span class="self">self</span>.<span class="ident">length</span>);
|
||||
}
|
||||
|
||||
<span class="macro">macro_rules</span><span class="macro">!</span> <span class="ident">bar</span> {
|
||||
<span class="macro">macro_rules!</span> <span class="ident">bar</span> {
|
||||
(<span class="macro-nonterminal">$</span><span class="macro-nonterminal">foo</span>:<span class="ident">tt</span>) <span class="op">=</span><span class="op">></span> {};
|
||||
}
|
||||
</code></pre>
|
||||
|
@ -1356,6 +1356,9 @@ fn init_id_map() -> FxHashMap<String, usize> {
|
||||
map.insert("rustdoc-vars".to_owned(), 1);
|
||||
map.insert("sidebar-vars".to_owned(), 1);
|
||||
map.insert("copy-path".to_owned(), 1);
|
||||
map.insert("help".to_owned(), 1);
|
||||
map.insert("TOC".to_owned(), 1);
|
||||
map.insert("render-detail".to_owned(), 1);
|
||||
// This is the list of IDs used by rustdoc sections.
|
||||
map.insert("fields".to_owned(), 1);
|
||||
map.insert("variants".to_owned(), 1);
|
||||
@ -1365,6 +1368,12 @@ fn init_id_map() -> FxHashMap<String, usize> {
|
||||
map.insert("trait-implementations".to_owned(), 1);
|
||||
map.insert("synthetic-implementations".to_owned(), 1);
|
||||
map.insert("blanket-implementations".to_owned(), 1);
|
||||
map.insert("associated-types".to_owned(), 1);
|
||||
map.insert("associated-const".to_owned(), 1);
|
||||
map.insert("required-methods".to_owned(), 1);
|
||||
map.insert("provided-methods".to_owned(), 1);
|
||||
map.insert("implementors".to_owned(), 1);
|
||||
map.insert("synthetic-implementors".to_owned(), 1);
|
||||
map
|
||||
}
|
||||
|
||||
@ -1373,12 +1382,6 @@ impl IdMap {
|
||||
IdMap { map: init_id_map() }
|
||||
}
|
||||
|
||||
crate fn populate<I: IntoIterator<Item = S>, S: AsRef<str> + ToString>(&mut self, ids: I) {
|
||||
for id in ids {
|
||||
let _ = self.derive(id);
|
||||
}
|
||||
}
|
||||
|
||||
crate fn derive<S: AsRef<str> + ToString>(&mut self, candidate: S) -> String {
|
||||
let id = match self.map.get_mut(candidate.as_ref()) {
|
||||
None => candidate.to_string(),
|
||||
|
@ -18,7 +18,7 @@ use super::print_item::{full_path, item_path, print_item};
|
||||
use super::write_shared::write_shared;
|
||||
use super::{
|
||||
print_sidebar, settings, AllTypes, NameDoc, SharedContext, StylePath, BASIC_KEYWORDS,
|
||||
CURRENT_DEPTH, INITIAL_IDS,
|
||||
CURRENT_DEPTH,
|
||||
};
|
||||
|
||||
use crate::clean::{self, AttributesExt};
|
||||
@ -423,14 +423,11 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
|
||||
}
|
||||
|
||||
fn make_child_renderer(&self) -> Self {
|
||||
let mut id_map = IdMap::new();
|
||||
id_map.populate(&INITIAL_IDS);
|
||||
|
||||
Self {
|
||||
current: self.current.clone(),
|
||||
dst: self.dst.clone(),
|
||||
render_redirect_pages: self.render_redirect_pages,
|
||||
id_map: RefCell::new(id_map),
|
||||
id_map: RefCell::new(IdMap::new()),
|
||||
deref_id_map: RefCell::new(FxHashMap::default()),
|
||||
shared: Rc::clone(&self.shared),
|
||||
cache: Rc::clone(&self.cache),
|
||||
|
@ -283,24 +283,6 @@ crate struct StylePath {
|
||||
|
||||
thread_local!(crate static CURRENT_DEPTH: Cell<usize> = Cell::new(0));
|
||||
|
||||
crate const INITIAL_IDS: [&'static str; 15] = [
|
||||
"main",
|
||||
"search",
|
||||
"help",
|
||||
"TOC",
|
||||
"render-detail",
|
||||
"associated-types",
|
||||
"associated-const",
|
||||
"required-methods",
|
||||
"provided-methods",
|
||||
"implementors",
|
||||
"synthetic-implementors",
|
||||
"implementors-list",
|
||||
"synthetic-implementors-list",
|
||||
"methods",
|
||||
"implementations",
|
||||
];
|
||||
|
||||
fn write_srclink(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) {
|
||||
if let Some(l) = cx.src_href(item) {
|
||||
write!(buf, "<a class=\"srclink\" href=\"{}\" title=\"goto source code\">[src]</a>", l)
|
||||
|
@ -130,12 +130,12 @@ fn address_of_reborrow() -> () {
|
||||
StorageLive(_2); // scope 0 at $DIR/address-of.rs:4:14: 4:21
|
||||
_2 = [const 0_i32; 10]; // scope 0 at $DIR/address-of.rs:4:14: 4:21
|
||||
_1 = &_2; // scope 0 at $DIR/address-of.rs:4:13: 4:21
|
||||
FakeRead(ForLet, _1); // scope 0 at $DIR/address-of.rs:4:9: 4:10
|
||||
FakeRead(ForLet(None), _1); // scope 0 at $DIR/address-of.rs:4:9: 4:10
|
||||
StorageLive(_3); // scope 1 at $DIR/address-of.rs:5:9: 5:14
|
||||
StorageLive(_4); // scope 1 at $DIR/address-of.rs:5:22: 5:29
|
||||
_4 = [const 0_i32; 10]; // scope 1 at $DIR/address-of.rs:5:22: 5:29
|
||||
_3 = &mut _4; // scope 1 at $DIR/address-of.rs:5:17: 5:29
|
||||
FakeRead(ForLet, _3); // scope 1 at $DIR/address-of.rs:5:9: 5:14
|
||||
FakeRead(ForLet(None), _3); // scope 1 at $DIR/address-of.rs:5:9: 5:14
|
||||
StorageLive(_5); // scope 2 at $DIR/address-of.rs:7:5: 7:18
|
||||
StorageLive(_6); // scope 2 at $DIR/address-of.rs:7:5: 7:18
|
||||
_6 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:7:5: 7:6
|
||||
@ -170,25 +170,25 @@ fn address_of_reborrow() -> () {
|
||||
StorageDead(_13); // scope 2 at $DIR/address-of.rs:11:20: 11:21
|
||||
StorageLive(_15); // scope 2 at $DIR/address-of.rs:13:9: 13:10
|
||||
_15 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:13:23: 13:24
|
||||
FakeRead(ForLet, _15); // scope 2 at $DIR/address-of.rs:13:9: 13:10
|
||||
FakeRead(ForLet(None), _15); // scope 2 at $DIR/address-of.rs:13:9: 13:10
|
||||
AscribeUserType(_15, o, UserTypeProjection { base: UserType(3), projs: [] }); // scope 2 at $DIR/address-of.rs:13:12: 13:20
|
||||
StorageLive(_16); // scope 3 at $DIR/address-of.rs:14:9: 14:10
|
||||
_16 = &raw const (*_1); // scope 3 at $DIR/address-of.rs:14:31: 14:32
|
||||
FakeRead(ForLet, _16); // scope 3 at $DIR/address-of.rs:14:9: 14:10
|
||||
FakeRead(ForLet(None), _16); // scope 3 at $DIR/address-of.rs:14:9: 14:10
|
||||
AscribeUserType(_16, o, UserTypeProjection { base: UserType(5), projs: [] }); // scope 3 at $DIR/address-of.rs:14:12: 14:28
|
||||
StorageLive(_17); // scope 4 at $DIR/address-of.rs:15:9: 15:10
|
||||
StorageLive(_18); // scope 4 at $DIR/address-of.rs:15:30: 15:31
|
||||
_18 = &raw const (*_1); // scope 4 at $DIR/address-of.rs:15:30: 15:31
|
||||
_17 = move _18 as *const dyn std::marker::Send (Pointer(Unsize)); // scope 4 at $DIR/address-of.rs:15:30: 15:31
|
||||
StorageDead(_18); // scope 4 at $DIR/address-of.rs:15:30: 15:31
|
||||
FakeRead(ForLet, _17); // scope 4 at $DIR/address-of.rs:15:9: 15:10
|
||||
FakeRead(ForLet(None), _17); // scope 4 at $DIR/address-of.rs:15:9: 15:10
|
||||
AscribeUserType(_17, o, UserTypeProjection { base: UserType(7), projs: [] }); // scope 4 at $DIR/address-of.rs:15:12: 15:27
|
||||
StorageLive(_19); // scope 5 at $DIR/address-of.rs:16:9: 16:10
|
||||
StorageLive(_20); // scope 5 at $DIR/address-of.rs:16:27: 16:28
|
||||
_20 = &raw const (*_1); // scope 5 at $DIR/address-of.rs:16:27: 16:28
|
||||
_19 = move _20 as *const [i32] (Pointer(Unsize)); // scope 5 at $DIR/address-of.rs:16:27: 16:28
|
||||
StorageDead(_20); // scope 5 at $DIR/address-of.rs:16:27: 16:28
|
||||
FakeRead(ForLet, _19); // scope 5 at $DIR/address-of.rs:16:9: 16:10
|
||||
FakeRead(ForLet(None), _19); // scope 5 at $DIR/address-of.rs:16:9: 16:10
|
||||
AscribeUserType(_19, o, UserTypeProjection { base: UserType(9), projs: [] }); // scope 5 at $DIR/address-of.rs:16:12: 16:24
|
||||
StorageLive(_21); // scope 6 at $DIR/address-of.rs:18:5: 18:18
|
||||
StorageLive(_22); // scope 6 at $DIR/address-of.rs:18:5: 18:18
|
||||
@ -218,25 +218,25 @@ fn address_of_reborrow() -> () {
|
||||
StorageDead(_27); // scope 6 at $DIR/address-of.rs:21:22: 21:23
|
||||
StorageLive(_29); // scope 6 at $DIR/address-of.rs:23:9: 23:10
|
||||
_29 = &raw const (*_3); // scope 6 at $DIR/address-of.rs:23:23: 23:24
|
||||
FakeRead(ForLet, _29); // scope 6 at $DIR/address-of.rs:23:9: 23:10
|
||||
FakeRead(ForLet(None), _29); // scope 6 at $DIR/address-of.rs:23:9: 23:10
|
||||
AscribeUserType(_29, o, UserTypeProjection { base: UserType(13), projs: [] }); // scope 6 at $DIR/address-of.rs:23:12: 23:20
|
||||
StorageLive(_30); // scope 7 at $DIR/address-of.rs:24:9: 24:10
|
||||
_30 = &raw const (*_3); // scope 7 at $DIR/address-of.rs:24:31: 24:32
|
||||
FakeRead(ForLet, _30); // scope 7 at $DIR/address-of.rs:24:9: 24:10
|
||||
FakeRead(ForLet(None), _30); // scope 7 at $DIR/address-of.rs:24:9: 24:10
|
||||
AscribeUserType(_30, o, UserTypeProjection { base: UserType(15), projs: [] }); // scope 7 at $DIR/address-of.rs:24:12: 24:28
|
||||
StorageLive(_31); // scope 8 at $DIR/address-of.rs:25:9: 25:10
|
||||
StorageLive(_32); // scope 8 at $DIR/address-of.rs:25:30: 25:31
|
||||
_32 = &raw const (*_3); // scope 8 at $DIR/address-of.rs:25:30: 25:31
|
||||
_31 = move _32 as *const dyn std::marker::Send (Pointer(Unsize)); // scope 8 at $DIR/address-of.rs:25:30: 25:31
|
||||
StorageDead(_32); // scope 8 at $DIR/address-of.rs:25:30: 25:31
|
||||
FakeRead(ForLet, _31); // scope 8 at $DIR/address-of.rs:25:9: 25:10
|
||||
FakeRead(ForLet(None), _31); // scope 8 at $DIR/address-of.rs:25:9: 25:10
|
||||
AscribeUserType(_31, o, UserTypeProjection { base: UserType(17), projs: [] }); // scope 8 at $DIR/address-of.rs:25:12: 25:27
|
||||
StorageLive(_33); // scope 9 at $DIR/address-of.rs:26:9: 26:10
|
||||
StorageLive(_34); // scope 9 at $DIR/address-of.rs:26:27: 26:28
|
||||
_34 = &raw const (*_3); // scope 9 at $DIR/address-of.rs:26:27: 26:28
|
||||
_33 = move _34 as *const [i32] (Pointer(Unsize)); // scope 9 at $DIR/address-of.rs:26:27: 26:28
|
||||
StorageDead(_34); // scope 9 at $DIR/address-of.rs:26:27: 26:28
|
||||
FakeRead(ForLet, _33); // scope 9 at $DIR/address-of.rs:26:9: 26:10
|
||||
FakeRead(ForLet(None), _33); // scope 9 at $DIR/address-of.rs:26:9: 26:10
|
||||
AscribeUserType(_33, o, UserTypeProjection { base: UserType(19), projs: [] }); // scope 9 at $DIR/address-of.rs:26:12: 26:24
|
||||
StorageLive(_35); // scope 10 at $DIR/address-of.rs:28:5: 28:16
|
||||
StorageLive(_36); // scope 10 at $DIR/address-of.rs:28:5: 28:16
|
||||
@ -266,25 +266,25 @@ fn address_of_reborrow() -> () {
|
||||
StorageDead(_41); // scope 10 at $DIR/address-of.rs:31:20: 31:21
|
||||
StorageLive(_43); // scope 10 at $DIR/address-of.rs:33:9: 33:10
|
||||
_43 = &raw mut (*_3); // scope 10 at $DIR/address-of.rs:33:21: 33:22
|
||||
FakeRead(ForLet, _43); // scope 10 at $DIR/address-of.rs:33:9: 33:10
|
||||
FakeRead(ForLet(None), _43); // scope 10 at $DIR/address-of.rs:33:9: 33:10
|
||||
AscribeUserType(_43, o, UserTypeProjection { base: UserType(23), projs: [] }); // scope 10 at $DIR/address-of.rs:33:12: 33:18
|
||||
StorageLive(_44); // scope 11 at $DIR/address-of.rs:34:9: 34:10
|
||||
_44 = &raw mut (*_3); // scope 11 at $DIR/address-of.rs:34:29: 34:30
|
||||
FakeRead(ForLet, _44); // scope 11 at $DIR/address-of.rs:34:9: 34:10
|
||||
FakeRead(ForLet(None), _44); // scope 11 at $DIR/address-of.rs:34:9: 34:10
|
||||
AscribeUserType(_44, o, UserTypeProjection { base: UserType(25), projs: [] }); // scope 11 at $DIR/address-of.rs:34:12: 34:26
|
||||
StorageLive(_45); // scope 12 at $DIR/address-of.rs:35:9: 35:10
|
||||
StorageLive(_46); // scope 12 at $DIR/address-of.rs:35:28: 35:29
|
||||
_46 = &raw mut (*_3); // scope 12 at $DIR/address-of.rs:35:28: 35:29
|
||||
_45 = move _46 as *mut dyn std::marker::Send (Pointer(Unsize)); // scope 12 at $DIR/address-of.rs:35:28: 35:29
|
||||
StorageDead(_46); // scope 12 at $DIR/address-of.rs:35:28: 35:29
|
||||
FakeRead(ForLet, _45); // scope 12 at $DIR/address-of.rs:35:9: 35:10
|
||||
FakeRead(ForLet(None), _45); // scope 12 at $DIR/address-of.rs:35:9: 35:10
|
||||
AscribeUserType(_45, o, UserTypeProjection { base: UserType(27), projs: [] }); // scope 12 at $DIR/address-of.rs:35:12: 35:25
|
||||
StorageLive(_47); // scope 13 at $DIR/address-of.rs:36:9: 36:10
|
||||
StorageLive(_48); // scope 13 at $DIR/address-of.rs:36:25: 36:26
|
||||
_48 = &raw mut (*_3); // scope 13 at $DIR/address-of.rs:36:25: 36:26
|
||||
_47 = move _48 as *mut [i32] (Pointer(Unsize)); // scope 13 at $DIR/address-of.rs:36:25: 36:26
|
||||
StorageDead(_48); // scope 13 at $DIR/address-of.rs:36:25: 36:26
|
||||
FakeRead(ForLet, _47); // scope 13 at $DIR/address-of.rs:36:9: 36:10
|
||||
FakeRead(ForLet(None), _47); // scope 13 at $DIR/address-of.rs:36:9: 36:10
|
||||
AscribeUserType(_47, o, UserTypeProjection { base: UserType(29), projs: [] }); // scope 13 at $DIR/address-of.rs:36:12: 36:22
|
||||
_0 = const (); // scope 0 at $DIR/address-of.rs:3:26: 37:2
|
||||
StorageDead(_47); // scope 13 at $DIR/address-of.rs:37:1: 37:2
|
||||
|
@ -24,19 +24,19 @@ fn borrow_and_cast(_1: i32) -> () {
|
||||
StorageLive(_3); // scope 0 at $DIR/address-of.rs:42:13: 42:15
|
||||
_3 = &_1; // scope 0 at $DIR/address-of.rs:42:13: 42:15
|
||||
_2 = &raw const (*_3); // scope 0 at $DIR/address-of.rs:42:13: 42:15
|
||||
FakeRead(ForLet, _2); // scope 0 at $DIR/address-of.rs:42:9: 42:10
|
||||
FakeRead(ForLet(None), _2); // scope 0 at $DIR/address-of.rs:42:9: 42:10
|
||||
StorageDead(_3); // scope 0 at $DIR/address-of.rs:42:29: 42:30
|
||||
StorageLive(_4); // scope 1 at $DIR/address-of.rs:43:9: 43:10
|
||||
StorageLive(_5); // scope 1 at $DIR/address-of.rs:43:13: 43:19
|
||||
_5 = &mut _1; // scope 1 at $DIR/address-of.rs:43:13: 43:19
|
||||
_4 = &raw const (*_5); // scope 1 at $DIR/address-of.rs:43:13: 43:19
|
||||
FakeRead(ForLet, _4); // scope 1 at $DIR/address-of.rs:43:9: 43:10
|
||||
FakeRead(ForLet(None), _4); // scope 1 at $DIR/address-of.rs:43:9: 43:10
|
||||
StorageDead(_5); // scope 1 at $DIR/address-of.rs:43:33: 43:34
|
||||
StorageLive(_6); // scope 2 at $DIR/address-of.rs:44:9: 44:10
|
||||
StorageLive(_7); // scope 2 at $DIR/address-of.rs:44:13: 44:19
|
||||
_7 = &mut _1; // scope 2 at $DIR/address-of.rs:44:13: 44:19
|
||||
_6 = &raw mut (*_7); // scope 2 at $DIR/address-of.rs:44:13: 44:19
|
||||
FakeRead(ForLet, _6); // scope 2 at $DIR/address-of.rs:44:9: 44:10
|
||||
FakeRead(ForLet(None), _6); // scope 2 at $DIR/address-of.rs:44:9: 44:10
|
||||
StorageDead(_7); // scope 2 at $DIR/address-of.rs:44:31: 44:32
|
||||
_0 = const (); // scope 0 at $DIR/address-of.rs:41:32: 45:2
|
||||
StorageDead(_6); // scope 2 at $DIR/address-of.rs:45:1: 45:2
|
||||
|
@ -28,7 +28,7 @@ fn main() -> () {
|
||||
bb0: {
|
||||
StorageLive(_1); // scope 0 at $DIR/basic_assignment.rs:11:9: 11:17
|
||||
_1 = const false; // scope 0 at $DIR/basic_assignment.rs:11:20: 11:25
|
||||
FakeRead(ForLet, _1); // scope 0 at $DIR/basic_assignment.rs:11:9: 11:17
|
||||
FakeRead(ForLet(None), _1); // scope 0 at $DIR/basic_assignment.rs:11:9: 11:17
|
||||
StorageLive(_2); // scope 1 at $DIR/basic_assignment.rs:12:9: 12:17
|
||||
StorageLive(_3); // scope 2 at $DIR/basic_assignment.rs:16:16: 16:24
|
||||
_3 = _1; // scope 2 at $DIR/basic_assignment.rs:16:16: 16:24
|
||||
@ -36,7 +36,7 @@ fn main() -> () {
|
||||
StorageDead(_3); // scope 2 at $DIR/basic_assignment.rs:16:23: 16:24
|
||||
StorageLive(_4); // scope 2 at $DIR/basic_assignment.rs:18:9: 18:15
|
||||
_4 = Option::<Box<u32>>::None; // scope 2 at $DIR/basic_assignment.rs:18:36: 18:40
|
||||
FakeRead(ForLet, _4); // scope 2 at $DIR/basic_assignment.rs:18:9: 18:15
|
||||
FakeRead(ForLet(None), _4); // scope 2 at $DIR/basic_assignment.rs:18:9: 18:15
|
||||
AscribeUserType(_4, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 2 at $DIR/basic_assignment.rs:18:17: 18:33
|
||||
StorageLive(_5); // scope 3 at $DIR/basic_assignment.rs:19:9: 19:15
|
||||
StorageLive(_6); // scope 4 at $DIR/basic_assignment.rs:23:14: 23:20
|
||||
|
@ -18,7 +18,7 @@ fn match_tuple(_1: (u32, bool, Option<i32>, u32)) -> u32 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
FakeRead(ForMatchedPlace, _1); // scope 0 at $DIR/exponential-or.rs:5:11: 5:12
|
||||
FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/exponential-or.rs:5:11: 5:12
|
||||
switchInt((_1.0: u32)) -> [1_u32: bb2, 4_u32: bb2, otherwise: bb1]; // scope 0 at $DIR/exponential-or.rs:6:15: 6:16
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ fn main() -> () {
|
||||
bb0: {
|
||||
StorageLive(_1); // scope 0 at $DIR/issue-38669.rs:5:9: 5:25
|
||||
_1 = const false; // scope 0 at $DIR/issue-38669.rs:5:28: 5:33
|
||||
FakeRead(ForLet, _1); // scope 0 at $DIR/issue-38669.rs:5:9: 5:25
|
||||
FakeRead(ForLet(None), _1); // scope 0 at $DIR/issue-38669.rs:5:9: 5:25
|
||||
goto -> bb1; // scope 1 at $DIR/issue-38669.rs:6:5: 11:6
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ fn main() -> () {
|
||||
StorageLive(_2); // scope 0 at $DIR/issue-49232.rs:7:13: 7:19
|
||||
StorageLive(_3); // scope 0 at $DIR/issue-49232.rs:8:19: 8:23
|
||||
_3 = const true; // scope 0 at $DIR/issue-49232.rs:8:19: 8:23
|
||||
FakeRead(ForMatchedPlace, _3); // scope 0 at $DIR/issue-49232.rs:8:19: 8:23
|
||||
FakeRead(ForMatchedPlace(None), _3); // scope 0 at $DIR/issue-49232.rs:8:19: 8:23
|
||||
switchInt(_3) -> [false: bb3, otherwise: bb4]; // scope 0 at $DIR/issue-49232.rs:9:17: 9:22
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ fn main() -> () {
|
||||
}
|
||||
|
||||
bb8: {
|
||||
FakeRead(ForLet, _2); // scope 0 at $DIR/issue-49232.rs:7:13: 7:19
|
||||
FakeRead(ForLet(None), _2); // scope 0 at $DIR/issue-49232.rs:7:13: 7:19
|
||||
StorageDead(_3); // scope 0 at $DIR/issue-49232.rs:12:10: 12:11
|
||||
StorageLive(_5); // scope 1 at $DIR/issue-49232.rs:13:9: 13:22
|
||||
StorageLive(_6); // scope 1 at $DIR/issue-49232.rs:13:14: 13:21
|
||||
|
@ -38,7 +38,7 @@ fn main() -> () {
|
||||
_2 = [move _3, move _4]; // scope 1 at $DIR/issue-72181.rs:26:13: 26:43
|
||||
StorageDead(_4); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43
|
||||
StorageDead(_3); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43
|
||||
FakeRead(ForLet, _2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10
|
||||
FakeRead(ForLet(None), _2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10
|
||||
StorageLive(_5); // scope 2 at $DIR/issue-72181.rs:27:13: 27:30
|
||||
StorageLive(_6); // scope 4 at $DIR/issue-72181.rs:27:24: 27:25
|
||||
_6 = const 0_usize; // scope 4 at $DIR/issue-72181.rs:27:24: 27:25
|
||||
|
@ -38,7 +38,7 @@ fn main() -> () {
|
||||
_2 = [move _3, move _4]; // scope 1 at $DIR/issue-72181.rs:26:13: 26:43
|
||||
StorageDead(_4); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43
|
||||
StorageDead(_3); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43
|
||||
FakeRead(ForLet, _2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10
|
||||
FakeRead(ForLet(None), _2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10
|
||||
StorageLive(_5); // scope 2 at $DIR/issue-72181.rs:27:13: 27:30
|
||||
StorageLive(_6); // scope 4 at $DIR/issue-72181.rs:27:24: 27:25
|
||||
_6 = const 0_usize; // scope 4 at $DIR/issue-72181.rs:27:24: 27:25
|
||||
|
@ -9,7 +9,7 @@ fn f(_1: Void) -> ! {
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $DIR/issue-72181-1.rs:10:20: 12:2
|
||||
StorageLive(_3); // scope 0 at $DIR/issue-72181-1.rs:11:5: 11:15
|
||||
FakeRead(ForMatchedPlace, _1); // scope 0 at $DIR/issue-72181-1.rs:11:11: 11:12
|
||||
FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/issue-72181-1.rs:11:11: 11:12
|
||||
unreachable; // scope 0 at $DIR/issue-72181-1.rs:11:11: 11:12
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ fn main() -> () {
|
||||
|
||||
bb1: {
|
||||
StorageDead(_3); // scope 2 at $DIR/issue-72181-1.rs:17:43: 17:44
|
||||
FakeRead(ForLet, _2); // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10
|
||||
FakeRead(ForLet(None), _2); // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10
|
||||
AscribeUserType(_2, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at $DIR/issue-72181-1.rs:16:12: 16:16
|
||||
StorageLive(_4); // scope 1 at $DIR/issue-72181-1.rs:20:5: 20:9
|
||||
StorageLive(_5); // scope 1 at $DIR/issue-72181-1.rs:20:7: 20:8
|
||||
|
@ -41,7 +41,7 @@ fn main() -> () {
|
||||
bb4: {
|
||||
StorageLive(_6); // scope 0 at $DIR/loop_test.rs:14:13: 14:14
|
||||
_6 = const 1_i32; // scope 0 at $DIR/loop_test.rs:14:17: 14:18
|
||||
FakeRead(ForLet, _6); // scope 0 at $DIR/loop_test.rs:14:13: 14:14
|
||||
FakeRead(ForLet(None), _6); // scope 0 at $DIR/loop_test.rs:14:13: 14:14
|
||||
StorageDead(_6); // scope 0 at $DIR/loop_test.rs:16:5: 16:6
|
||||
goto -> bb3; // scope 0 at $DIR/loop_test.rs:1:1: 1:1
|
||||
}
|
||||
|
@ -31,7 +31,7 @@
|
||||
}
|
||||
|
||||
bb0: {
|
||||
- FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16
|
||||
- FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16
|
||||
- switchInt((_2.0: bool)) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/match-arm-scopes.rs:15:10: 15:15
|
||||
+ switchInt((_2.0: bool)) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/match-arm-scopes.rs:15:10: 15:15
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ fn full_tested_match() -> () {
|
||||
StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:15:13: 19:6
|
||||
StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27
|
||||
_2 = Option::<i32>::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27
|
||||
FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27
|
||||
FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27
|
||||
_3 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:16:9: 16:16
|
||||
switchInt(move _3) -> [0_isize: bb1, 1_isize: bb2, otherwise: bb4]; // scope 0 at $DIR/match_false_edges.rs:16:9: 16:16
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ fn full_tested_match2() -> () {
|
||||
StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:26:13: 30:6
|
||||
StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27
|
||||
_2 = Option::<i32>::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27
|
||||
FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27
|
||||
FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27
|
||||
_3 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:27:9: 27:16
|
||||
switchInt(move _3) -> [0_isize: bb1, 1_isize: bb2, otherwise: bb4]; // scope 0 at $DIR/match_false_edges.rs:27:9: 27:16
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ fn main() -> () {
|
||||
StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:35:13: 40:6
|
||||
StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26
|
||||
_2 = Option::<i32>::Some(const 1_i32); // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26
|
||||
FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26
|
||||
FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26
|
||||
_4 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:36:9: 36:17
|
||||
switchInt(move _4) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/match_false_edges.rs:36:9: 36:17
|
||||
}
|
||||
|
@ -21,12 +21,12 @@ fn main() -> () {
|
||||
bb0: {
|
||||
StorageLive(_1); // scope 0 at $DIR/match_test.rs:7:9: 7:10
|
||||
_1 = const 3_i32; // scope 0 at $DIR/match_test.rs:7:13: 7:14
|
||||
FakeRead(ForLet, _1); // scope 0 at $DIR/match_test.rs:7:9: 7:10
|
||||
FakeRead(ForLet(None), _1); // scope 0 at $DIR/match_test.rs:7:9: 7:10
|
||||
StorageLive(_2); // scope 1 at $DIR/match_test.rs:8:9: 8:10
|
||||
_2 = const true; // scope 1 at $DIR/match_test.rs:8:13: 8:17
|
||||
FakeRead(ForLet, _2); // scope 1 at $DIR/match_test.rs:8:9: 8:10
|
||||
FakeRead(ForLet(None), _2); // scope 1 at $DIR/match_test.rs:8:9: 8:10
|
||||
StorageLive(_3); // scope 2 at $DIR/match_test.rs:12:5: 17:6
|
||||
FakeRead(ForMatchedPlace, _1); // scope 2 at $DIR/match_test.rs:12:11: 12:12
|
||||
FakeRead(ForMatchedPlace(None), _1); // scope 2 at $DIR/match_test.rs:12:11: 12:12
|
||||
_6 = Le(const 0_i32, _1); // scope 2 at $DIR/match_test.rs:13:9: 13:14
|
||||
switchInt(move _6) -> [false: bb4, otherwise: bb1]; // scope 2 at $DIR/match_test.rs:13:9: 13:14
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ fn main() -> () {
|
||||
bb0: {
|
||||
StorageLive(_1); // bb0[0]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14
|
||||
_1 = [const Const(Value(Scalar(0x00000001)): usize), const Const(Value(Scalar(0x00000002)): usize), const Const(Value(Scalar(0x00000003)): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:17:17: 17:26
|
||||
FakeRead(ForLet, _1); // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14
|
||||
FakeRead(ForLet(None), _1); // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14
|
||||
StorageLive(_2); // bb0[3]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10
|
||||
StorageLive(_3); // bb0[4]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
|
||||
_3 = const Const(Value(Scalar(0x00000000)): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
|
||||
@ -57,10 +57,10 @@ fn main() -> () {
|
||||
|
||||
bb1: {
|
||||
_2 = &'_#3r _1[_3]; // bb1[0]: scope 1 at $DIR/region-subtyping-basic.rs:18:13: 18:18
|
||||
FakeRead(ForLet, _2); // bb1[1]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10
|
||||
FakeRead(ForLet(None), _2); // bb1[1]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10
|
||||
StorageLive(_6); // bb1[2]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10
|
||||
_6 = _2; // bb1[3]: scope 2 at $DIR/region-subtyping-basic.rs:19:13: 19:14
|
||||
FakeRead(ForLet, _6); // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10
|
||||
FakeRead(ForLet(None), _6); // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10
|
||||
StorageLive(_7); // bb1[5]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
|
||||
_7 = const Const(Value(Scalar(0x01)): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
|
||||
switchInt(move _7) -> [Const(Value(Scalar(0x00)): bool): bb3, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
|
||||
|
@ -46,7 +46,7 @@ fn main() -> () {
|
||||
bb0: {
|
||||
StorageLive(_1); // bb0[0]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14
|
||||
_1 = [const Const(Value(Scalar(0x0000000000000001)): usize), const Const(Value(Scalar(0x0000000000000002)): usize), const Const(Value(Scalar(0x0000000000000003)): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:17:17: 17:26
|
||||
FakeRead(ForLet, _1); // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14
|
||||
FakeRead(ForLet(None), _1); // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14
|
||||
StorageLive(_2); // bb0[3]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10
|
||||
StorageLive(_3); // bb0[4]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
|
||||
_3 = const Const(Value(Scalar(0x0000000000000000)): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
|
||||
@ -57,10 +57,10 @@ fn main() -> () {
|
||||
|
||||
bb1: {
|
||||
_2 = &'_#3r _1[_3]; // bb1[0]: scope 1 at $DIR/region-subtyping-basic.rs:18:13: 18:18
|
||||
FakeRead(ForLet, _2); // bb1[1]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10
|
||||
FakeRead(ForLet(None), _2); // bb1[1]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10
|
||||
StorageLive(_6); // bb1[2]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10
|
||||
_6 = _2; // bb1[3]: scope 2 at $DIR/region-subtyping-basic.rs:19:13: 19:14
|
||||
FakeRead(ForLet, _6); // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10
|
||||
FakeRead(ForLet(None), _6); // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10
|
||||
StorageLive(_7); // bb1[5]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
|
||||
_7 = const Const(Value(Scalar(0x01)): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
|
||||
switchInt(move _7) -> [Const(Value(Scalar(0x00)): bool): bb3, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
|
||||
|
@ -36,7 +36,7 @@ fn main() -> () {
|
||||
}
|
||||
|
||||
bb1: {
|
||||
FakeRead(ForLet, _1); // scope 0 at $DIR/receiver-ptr-mutability.rs:14:9: 14:12
|
||||
FakeRead(ForLet(None), _1); // scope 0 at $DIR/receiver-ptr-mutability.rs:14:9: 14:12
|
||||
AscribeUserType(_1, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at $DIR/receiver-ptr-mutability.rs:14:14: 14:23
|
||||
StorageLive(_2); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:12
|
||||
StorageLive(_3); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:8
|
||||
@ -63,7 +63,7 @@ fn main() -> () {
|
||||
_7 = &_8; // scope 1 at $DIR/receiver-ptr-mutability.rs:18:35: 18:41
|
||||
_6 = &_7; // scope 1 at $DIR/receiver-ptr-mutability.rs:18:34: 18:41
|
||||
_5 = &(*_6); // scope 1 at $DIR/receiver-ptr-mutability.rs:18:34: 18:41
|
||||
FakeRead(ForLet, _5); // scope 1 at $DIR/receiver-ptr-mutability.rs:18:9: 18:16
|
||||
FakeRead(ForLet(None), _5); // scope 1 at $DIR/receiver-ptr-mutability.rs:18:9: 18:16
|
||||
AscribeUserType(_5, o, UserTypeProjection { base: UserType(3), projs: [] }); // scope 1 at $DIR/receiver-ptr-mutability.rs:18:18: 18:31
|
||||
StorageDead(_6); // scope 1 at $DIR/receiver-ptr-mutability.rs:18:41: 18:42
|
||||
StorageLive(_10); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16
|
||||
|
@ -13,7 +13,7 @@
|
||||
let mut _8: bool; // in scope 0 at $DIR/remove_fake_borrows.rs:8:20: 8:21
|
||||
|
||||
bb0: {
|
||||
- FakeRead(ForMatchedPlace, _1); // scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12
|
||||
- FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12
|
||||
+ nop; // scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12
|
||||
_3 = discriminant(_1); // scope 0 at $DIR/remove_fake_borrows.rs:8:9: 8:16
|
||||
switchInt(move _3) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:8:9: 8:16
|
||||
|
@ -5,7 +5,7 @@ fn match_bool(_1: bool) -> usize {
|
||||
let mut _0: usize; // return place in scope 0 at $DIR/simple-match.rs:5:27: 5:32
|
||||
|
||||
bb0: {
|
||||
FakeRead(ForMatchedPlace, _1); // scope 0 at $DIR/simple-match.rs:6:11: 6:12
|
||||
FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/simple-match.rs:6:11: 6:12
|
||||
switchInt(_1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/simple-match.rs:7:9: 7:13
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ fn match_bool(_1: bool) -> usize {
|
||||
let mut _0: usize; // return place in scope 0 at $DIR/simple-match.rs:5:27: 5:32
|
||||
|
||||
bb0: {
|
||||
FakeRead(ForMatchedPlace, _1); // scope 0 at $DIR/simple-match.rs:6:11: 6:12
|
||||
FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/simple-match.rs:6:11: 6:12
|
||||
switchInt(_1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/simple-match.rs:7:9: 7:13
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ fn main() -> () {
|
||||
bb0: {
|
||||
StorageLive(_1); // scope 0 at $DIR/storage_ranges.rs:4:9: 4:10
|
||||
_1 = const 0_i32; // scope 0 at $DIR/storage_ranges.rs:4:13: 4:14
|
||||
FakeRead(ForLet, _1); // scope 0 at $DIR/storage_ranges.rs:4:9: 4:10
|
||||
FakeRead(ForLet(None), _1); // scope 0 at $DIR/storage_ranges.rs:4:9: 4:10
|
||||
StorageLive(_2); // scope 1 at $DIR/storage_ranges.rs:5:5: 7:6
|
||||
StorageLive(_3); // scope 1 at $DIR/storage_ranges.rs:6:13: 6:14
|
||||
StorageLive(_4); // scope 1 at $DIR/storage_ranges.rs:6:18: 6:25
|
||||
@ -48,14 +48,14 @@ fn main() -> () {
|
||||
_4 = Option::<i32>::Some(move _5); // scope 1 at $DIR/storage_ranges.rs:6:18: 6:25
|
||||
StorageDead(_5); // scope 1 at $DIR/storage_ranges.rs:6:24: 6:25
|
||||
_3 = &_4; // scope 1 at $DIR/storage_ranges.rs:6:17: 6:25
|
||||
FakeRead(ForLet, _3); // scope 1 at $DIR/storage_ranges.rs:6:13: 6:14
|
||||
FakeRead(ForLet(None), _3); // scope 1 at $DIR/storage_ranges.rs:6:13: 6:14
|
||||
_2 = const (); // scope 1 at $DIR/storage_ranges.rs:5:5: 7:6
|
||||
StorageDead(_4); // scope 1 at $DIR/storage_ranges.rs:7:5: 7:6
|
||||
StorageDead(_3); // scope 1 at $DIR/storage_ranges.rs:7:5: 7:6
|
||||
StorageDead(_2); // scope 1 at $DIR/storage_ranges.rs:7:5: 7:6
|
||||
StorageLive(_6); // scope 1 at $DIR/storage_ranges.rs:8:9: 8:10
|
||||
_6 = const 1_i32; // scope 1 at $DIR/storage_ranges.rs:8:13: 8:14
|
||||
FakeRead(ForLet, _6); // scope 1 at $DIR/storage_ranges.rs:8:9: 8:10
|
||||
FakeRead(ForLet(None), _6); // scope 1 at $DIR/storage_ranges.rs:8:9: 8:10
|
||||
_0 = const (); // scope 0 at $DIR/storage_ranges.rs:3:11: 9:2
|
||||
StorageDead(_6); // scope 1 at $DIR/storage_ranges.rs:9:1: 9:2
|
||||
StorageDead(_1); // scope 0 at $DIR/storage_ranges.rs:9:1: 9:2
|
||||
|
@ -48,7 +48,7 @@ fn move_out_by_subslice() -> () {
|
||||
|
||||
bb4: {
|
||||
StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
|
||||
FakeRead(ForLet, _1); // scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10
|
||||
FakeRead(ForLet(None), _1); // scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10
|
||||
StorageLive(_6); // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17
|
||||
_6 = move _1[0..2]; // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17
|
||||
_0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:10:27: 13:2
|
||||
|
@ -48,7 +48,7 @@ fn move_out_from_end() -> () {
|
||||
|
||||
bb4: {
|
||||
StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
|
||||
FakeRead(ForLet, _1); // scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10
|
||||
FakeRead(ForLet(None), _1); // scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10
|
||||
StorageLive(_6); // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16
|
||||
_6 = move _1[1 of 2]; // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16
|
||||
_0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:4:24: 7:2
|
||||
|
@ -212,7 +212,7 @@ fn check_statement(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, statemen
|
||||
check_rvalue(tcx, body, def_id, rval, span)
|
||||
}
|
||||
|
||||
StatementKind::FakeRead(_, place) |
|
||||
StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body),
|
||||
// just an assignment
|
||||
StatementKind::SetDiscriminant { place, .. } => check_place(tcx, **place, span, body),
|
||||
|
||||
|
@ -909,7 +909,8 @@ fn extract_gdb_version(full_version_line: &str) -> Option<u32> {
|
||||
// This particular form is documented in the GNU coding standards:
|
||||
// https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html#g_t_002d_002dversion
|
||||
|
||||
let mut splits = full_version_line.rsplit(' ');
|
||||
let unbracketed_part = full_version_line.split('[').next().unwrap();
|
||||
let mut splits = unbracketed_part.trim_end().rsplit(' ');
|
||||
let version_string = splits.next().unwrap();
|
||||
|
||||
let mut splits = version_string.split('.');
|
||||
|
@ -39,6 +39,9 @@ fn test_extract_gdb_version() {
|
||||
7012000: "GNU gdb (GDB) 7.12",
|
||||
7012000: "GNU gdb (GDB) 7.12.20161027-git",
|
||||
7012050: "GNU gdb (GDB) 7.12.50.20161027-git",
|
||||
|
||||
9002000: "GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2",
|
||||
10001000: "GNU gdb (GDB) 10.1 [GDB v10.1 for FreeBSD]",
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user