mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-06 06:57:42 +00:00
Auto merge of #56231 - eddyb:mir-debuginfo, r=oli-obk
rustc: move debug info from LocalDecl and UpvarDecl into a dedicated VarDebugInfo. This PR introduces a MIR "user variable" debuginfo system, which amounts to mapping a variable name, in some `SourceScope`, to a `Place`, so that: * each name can appear multiple times (e.g. due to macro hygiene), even in the same scope * each `Place` can appear multiple times (e.g. in the future from optimizations like NRVO, which collapse multiple MIR locals into one) * the `Place`s aren't limited to just locals, so they can describe the (right now quite ad-hoc) closure upvars and generator saved state fields, and can be properly transformed by optimizations (e.g. inlining - see `src/test/mir-opt/inline-closure-captures.rs`) The main motivation for this was that #48300 and further optimizations were blocked on being able to describe complex debuginfo transformations (see https://github.com/rust-lang/rust/pull/48300#discussion_r170020762). <hr/> In the textual representation, the "user variable" debuginfo can be found in each scope, and consists of `debug NAME => PLACE;` "declarations", e.g. the MIR for `let x = ...; let y = ...; ...` is now: ```rust let _1: T; // in scope 0 at ... scope 1 { debug x => _1; // in scope 1 at ... let _2: T; // in scope 1 at ... scope 2 { debug y => _2; // in scope 2 at ... } } ``` For reference, this is how the information was represented before this PR: (notably, the scopes in which the variables are visible for debuginfo weren't even shown anywhere, making `scope 2` look pointless, and user variable names were part of MIR locals) ```rust let _1: T; // "x" in scope 0 at ... scope 1 { let _2: T; // "y" in scope 1 at ... scope 2 { } } ``` cc @nikomatsakis @michaelwoerister
This commit is contained in:
commit
e87a205c2e
@ -141,14 +141,8 @@ pub struct Body<'tcx> {
|
|||||||
/// This is used for the "rust-call" ABI.
|
/// This is used for the "rust-call" ABI.
|
||||||
pub spread_arg: Option<Local>,
|
pub spread_arg: Option<Local>,
|
||||||
|
|
||||||
/// Names and capture modes of all the closure upvars, assuming
|
/// Debug information pertaining to user variables, including captures.
|
||||||
/// the first argument is either the closure or a reference to it.
|
pub var_debug_info: Vec<VarDebugInfo<'tcx>>,
|
||||||
//
|
|
||||||
// NOTE(eddyb) This is *strictly* a temporary hack for codegen
|
|
||||||
// debuginfo generation, and will be removed at some point.
|
|
||||||
// Do **NOT** use it for anything else; upvar information should not be
|
|
||||||
// in the MIR, so please rely on local crate HIR or other side-channels.
|
|
||||||
pub __upvar_debuginfo_codegen_only_do_not_use: Vec<UpvarDebuginfo>,
|
|
||||||
|
|
||||||
/// Mark this MIR of a const context other than const functions as having converted a `&&` or
|
/// Mark this MIR of a const context other than const functions as having converted a `&&` or
|
||||||
/// `||` expression into `&` or `|` respectively. This is problematic because if we ever stop
|
/// `||` expression into `&` or `|` respectively. This is problematic because if we ever stop
|
||||||
@ -170,11 +164,10 @@ impl<'tcx> Body<'tcx> {
|
|||||||
basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
|
basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
|
||||||
source_scopes: IndexVec<SourceScope, SourceScopeData>,
|
source_scopes: IndexVec<SourceScope, SourceScopeData>,
|
||||||
source_scope_local_data: ClearCrossCrate<IndexVec<SourceScope, SourceScopeLocalData>>,
|
source_scope_local_data: ClearCrossCrate<IndexVec<SourceScope, SourceScopeLocalData>>,
|
||||||
yield_ty: Option<Ty<'tcx>>,
|
|
||||||
local_decls: LocalDecls<'tcx>,
|
local_decls: LocalDecls<'tcx>,
|
||||||
user_type_annotations: CanonicalUserTypeAnnotations<'tcx>,
|
user_type_annotations: CanonicalUserTypeAnnotations<'tcx>,
|
||||||
arg_count: usize,
|
arg_count: usize,
|
||||||
__upvar_debuginfo_codegen_only_do_not_use: Vec<UpvarDebuginfo>,
|
var_debug_info: Vec<VarDebugInfo<'tcx>>,
|
||||||
span: Span,
|
span: Span,
|
||||||
control_flow_destroyed: Vec<(Span, String)>,
|
control_flow_destroyed: Vec<(Span, String)>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@ -191,14 +184,14 @@ impl<'tcx> Body<'tcx> {
|
|||||||
basic_blocks,
|
basic_blocks,
|
||||||
source_scopes,
|
source_scopes,
|
||||||
source_scope_local_data,
|
source_scope_local_data,
|
||||||
yield_ty,
|
yield_ty: None,
|
||||||
generator_drop: None,
|
generator_drop: None,
|
||||||
generator_layout: None,
|
generator_layout: None,
|
||||||
local_decls,
|
local_decls,
|
||||||
user_type_annotations,
|
user_type_annotations,
|
||||||
arg_count,
|
arg_count,
|
||||||
__upvar_debuginfo_codegen_only_do_not_use,
|
|
||||||
spread_arg: None,
|
spread_arg: None,
|
||||||
|
var_debug_info,
|
||||||
span,
|
span,
|
||||||
cache: cache::Cache::new(),
|
cache: cache::Cache::new(),
|
||||||
control_flow_destroyed,
|
control_flow_destroyed,
|
||||||
@ -280,7 +273,7 @@ impl<'tcx> Body<'tcx> {
|
|||||||
LocalKind::ReturnPointer
|
LocalKind::ReturnPointer
|
||||||
} else if index < self.arg_count + 1 {
|
} else if index < self.arg_count + 1 {
|
||||||
LocalKind::Arg
|
LocalKind::Arg
|
||||||
} else if self.local_decls[local].name.is_some() {
|
} else if self.local_decls[local].is_user_variable() {
|
||||||
LocalKind::Var
|
LocalKind::Var
|
||||||
} else {
|
} else {
|
||||||
LocalKind::Temp
|
LocalKind::Temp
|
||||||
@ -728,12 +721,6 @@ pub struct LocalDecl<'tcx> {
|
|||||||
// FIXME(matthewjasper) Don't store in this in `Body`
|
// FIXME(matthewjasper) Don't store in this in `Body`
|
||||||
pub user_ty: UserTypeProjections,
|
pub user_ty: UserTypeProjections,
|
||||||
|
|
||||||
/// The name of the local, used in debuginfo and pretty-printing.
|
|
||||||
///
|
|
||||||
/// Note that function arguments can also have this set to `Some(_)`
|
|
||||||
/// to generate better debuginfo.
|
|
||||||
pub name: Option<Name>,
|
|
||||||
|
|
||||||
/// The *syntactic* (i.e., not visibility) source scope the local is defined
|
/// The *syntactic* (i.e., not visibility) source scope the local is defined
|
||||||
/// in. If the local was defined in a let-statement, this
|
/// in. If the local was defined in a let-statement, this
|
||||||
/// is *within* the let-statement, rather than outside
|
/// is *within* the let-statement, rather than outside
|
||||||
@ -785,9 +772,9 @@ pub struct LocalDecl<'tcx> {
|
|||||||
/// `drop(x)`, we want it to refer to `x: u32`.
|
/// `drop(x)`, we want it to refer to `x: u32`.
|
||||||
///
|
///
|
||||||
/// To allow both uses to work, we need to have more than a single scope
|
/// To allow both uses to work, we need to have more than a single scope
|
||||||
/// for a local. We have the `source_info.scope` represent the
|
/// for a local. We have the `source_info.scope` represent the "syntactic"
|
||||||
/// "syntactic" lint scope (with a variable being under its let
|
/// lint scope (with a variable being under its let block) while the
|
||||||
/// block) while the `visibility_scope` represents the "local variable"
|
/// `var_debug_info.source_info.scope` represents the "local variable"
|
||||||
/// scope (where the "rest" of a block is under all prior let-statements).
|
/// scope (where the "rest" of a block is under all prior let-statements).
|
||||||
///
|
///
|
||||||
/// The end result looks like this:
|
/// The end result looks like this:
|
||||||
@ -806,18 +793,14 @@ pub struct LocalDecl<'tcx> {
|
|||||||
/// │ │
|
/// │ │
|
||||||
/// │ │ │{ let y: u32 }
|
/// │ │ │{ let y: u32 }
|
||||||
/// │ │ │
|
/// │ │ │
|
||||||
/// │ │ │← y.visibility_scope
|
/// │ │ │← y.var_debug_info.source_info.scope
|
||||||
/// │ │ │← `y + 2`
|
/// │ │ │← `y + 2`
|
||||||
/// │
|
/// │
|
||||||
/// │ │{ let x: u32 }
|
/// │ │{ let x: u32 }
|
||||||
/// │ │← x.visibility_scope
|
/// │ │← x.var_debug_info.source_info.scope
|
||||||
/// │ │← `drop(x)` // This accesses `x: u32`.
|
/// │ │← `drop(x)` // This accesses `x: u32`.
|
||||||
/// ```
|
/// ```
|
||||||
pub source_info: SourceInfo,
|
pub source_info: SourceInfo,
|
||||||
|
|
||||||
/// Source scope within which the local is visible (for debuginfo)
|
|
||||||
/// (see `source_info` for more details).
|
|
||||||
pub visibility_scope: SourceScope,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extra information about a local that's used for diagnostics.
|
/// Extra information about a local that's used for diagnostics.
|
||||||
@ -955,9 +938,7 @@ impl<'tcx> LocalDecl<'tcx> {
|
|||||||
mutability,
|
mutability,
|
||||||
ty,
|
ty,
|
||||||
user_ty: UserTypeProjections::none(),
|
user_ty: UserTypeProjections::none(),
|
||||||
name: None,
|
|
||||||
source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE },
|
source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE },
|
||||||
visibility_scope: OUTERMOST_SOURCE_SCOPE,
|
|
||||||
internal,
|
internal,
|
||||||
local_info: LocalInfo::Other,
|
local_info: LocalInfo::Other,
|
||||||
is_block_tail: None,
|
is_block_tail: None,
|
||||||
@ -974,22 +955,27 @@ impl<'tcx> LocalDecl<'tcx> {
|
|||||||
ty: return_ty,
|
ty: return_ty,
|
||||||
user_ty: UserTypeProjections::none(),
|
user_ty: UserTypeProjections::none(),
|
||||||
source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE },
|
source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE },
|
||||||
visibility_scope: OUTERMOST_SOURCE_SCOPE,
|
|
||||||
internal: false,
|
internal: false,
|
||||||
is_block_tail: None,
|
is_block_tail: None,
|
||||||
name: None, // FIXME maybe we do want some name here?
|
|
||||||
local_info: LocalInfo::Other,
|
local_info: LocalInfo::Other,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A closure capture, with its name and mode.
|
/// Debug information pertaining to a user variable.
|
||||||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
|
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
|
||||||
pub struct UpvarDebuginfo {
|
pub struct VarDebugInfo<'tcx> {
|
||||||
pub debug_name: Name,
|
pub name: Name,
|
||||||
|
|
||||||
/// If true, the capture is behind a reference.
|
/// Source info of the user variable, including the scope
|
||||||
pub by_ref: bool,
|
/// within which the variable is visible (to debuginfo)
|
||||||
|
/// (see `LocalDecl`'s `source_info` field for more details).
|
||||||
|
pub source_info: SourceInfo,
|
||||||
|
|
||||||
|
/// Where the data for this user variable is to be found.
|
||||||
|
/// NOTE(eddyb) There's an unenforced invariant that this `Place` is
|
||||||
|
/// based on a `Local`, not a `Static`, and contains no indexing.
|
||||||
|
pub place: Place<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
@ -2758,16 +2744,6 @@ pub struct GeneratorLayout<'tcx> {
|
|||||||
/// have conflicts with each other are allowed to overlap in the computed
|
/// have conflicts with each other are allowed to overlap in the computed
|
||||||
/// layout.
|
/// layout.
|
||||||
pub storage_conflicts: BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal>,
|
pub storage_conflicts: BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal>,
|
||||||
|
|
||||||
/// The names and scopes of all the stored generator locals.
|
|
||||||
///
|
|
||||||
/// N.B., this is *strictly* a temporary hack for codegen
|
|
||||||
/// debuginfo generation, and will be removed at some point.
|
|
||||||
/// Do **NOT** use it for anything else, local information should not be
|
|
||||||
/// in the MIR, please rely on local crate HIR or other side-channels.
|
|
||||||
//
|
|
||||||
// FIXME(tmandry): see above.
|
|
||||||
pub __local_debuginfo_codegen_only_do_not_use: IndexVec<GeneratorSavedLocal, LocalDecl<'tcx>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
|
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
|
||||||
@ -2946,7 +2922,6 @@ CloneTypeFoldableAndLiftImpls! {
|
|||||||
MirPhase,
|
MirPhase,
|
||||||
Mutability,
|
Mutability,
|
||||||
SourceInfo,
|
SourceInfo,
|
||||||
UpvarDebuginfo,
|
|
||||||
FakeReadCause,
|
FakeReadCause,
|
||||||
RetagKind,
|
RetagKind,
|
||||||
SourceScope,
|
SourceScope,
|
||||||
|
@ -221,6 +221,11 @@ macro_rules! make_mir_visitor {
|
|||||||
self.super_local_decl(local, local_decl);
|
self.super_local_decl(local, local_decl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_var_debug_info(&mut self,
|
||||||
|
var_debug_info: & $($mutability)* VarDebugInfo<'tcx>) {
|
||||||
|
self.super_var_debug_info(var_debug_info);
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_local(&mut self,
|
fn visit_local(&mut self,
|
||||||
_local: & $($mutability)? Local,
|
_local: & $($mutability)? Local,
|
||||||
_context: PlaceContext,
|
_context: PlaceContext,
|
||||||
@ -279,6 +284,10 @@ macro_rules! make_mir_visitor {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for var_debug_info in &$($mutability)? body.var_debug_info {
|
||||||
|
self.visit_var_debug_info(var_debug_info);
|
||||||
|
}
|
||||||
|
|
||||||
self.visit_span(&$($mutability)? body.span);
|
self.visit_span(&$($mutability)? body.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -687,9 +696,7 @@ macro_rules! make_mir_visitor {
|
|||||||
mutability: _,
|
mutability: _,
|
||||||
ty,
|
ty,
|
||||||
user_ty,
|
user_ty,
|
||||||
name: _,
|
|
||||||
source_info,
|
source_info,
|
||||||
visibility_scope,
|
|
||||||
internal: _,
|
internal: _,
|
||||||
local_info: _,
|
local_info: _,
|
||||||
is_block_tail: _,
|
is_block_tail: _,
|
||||||
@ -703,7 +710,23 @@ macro_rules! make_mir_visitor {
|
|||||||
self.visit_user_type_projection(user_ty);
|
self.visit_user_type_projection(user_ty);
|
||||||
}
|
}
|
||||||
self.visit_source_info(source_info);
|
self.visit_source_info(source_info);
|
||||||
self.visit_source_scope(visibility_scope);
|
}
|
||||||
|
|
||||||
|
fn super_var_debug_info(&mut self,
|
||||||
|
var_debug_info: & $($mutability)? VarDebugInfo<'tcx>) {
|
||||||
|
let VarDebugInfo {
|
||||||
|
name: _,
|
||||||
|
source_info,
|
||||||
|
place,
|
||||||
|
} = var_debug_info;
|
||||||
|
|
||||||
|
self.visit_source_info(source_info);
|
||||||
|
let location = START_BLOCK.start_location();
|
||||||
|
self.visit_place(
|
||||||
|
place,
|
||||||
|
PlaceContext::NonUse(NonUseContext::VarDebugInfo),
|
||||||
|
location,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn super_source_scope(&mut self,
|
fn super_source_scope(&mut self,
|
||||||
@ -1029,6 +1052,8 @@ pub enum NonUseContext {
|
|||||||
StorageDead,
|
StorageDead,
|
||||||
/// User type annotation assertions for NLL.
|
/// User type annotation assertions for NLL.
|
||||||
AscribeUserTy,
|
AscribeUserTy,
|
||||||
|
/// The data of an user variable, for debug info.
|
||||||
|
VarDebugInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
@ -23,12 +23,10 @@ pub fn compute_mir_scopes(
|
|||||||
) {
|
) {
|
||||||
// Find all the scopes with variables defined in them.
|
// Find all the scopes with variables defined in them.
|
||||||
let mut has_variables = BitSet::new_empty(mir.source_scopes.len());
|
let mut has_variables = BitSet::new_empty(mir.source_scopes.len());
|
||||||
// FIXME(eddyb) base this on `decl.name`, or even better, on debuginfo.
|
|
||||||
// FIXME(eddyb) take into account that arguments always have debuginfo,
|
// FIXME(eddyb) take into account that arguments always have debuginfo,
|
||||||
// irrespective of their name (assuming full debuginfo is enabled).
|
// irrespective of their name (assuming full debuginfo is enabled).
|
||||||
for var in mir.vars_iter() {
|
for var_debug_info in &mir.var_debug_info {
|
||||||
let decl = &mir.local_decls[var];
|
has_variables.insert(var_debug_info.source_info.scope);
|
||||||
has_variables.insert(decl.visibility_scope);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instantiate all scopes.
|
// Instantiate all scopes.
|
||||||
|
@ -17,13 +17,13 @@ use crate::llvm_util;
|
|||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
|
|
||||||
use rustc_codegen_ssa::traits::*;
|
use rustc_codegen_ssa::traits::*;
|
||||||
|
use rustc_index::vec::{Idx, IndexVec};
|
||||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||||
use rustc::hir::CodegenFnAttrFlags;
|
use rustc::hir::CodegenFnAttrFlags;
|
||||||
use rustc::hir::def::CtorKind;
|
use rustc::hir::def::CtorKind;
|
||||||
use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
|
use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
|
||||||
use rustc::ich::NodeIdHashingMode;
|
use rustc::ich::NodeIdHashingMode;
|
||||||
use rustc::mir::Field;
|
use rustc::mir::{self, Field, GeneratorLayout};
|
||||||
use rustc::mir::GeneratorLayout;
|
|
||||||
use rustc::mir::interpret::truncate;
|
use rustc::mir::interpret::truncate;
|
||||||
use rustc_data_structures::fingerprint::Fingerprint;
|
use rustc_data_structures::fingerprint::Fingerprint;
|
||||||
use rustc::ty::Instance;
|
use rustc::ty::Instance;
|
||||||
@ -1316,6 +1316,45 @@ fn use_enum_fallback(cx: &CodegenCx<'_, '_>) -> bool {
|
|||||||
|| llvm_util::get_major_version() < 8;
|
|| llvm_util::get_major_version() < 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME(eddyb) maybe precompute this? Right now it's computed once
|
||||||
|
// per generator monomorphization, but it doesn't depend on substs.
|
||||||
|
fn generator_layout_and_saved_local_names(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
def_id: DefId,
|
||||||
|
) -> (&'tcx GeneratorLayout<'tcx>, IndexVec<mir::GeneratorSavedLocal, Option<ast::Name>>) {
|
||||||
|
let body = tcx.optimized_mir(def_id);
|
||||||
|
let generator_layout = body.generator_layout.as_ref().unwrap();
|
||||||
|
let mut generator_saved_local_names =
|
||||||
|
IndexVec::from_elem(None, &generator_layout.field_tys);
|
||||||
|
|
||||||
|
let state_arg = mir::PlaceBase::Local(mir::Local::new(1));
|
||||||
|
for var in &body.var_debug_info {
|
||||||
|
if var.place.base != state_arg {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
match var.place.projection[..] {
|
||||||
|
[
|
||||||
|
// Deref of the `Pin<&mut Self>` state argument.
|
||||||
|
mir::ProjectionElem::Field(..),
|
||||||
|
mir::ProjectionElem::Deref,
|
||||||
|
|
||||||
|
// Field of a variant of the state.
|
||||||
|
mir::ProjectionElem::Downcast(_, variant),
|
||||||
|
mir::ProjectionElem::Field(field, _),
|
||||||
|
] => {
|
||||||
|
let name = &mut generator_saved_local_names[
|
||||||
|
generator_layout.variant_fields[variant][field]
|
||||||
|
];
|
||||||
|
if name.is_none() {
|
||||||
|
name.replace(var.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(generator_layout, generator_saved_local_names)
|
||||||
|
}
|
||||||
|
|
||||||
/// Describes the members of an enum value; an enum is described as a union of
|
/// Describes the members of an enum value; an enum is described as a union of
|
||||||
/// structs in DWARF. This `MemberDescriptionFactory` provides the description for
|
/// structs in DWARF. This `MemberDescriptionFactory` provides the description for
|
||||||
/// the members of this union; so for every variant of the given enum, this
|
/// the members of this union; so for every variant of the given enum, this
|
||||||
@ -1332,12 +1371,25 @@ struct EnumMemberDescriptionFactory<'ll, 'tcx> {
|
|||||||
impl EnumMemberDescriptionFactory<'ll, 'tcx> {
|
impl EnumMemberDescriptionFactory<'ll, 'tcx> {
|
||||||
fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>)
|
fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>)
|
||||||
-> Vec<MemberDescription<'ll>> {
|
-> Vec<MemberDescription<'ll>> {
|
||||||
|
let generator_variant_info_data = match self.enum_type.kind {
|
||||||
|
ty::Generator(def_id, ..) => {
|
||||||
|
Some(generator_layout_and_saved_local_names(cx.tcx, def_id))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
let variant_info_for = |index: VariantIdx| {
|
let variant_info_for = |index: VariantIdx| {
|
||||||
match &self.enum_type.kind {
|
match self.enum_type.kind {
|
||||||
ty::Adt(adt, _) => VariantInfo::Adt(&adt.variants[index]),
|
ty::Adt(adt, _) => VariantInfo::Adt(&adt.variants[index]),
|
||||||
ty::Generator(def_id, substs, _) => {
|
ty::Generator(_, substs, _) => {
|
||||||
let generator_layout = cx.tcx.generator_layout(*def_id);
|
let (generator_layout, generator_saved_local_names) =
|
||||||
VariantInfo::Generator(substs, generator_layout, index)
|
generator_variant_info_data.as_ref().unwrap();
|
||||||
|
VariantInfo::Generator {
|
||||||
|
substs,
|
||||||
|
generator_layout: *generator_layout,
|
||||||
|
generator_saved_local_names,
|
||||||
|
variant_index: index,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
}
|
}
|
||||||
@ -1608,16 +1660,21 @@ enum EnumDiscriminantInfo<'ll> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
enum VariantInfo<'tcx> {
|
enum VariantInfo<'a, 'tcx> {
|
||||||
Adt(&'tcx ty::VariantDef),
|
Adt(&'tcx ty::VariantDef),
|
||||||
Generator(SubstsRef<'tcx>, &'tcx GeneratorLayout<'tcx>, VariantIdx),
|
Generator {
|
||||||
|
substs: SubstsRef<'tcx>,
|
||||||
|
generator_layout: &'tcx GeneratorLayout<'tcx>,
|
||||||
|
generator_saved_local_names: &'a IndexVec<mir::GeneratorSavedLocal, Option<ast::Name>>,
|
||||||
|
variant_index: VariantIdx,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> VariantInfo<'tcx> {
|
impl<'tcx> VariantInfo<'_, 'tcx> {
|
||||||
fn map_struct_name<R>(&self, f: impl FnOnce(&str) -> R) -> R {
|
fn map_struct_name<R>(&self, f: impl FnOnce(&str) -> R) -> R {
|
||||||
match self {
|
match self {
|
||||||
VariantInfo::Adt(variant) => f(&variant.ident.as_str()),
|
VariantInfo::Adt(variant) => f(&variant.ident.as_str()),
|
||||||
VariantInfo::Generator(substs, _, variant_index) =>
|
VariantInfo::Generator { substs, variant_index, .. } =>
|
||||||
f(&substs.as_generator().variant_name(*variant_index)),
|
f(&substs.as_generator().variant_name(*variant_index)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1625,7 +1682,7 @@ impl<'tcx> VariantInfo<'tcx> {
|
|||||||
fn variant_name(&self) -> String {
|
fn variant_name(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
VariantInfo::Adt(variant) => variant.ident.to_string(),
|
VariantInfo::Adt(variant) => variant.ident.to_string(),
|
||||||
VariantInfo::Generator(_, _, variant_index) => {
|
VariantInfo::Generator { variant_index, .. } => {
|
||||||
// Since GDB currently prints out the raw discriminant along
|
// Since GDB currently prints out the raw discriminant along
|
||||||
// with every variant, make each variant name be just the value
|
// with every variant, make each variant name be just the value
|
||||||
// of the discriminant. The struct name for the variant includes
|
// of the discriminant. The struct name for the variant includes
|
||||||
@ -1636,17 +1693,20 @@ impl<'tcx> VariantInfo<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn field_name(&self, i: usize) -> String {
|
fn field_name(&self, i: usize) -> String {
|
||||||
let field_name = match self {
|
let field_name = match *self {
|
||||||
VariantInfo::Adt(variant) if variant.ctor_kind != CtorKind::Fn =>
|
VariantInfo::Adt(variant) if variant.ctor_kind != CtorKind::Fn =>
|
||||||
Some(variant.fields[i].ident.to_string()),
|
Some(variant.fields[i].ident.name),
|
||||||
VariantInfo::Generator(_, generator_layout, variant_index) => {
|
VariantInfo::Generator {
|
||||||
let field = generator_layout.variant_fields[*variant_index][i.into()];
|
generator_layout,
|
||||||
let decl = &generator_layout.__local_debuginfo_codegen_only_do_not_use[field];
|
generator_saved_local_names,
|
||||||
decl.name.map(|name| name.to_string())
|
variant_index,
|
||||||
}
|
..
|
||||||
|
} => generator_saved_local_names[
|
||||||
|
generator_layout.variant_fields[variant_index][i.into()]
|
||||||
|
],
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
field_name.unwrap_or_else(|| format!("__{}", i))
|
field_name.map(|name| name.to_string()).unwrap_or_else(|| format!("__{}", i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1657,7 +1717,7 @@ impl<'tcx> VariantInfo<'tcx> {
|
|||||||
fn describe_enum_variant(
|
fn describe_enum_variant(
|
||||||
cx: &CodegenCx<'ll, 'tcx>,
|
cx: &CodegenCx<'ll, 'tcx>,
|
||||||
layout: layout::TyLayout<'tcx>,
|
layout: layout::TyLayout<'tcx>,
|
||||||
variant: VariantInfo<'tcx>,
|
variant: VariantInfo<'_, 'tcx>,
|
||||||
discriminant_info: EnumDiscriminantInfo<'ll>,
|
discriminant_info: EnumDiscriminantInfo<'ll>,
|
||||||
containing_scope: &'ll DIScope,
|
containing_scope: &'ll DIScope,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
@ -5,7 +5,9 @@ use rustc_index::bit_set::BitSet;
|
|||||||
use rustc_data_structures::graph::dominators::Dominators;
|
use rustc_data_structures::graph::dominators::Dominators;
|
||||||
use rustc_index::vec::{Idx, IndexVec};
|
use rustc_index::vec::{Idx, IndexVec};
|
||||||
use rustc::mir::{self, Location, TerminatorKind};
|
use rustc::mir::{self, Location, TerminatorKind};
|
||||||
use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext};
|
use rustc::mir::visit::{
|
||||||
|
Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext, NonUseContext,
|
||||||
|
};
|
||||||
use rustc::mir::traversal;
|
use rustc::mir::traversal;
|
||||||
use rustc::session::config::DebugInfo;
|
use rustc::session::config::DebugInfo;
|
||||||
use rustc::ty;
|
use rustc::ty;
|
||||||
@ -27,7 +29,7 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||||||
// FIXME(eddyb): We should figure out how to use llvm.dbg.value instead
|
// FIXME(eddyb): We should figure out how to use llvm.dbg.value instead
|
||||||
// of putting everything in allocas just so we can use llvm.dbg.declare.
|
// of putting everything in allocas just so we can use llvm.dbg.declare.
|
||||||
if fx.cx.sess().opts.debuginfo == DebugInfo::Full {
|
if fx.cx.sess().opts.debuginfo == DebugInfo::Full {
|
||||||
if mir.local_kind(local) == mir::LocalKind::Arg || decl.name.is_some() {
|
if mir.local_kind(local) == mir::LocalKind::Arg {
|
||||||
analyzer.not_ssa(local);
|
analyzer.not_ssa(local);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -114,6 +116,12 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
|||||||
let cx = self.fx.cx;
|
let cx = self.fx.cx;
|
||||||
|
|
||||||
if let [proj_base @ .., elem] = place_ref.projection {
|
if let [proj_base @ .., elem] = place_ref.projection {
|
||||||
|
let mut base_context = if context.is_mutating_use() {
|
||||||
|
PlaceContext::MutatingUse(MutatingUseContext::Projection)
|
||||||
|
} else {
|
||||||
|
PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
|
||||||
|
};
|
||||||
|
|
||||||
// Allow uses of projections that are ZSTs or from scalar fields.
|
// Allow uses of projections that are ZSTs or from scalar fields.
|
||||||
let is_consume = match context {
|
let is_consume = match context {
|
||||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
|
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
|
||||||
@ -145,33 +153,66 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
|||||||
// Recurse with the same context, instead of `Projection`,
|
// Recurse with the same context, instead of `Projection`,
|
||||||
// potentially stopping at non-operand projections,
|
// potentially stopping at non-operand projections,
|
||||||
// which would trigger `not_ssa` on locals.
|
// which would trigger `not_ssa` on locals.
|
||||||
self.process_place(
|
base_context = context;
|
||||||
&mir::PlaceRef {
|
|
||||||
base: place_ref.base,
|
|
||||||
projection: proj_base,
|
|
||||||
},
|
|
||||||
context,
|
|
||||||
location,
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A deref projection only reads the pointer, never needs the place.
|
|
||||||
if let mir::ProjectionElem::Deref = elem {
|
if let mir::ProjectionElem::Deref = elem {
|
||||||
|
// Deref projections typically only read the pointer.
|
||||||
|
// (the exception being `VarDebugInfo` contexts, handled below)
|
||||||
|
base_context = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy);
|
||||||
|
|
||||||
|
// Indirect debuginfo requires going through memory, that only
|
||||||
|
// the debugger accesses, following our emitted DWARF pointer ops.
|
||||||
|
//
|
||||||
|
// FIXME(eddyb) Investigate the possibility of relaxing this, but
|
||||||
|
// note that `llvm.dbg.declare` *must* be used for indirect places,
|
||||||
|
// even if we start using `llvm.dbg.value` for all other cases,
|
||||||
|
// as we don't necessarily know when the value changes, but only
|
||||||
|
// where it lives in memory.
|
||||||
|
//
|
||||||
|
// It's possible `llvm.dbg.declare` could support starting from
|
||||||
|
// a pointer that doesn't point to an `alloca`, but this would
|
||||||
|
// only be useful if we know the pointer being `Deref`'d comes
|
||||||
|
// from an immutable place, and if `llvm.dbg.declare` calls
|
||||||
|
// must be at the very start of the function, then only function
|
||||||
|
// arguments could contain such pointers.
|
||||||
|
if context == PlaceContext::NonUse(NonUseContext::VarDebugInfo) {
|
||||||
|
// We use `NonUseContext::VarDebugInfo` for the base,
|
||||||
|
// which might not force the base local to memory,
|
||||||
|
// so we have to do it manually.
|
||||||
|
if let mir::PlaceBase::Local(local) = place_ref.base {
|
||||||
|
self.visit_local(&local, context, location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// `NonUseContext::VarDebugInfo` needs to flow all the
|
||||||
|
// way down to the base local (see `visit_local`).
|
||||||
|
if context == PlaceContext::NonUse(NonUseContext::VarDebugInfo) {
|
||||||
|
base_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
self.process_place(
|
self.process_place(
|
||||||
&mir::PlaceRef {
|
&mir::PlaceRef {
|
||||||
base: place_ref.base,
|
base: place_ref.base,
|
||||||
projection: proj_base,
|
projection: proj_base,
|
||||||
},
|
},
|
||||||
|
base_context,
|
||||||
|
location
|
||||||
|
);
|
||||||
|
// HACK(eddyb) this emulates the old `visit_projection_elem`, this
|
||||||
|
// entire `visit_place`-like `process_place` method should be rewritten,
|
||||||
|
// now that we have moved to the "slice of projections" representation.
|
||||||
|
if let mir::ProjectionElem::Index(local) = elem {
|
||||||
|
self.visit_local(
|
||||||
|
local,
|
||||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
|
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
|
||||||
location
|
location
|
||||||
);
|
);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
|
||||||
// FIXME this is super_place code, is repeated here to avoid cloning place or changing
|
// FIXME this is super_place code, is repeated here to avoid cloning place or changing
|
||||||
// visit_place API
|
// visit_place API
|
||||||
let mut context = context;
|
let mut context = context;
|
||||||
@ -187,6 +228,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
|||||||
self.visit_place_base(place_ref.base, context, location);
|
self.visit_place_base(place_ref.base, context, location);
|
||||||
self.visit_projection(place_ref.base, place_ref.projection, context, location);
|
self.visit_projection(place_ref.base, place_ref.projection, context, location);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,6 +306,15 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
|
|||||||
self.assign(local, location);
|
self.assign(local, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PlaceContext::NonUse(NonUseContext::VarDebugInfo) => {
|
||||||
|
// We need to keep locals in `alloca`s for debuginfo.
|
||||||
|
// FIXME(eddyb): We should figure out how to use `llvm.dbg.value` instead
|
||||||
|
// of putting everything in allocas just so we can use `llvm.dbg.declare`.
|
||||||
|
if self.fx.cx.sess().opts.debuginfo == DebugInfo::Full {
|
||||||
|
self.not_ssa(local);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PlaceContext::NonUse(_) |
|
PlaceContext::NonUse(_) |
|
||||||
PlaceContext::MutatingUse(MutatingUseContext::Retag) => {}
|
PlaceContext::MutatingUse(MutatingUseContext::Retag) => {}
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
use rustc_index::vec::{Idx, IndexVec};
|
use rustc_index::vec::IndexVec;
|
||||||
use rustc::hir::def_id::CrateNum;
|
use rustc::hir::def_id::CrateNum;
|
||||||
use rustc::mir;
|
use rustc::mir;
|
||||||
use rustc::session::config::DebugInfo;
|
use rustc::session::config::DebugInfo;
|
||||||
use rustc::ty::{self, TyCtxt};
|
use rustc::ty::TyCtxt;
|
||||||
use rustc::ty::layout::{LayoutOf, Size, VariantIdx};
|
use rustc::ty::layout::{LayoutOf, Size};
|
||||||
use crate::traits::*;
|
use crate::traits::*;
|
||||||
|
|
||||||
use syntax_pos::{BytePos, Span, Symbol};
|
use syntax_pos::{BytePos, Span};
|
||||||
use syntax::symbol::kw;
|
use syntax::symbol::kw;
|
||||||
|
|
||||||
use super::{FunctionCx, LocalRef};
|
use super::{FunctionCx, LocalRef};
|
||||||
@ -113,7 +113,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
Some(per_local) => &per_local[local],
|
Some(per_local) => &per_local[local],
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
let whole_local_var = vars.iter().find(|var| {
|
let whole_local_var = vars.iter().copied().find(|var| {
|
||||||
var.place.projection.is_empty()
|
var.place.projection.is_empty()
|
||||||
});
|
});
|
||||||
let has_proj = || vars.iter().any(|var| {
|
let has_proj = || vars.iter().any(|var| {
|
||||||
@ -131,7 +131,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
// be offset to account for the hidden environment?
|
// be offset to account for the hidden environment?
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(VarDebugInfo {
|
Some(mir::VarDebugInfo {
|
||||||
name: kw::Invalid,
|
name: kw::Invalid,
|
||||||
source_info: self.mir.local_decls[local].source_info,
|
source_info: self.mir.local_decls[local].source_info,
|
||||||
place: local.into(),
|
place: local.into(),
|
||||||
@ -185,7 +185,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let vars = vars.iter().chain(if whole_local_var.is_none() {
|
let vars = vars.iter().copied().chain(if whole_local_var.is_none() {
|
||||||
fallback_var.as_ref()
|
fallback_var.as_ref()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -253,133 +253,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Partition all `VarDebuginfo` in `body`, by their base `Local`.
|
||||||
pub fn per_local_var_debug_info(
|
pub fn per_local_var_debug_info(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
body: &mir::Body<'tcx>,
|
body: &'a mir::Body<'tcx>,
|
||||||
) -> Option<IndexVec<mir::Local, Vec<VarDebugInfo<'tcx>>>> {
|
) -> Option<IndexVec<mir::Local, Vec<&'a mir::VarDebugInfo<'tcx>>>> {
|
||||||
if tcx.sess.opts.debuginfo == DebugInfo::Full || !tcx.sess.fewer_names() {
|
if tcx.sess.opts.debuginfo == DebugInfo::Full || !tcx.sess.fewer_names() {
|
||||||
let mut per_local = IndexVec::from_elem(vec![], &body.local_decls);
|
let mut per_local = IndexVec::from_elem(vec![], &body.local_decls);
|
||||||
for (local, decl) in body.local_decls.iter_enumerated() {
|
for var in &body.var_debug_info {
|
||||||
if let Some(name) = decl.name {
|
if let mir::PlaceBase::Local(local) = var.place.base {
|
||||||
per_local[local].push(VarDebugInfo {
|
per_local[local].push(var);
|
||||||
name,
|
|
||||||
source_info: mir::SourceInfo {
|
|
||||||
span: decl.source_info.span,
|
|
||||||
scope: decl.visibility_scope,
|
|
||||||
},
|
|
||||||
place: local.into(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let upvar_debuginfo = &body.__upvar_debuginfo_codegen_only_do_not_use;
|
|
||||||
if !upvar_debuginfo.is_empty() {
|
|
||||||
|
|
||||||
let env_arg = mir::Local::new(1);
|
|
||||||
let mut env_projs = vec![];
|
|
||||||
|
|
||||||
let pin_did = tcx.lang_items().pin_type();
|
|
||||||
match body.local_decls[env_arg].ty.kind {
|
|
||||||
ty::RawPtr(_) |
|
|
||||||
ty::Ref(..) => {
|
|
||||||
env_projs.push(mir::ProjectionElem::Deref);
|
|
||||||
}
|
|
||||||
ty::Adt(def, substs) if Some(def.did) == pin_did => {
|
|
||||||
if let ty::Ref(..) = substs.type_at(0).kind {
|
|
||||||
env_projs.push(mir::ProjectionElem::Field(
|
|
||||||
mir::Field::new(0),
|
|
||||||
// HACK(eddyb) field types aren't used or needed here.
|
|
||||||
tcx.types.err,
|
|
||||||
));
|
|
||||||
env_projs.push(mir::ProjectionElem::Deref);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
let extra_locals = {
|
|
||||||
let upvars = upvar_debuginfo
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(i, upvar)| {
|
|
||||||
let source_info = mir::SourceInfo {
|
|
||||||
span: body.span,
|
|
||||||
scope: mir::OUTERMOST_SOURCE_SCOPE,
|
|
||||||
};
|
|
||||||
(None, i, upvar.debug_name, upvar.by_ref, source_info)
|
|
||||||
});
|
|
||||||
|
|
||||||
let generator_fields = body.generator_layout.as_ref().map(|generator_layout| {
|
|
||||||
generator_layout.variant_fields.iter()
|
|
||||||
.enumerate()
|
|
||||||
.flat_map(move |(variant_idx, fields)| {
|
|
||||||
let variant_idx = Some(VariantIdx::from(variant_idx));
|
|
||||||
fields.iter()
|
|
||||||
.enumerate()
|
|
||||||
.filter_map(move |(i, field)| {
|
|
||||||
let decl = &generator_layout.
|
|
||||||
__local_debuginfo_codegen_only_do_not_use[*field];
|
|
||||||
if let Some(name) = decl.name {
|
|
||||||
let source_info = mir::SourceInfo {
|
|
||||||
span: decl.source_info.span,
|
|
||||||
scope: decl.visibility_scope,
|
|
||||||
};
|
|
||||||
Some((variant_idx, i, name, false, source_info))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}).into_iter().flatten();
|
|
||||||
|
|
||||||
upvars.chain(generator_fields)
|
|
||||||
};
|
|
||||||
|
|
||||||
for (variant_idx, field, name, by_ref, source_info) in extra_locals {
|
|
||||||
let mut projs = env_projs.clone();
|
|
||||||
|
|
||||||
if let Some(variant_idx) = variant_idx {
|
|
||||||
projs.push(mir::ProjectionElem::Downcast(None, variant_idx));
|
|
||||||
}
|
|
||||||
|
|
||||||
projs.push(mir::ProjectionElem::Field(
|
|
||||||
mir::Field::new(field),
|
|
||||||
// HACK(eddyb) field types aren't used or needed here.
|
|
||||||
tcx.types.err,
|
|
||||||
));
|
|
||||||
|
|
||||||
if by_ref {
|
|
||||||
projs.push(mir::ProjectionElem::Deref);
|
|
||||||
}
|
|
||||||
|
|
||||||
per_local[env_arg].push(VarDebugInfo {
|
|
||||||
name,
|
|
||||||
source_info,
|
|
||||||
place: mir::Place {
|
|
||||||
base: mir::PlaceBase::Local(env_arg),
|
|
||||||
projection: tcx.intern_place_elems(&projs),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(per_local)
|
Some(per_local)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Debug information relatating to an user variable.
|
|
||||||
// FIXME(eddyb) move this to the MIR bodies themselves.
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct VarDebugInfo<'tcx> {
|
|
||||||
pub name: Symbol,
|
|
||||||
|
|
||||||
/// Source info of the user variable, including the scope
|
|
||||||
/// within which the variable is visible (to debuginfo)
|
|
||||||
/// (see `LocalDecl`'s `source_info` field for more details).
|
|
||||||
pub source_info: mir::SourceInfo,
|
|
||||||
|
|
||||||
/// Where the data for this user variable is to be found.
|
|
||||||
pub place: mir::Place<'tcx>,
|
|
||||||
}
|
|
||||||
|
@ -74,7 +74,9 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
|
|||||||
/// notably `expect`.
|
/// notably `expect`.
|
||||||
locals: IndexVec<mir::Local, LocalRef<'tcx, Bx::Value>>,
|
locals: IndexVec<mir::Local, LocalRef<'tcx, Bx::Value>>,
|
||||||
|
|
||||||
per_local_var_debug_info: Option<IndexVec<mir::Local, Vec<debuginfo::VarDebugInfo<'tcx>>>>,
|
/// All `VarDebuginfo` from the MIR body, partitioned by `Local`.
|
||||||
|
/// This is `None` if no variable debuginfo/names are needed.
|
||||||
|
per_local_var_debug_info: Option<IndexVec<mir::Local, Vec<&'a mir::VarDebugInfo<'tcx>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
|
@ -308,7 +308,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
location,
|
location,
|
||||||
borrow,
|
borrow,
|
||||||
None,
|
None,
|
||||||
).add_explanation_to_diagnostic(self.infcx.tcx, self.body, &mut err, "", Some(borrow_span));
|
).add_explanation_to_diagnostic(
|
||||||
|
self.infcx.tcx,
|
||||||
|
self.body,
|
||||||
|
&self.local_names,
|
||||||
|
&mut err,
|
||||||
|
"",
|
||||||
|
Some(borrow_span),
|
||||||
|
);
|
||||||
err.buffer(&mut self.errors_buffer);
|
err.buffer(&mut self.errors_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,7 +350,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
self.explain_why_borrow_contains_point(location, borrow, None)
|
self.explain_why_borrow_contains_point(location, borrow, None)
|
||||||
.add_explanation_to_diagnostic(self.infcx.tcx, self.body, &mut err, "", None);
|
.add_explanation_to_diagnostic(
|
||||||
|
self.infcx.tcx,
|
||||||
|
self.body,
|
||||||
|
&self.local_names,
|
||||||
|
&mut err,
|
||||||
|
"",
|
||||||
|
None,
|
||||||
|
);
|
||||||
err
|
err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -561,6 +575,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
explanation.add_explanation_to_diagnostic(
|
explanation.add_explanation_to_diagnostic(
|
||||||
self.infcx.tcx,
|
self.infcx.tcx,
|
||||||
self.body,
|
self.body,
|
||||||
|
&self.local_names,
|
||||||
&mut err,
|
&mut err,
|
||||||
first_borrow_desc,
|
first_borrow_desc,
|
||||||
None,
|
None,
|
||||||
@ -947,6 +962,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
explanation.add_explanation_to_diagnostic(
|
explanation.add_explanation_to_diagnostic(
|
||||||
self.infcx.tcx,
|
self.infcx.tcx,
|
||||||
self.body,
|
self.body,
|
||||||
|
&self.local_names,
|
||||||
&mut err,
|
&mut err,
|
||||||
"",
|
"",
|
||||||
None,
|
None,
|
||||||
@ -971,7 +987,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
explanation.add_explanation_to_diagnostic(
|
explanation.add_explanation_to_diagnostic(
|
||||||
self.infcx.tcx, self.body, &mut err, "", None);
|
self.infcx.tcx, self.body, &self.local_names, &mut err, "", None);
|
||||||
}
|
}
|
||||||
|
|
||||||
err
|
err
|
||||||
@ -1029,7 +1045,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
explanation.add_explanation_to_diagnostic(self.infcx.tcx, self.body, &mut err, "", None);
|
explanation.add_explanation_to_diagnostic(
|
||||||
|
self.infcx.tcx,
|
||||||
|
self.body,
|
||||||
|
&self.local_names,
|
||||||
|
&mut err,
|
||||||
|
"",
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
err.buffer(&mut self.errors_buffer);
|
err.buffer(&mut self.errors_buffer);
|
||||||
}
|
}
|
||||||
@ -1109,7 +1132,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
explanation.add_explanation_to_diagnostic(self.infcx.tcx, self.body, &mut err, "", None);
|
explanation.add_explanation_to_diagnostic(
|
||||||
|
self.infcx.tcx,
|
||||||
|
self.body,
|
||||||
|
&self.local_names,
|
||||||
|
&mut err,
|
||||||
|
"",
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
let within = if borrow_spans.for_generator() {
|
let within = if borrow_spans.for_generator() {
|
||||||
" by generator"
|
" by generator"
|
||||||
@ -1478,7 +1508,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
self.explain_why_borrow_contains_point(location, loan, None)
|
self.explain_why_borrow_contains_point(location, loan, None)
|
||||||
.add_explanation_to_diagnostic(self.infcx.tcx, self.body, &mut err, "", None);
|
.add_explanation_to_diagnostic(
|
||||||
|
self.infcx.tcx,
|
||||||
|
self.body,
|
||||||
|
&self.local_names,
|
||||||
|
&mut err,
|
||||||
|
"",
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
err.buffer(&mut self.errors_buffer);
|
err.buffer(&mut self.errors_buffer);
|
||||||
}
|
}
|
||||||
@ -1496,14 +1533,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
assigned_span: Span,
|
assigned_span: Span,
|
||||||
err_place: &Place<'tcx>,
|
err_place: &Place<'tcx>,
|
||||||
) {
|
) {
|
||||||
let (from_arg, local_decl) = if let Some(local) = err_place.as_local() {
|
let (from_arg, local_decl, local_name) = match err_place.as_local() {
|
||||||
if let LocalKind::Arg = self.body.local_kind(local) {
|
Some(local) => (
|
||||||
(true, Some(&self.body.local_decls[local]))
|
self.body.local_kind(local) == LocalKind::Arg,
|
||||||
} else {
|
Some(&self.body.local_decls[local]),
|
||||||
(false, Some(&self.body.local_decls[local]))
|
self.local_names[local],
|
||||||
}
|
),
|
||||||
} else {
|
None => (false, None, None),
|
||||||
(false, None)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// If root local is initialized immediately (everything apart from let
|
// If root local is initialized immediately (everything apart from let
|
||||||
@ -1553,7 +1589,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(decl) = local_decl {
|
if let Some(decl) = local_decl {
|
||||||
if let Some(name) = decl.name {
|
if let Some(name) = local_name {
|
||||||
if decl.can_be_made_mutable() {
|
if decl.can_be_made_mutable() {
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
decl.source_info.span,
|
decl.source_info.span,
|
||||||
|
@ -331,10 +331,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
|
|
||||||
/// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
|
/// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
|
||||||
/// a name, or its name was generated by the compiler, then `Err` is returned
|
/// a name, or its name was generated by the compiler, then `Err` is returned
|
||||||
fn append_local_to_string(&self, local_index: Local, buf: &mut String) -> Result<(), ()> {
|
fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> {
|
||||||
let local = &self.body.local_decls[local_index];
|
let decl = &self.body.local_decls[local];
|
||||||
match local.name {
|
match self.local_names[local] {
|
||||||
Some(name) if !local.from_compiler_desugaring() => {
|
Some(name) if !decl.from_compiler_desugaring() => {
|
||||||
buf.push_str(&name.as_str());
|
buf.push_str(&name.as_str());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -115,6 +115,20 @@ fn do_mir_borrowck<'a, 'tcx>(
|
|||||||
.as_local_hir_id(def_id)
|
.as_local_hir_id(def_id)
|
||||||
.expect("do_mir_borrowck: non-local DefId");
|
.expect("do_mir_borrowck: non-local DefId");
|
||||||
|
|
||||||
|
let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
|
||||||
|
for var_debug_info in &input_body.var_debug_info {
|
||||||
|
if let Some(local) = var_debug_info.place.as_local() {
|
||||||
|
if let Some(prev_name) = local_names[local] {
|
||||||
|
if var_debug_info.name != prev_name {
|
||||||
|
span_bug!(var_debug_info.source_info.span,
|
||||||
|
"local {:?} has many names (`{}` vs `{}`)",
|
||||||
|
local, prev_name, var_debug_info.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
local_names[local] = Some(var_debug_info.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Gather the upvars of a closure, if any.
|
// Gather the upvars of a closure, if any.
|
||||||
let tables = tcx.typeck_tables_of(def_id);
|
let tables = tcx.typeck_tables_of(def_id);
|
||||||
let upvars: Vec<_> = tables
|
let upvars: Vec<_> = tables
|
||||||
@ -189,6 +203,7 @@ fn do_mir_borrowck<'a, 'tcx>(
|
|||||||
free_regions,
|
free_regions,
|
||||||
body,
|
body,
|
||||||
&promoted,
|
&promoted,
|
||||||
|
&local_names,
|
||||||
&upvars,
|
&upvars,
|
||||||
location_table,
|
location_table,
|
||||||
param_env,
|
param_env,
|
||||||
@ -264,6 +279,7 @@ fn do_mir_borrowck<'a, 'tcx>(
|
|||||||
borrow_set,
|
borrow_set,
|
||||||
dominators,
|
dominators,
|
||||||
upvars,
|
upvars,
|
||||||
|
local_names,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut state = Flows::new(
|
let mut state = Flows::new(
|
||||||
@ -325,13 +341,8 @@ fn do_mir_borrowck<'a, 'tcx>(
|
|||||||
if let ClearCrossCrate::Set(ref vsi) = mbcx.body.source_scope_local_data {
|
if let ClearCrossCrate::Set(ref vsi) = mbcx.body.source_scope_local_data {
|
||||||
let local_decl = &mbcx.body.local_decls[local];
|
let local_decl = &mbcx.body.local_decls[local];
|
||||||
|
|
||||||
// Skip implicit `self` argument for closures
|
|
||||||
if local.index() == 1 && tcx.is_closure(mbcx.mir_def_id) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip over locals that begin with an underscore or have no name
|
// Skip over locals that begin with an underscore or have no name
|
||||||
match local_decl.name {
|
match mbcx.local_names[local] {
|
||||||
Some(name) => if name.as_str().starts_with("_") {
|
Some(name) => if name.as_str().starts_with("_") {
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
@ -463,6 +474,9 @@ crate struct MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
|
|
||||||
/// Information about upvars not necessarily preserved in types or MIR
|
/// Information about upvars not necessarily preserved in types or MIR
|
||||||
upvars: Vec<Upvar>,
|
upvars: Vec<Upvar>,
|
||||||
|
|
||||||
|
/// Names of local (user) variables (extracted from `var_debug_info`).
|
||||||
|
local_names: IndexVec<Local, Option<Name>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that:
|
// Check that:
|
||||||
|
@ -322,7 +322,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
if decl.is_ref_for_guard() {
|
if decl.is_ref_for_guard() {
|
||||||
let mut err = self.cannot_move_out_of(
|
let mut err = self.cannot_move_out_of(
|
||||||
span,
|
span,
|
||||||
&format!("`{}` in pattern guard", decl.name.unwrap()),
|
&format!("`{}` in pattern guard", self.local_names[*local].unwrap()),
|
||||||
);
|
);
|
||||||
err.note(
|
err.note(
|
||||||
"variables bound in patterns cannot be moved from \
|
"variables bound in patterns cannot be moved from \
|
||||||
@ -571,7 +571,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
if binds_to.len() == 1 {
|
if binds_to.len() == 1 {
|
||||||
self.note_type_does_not_implement_copy(
|
self.note_type_does_not_implement_copy(
|
||||||
err,
|
err,
|
||||||
&format!("`{}`", bind_to.name.unwrap()),
|
&format!("`{}`", self.local_names[*local].unwrap()),
|
||||||
bind_to.ty,
|
bind_to.ty,
|
||||||
Some(binding_span)
|
Some(binding_span)
|
||||||
);
|
);
|
||||||
|
@ -50,8 +50,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
if access_place.as_local().is_some() {
|
if access_place.as_local().is_some() {
|
||||||
reason = ", as it is not declared as mutable".to_string();
|
reason = ", as it is not declared as mutable".to_string();
|
||||||
} else {
|
} else {
|
||||||
let name = self.body.local_decls[*local]
|
let name = self.local_names[*local]
|
||||||
.name
|
|
||||||
.expect("immutable unnamed local");
|
.expect("immutable unnamed local");
|
||||||
reason = format!(", as `{}` is not declared as mutable", name);
|
reason = format!(", as `{}` is not declared as mutable", name);
|
||||||
}
|
}
|
||||||
@ -253,7 +252,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
// Deliberately fall into this case for all implicit self types,
|
// Deliberately fall into this case for all implicit self types,
|
||||||
// so that we don't fall in to the next case with them.
|
// so that we don't fall in to the next case with them.
|
||||||
kind == mir::ImplicitSelfKind::MutRef
|
kind == mir::ImplicitSelfKind::MutRef
|
||||||
} else if Some(kw::SelfLower) == local_decl.name {
|
} else if Some(kw::SelfLower) == self.local_names[*local] {
|
||||||
// Otherwise, check if the name is the self kewyord - in which case
|
// Otherwise, check if the name is the self kewyord - in which case
|
||||||
// we have an explicit self. Do the same thing in this case and check
|
// we have an explicit self. Do the same thing in this case and check
|
||||||
// for a `self: &mut Self` to suggest removing the `&mut`.
|
// for a `self: &mut Self` to suggest removing the `&mut`.
|
||||||
@ -290,7 +289,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
local_decl.source_info.span,
|
local_decl.source_info.span,
|
||||||
"consider changing this to be mutable",
|
"consider changing this to be mutable",
|
||||||
format!("mut {}", local_decl.name.unwrap()),
|
format!("mut {}", self.local_names[*local].unwrap()),
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -415,7 +414,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
match local_decl.name {
|
match self.local_names[*local] {
|
||||||
Some(name) if !local_decl.from_compiler_desugaring() => {
|
Some(name) if !local_decl.from_compiler_desugaring() => {
|
||||||
err.span_label(
|
err.span_label(
|
||||||
span,
|
span,
|
||||||
|
@ -11,9 +11,11 @@ use rustc::mir::{
|
|||||||
};
|
};
|
||||||
use rustc::ty::{self, TyCtxt};
|
use rustc::ty::{self, TyCtxt};
|
||||||
use rustc::ty::adjustment::{PointerCast};
|
use rustc::ty::adjustment::{PointerCast};
|
||||||
|
use rustc_index::vec::IndexVec;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_errors::DiagnosticBuilder;
|
use rustc_errors::DiagnosticBuilder;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
use syntax_pos::symbol::Symbol;
|
||||||
|
|
||||||
mod find_use;
|
mod find_use;
|
||||||
|
|
||||||
@ -56,6 +58,7 @@ impl BorrowExplanation {
|
|||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
|
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||||
err: &mut DiagnosticBuilder<'_>,
|
err: &mut DiagnosticBuilder<'_>,
|
||||||
borrow_desc: &str,
|
borrow_desc: &str,
|
||||||
borrow_span: Option<Span>,
|
borrow_span: Option<Span>,
|
||||||
@ -112,7 +115,7 @@ impl BorrowExplanation {
|
|||||||
_ => ("destructor", format!("type `{}`", local_decl.ty)),
|
_ => ("destructor", format!("type `{}`", local_decl.ty)),
|
||||||
};
|
};
|
||||||
|
|
||||||
match local_decl.name {
|
match local_names[dropped_local] {
|
||||||
Some(local_name) if !local_decl.from_compiler_desugaring() => {
|
Some(local_name) if !local_decl.from_compiler_desugaring() => {
|
||||||
let message = format!(
|
let message = format!(
|
||||||
"{B}borrow might be used here, when `{LOC}` is dropped \
|
"{B}borrow might be used here, when `{LOC}` is dropped \
|
||||||
@ -271,10 +274,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
|
|
||||||
Some(Cause::DropVar(local, location)) => {
|
Some(Cause::DropVar(local, location)) => {
|
||||||
let mut should_note_order = false;
|
let mut should_note_order = false;
|
||||||
if body.local_decls[local].name.is_some() {
|
if self.local_names[local].is_some() {
|
||||||
if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place {
|
if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place {
|
||||||
if let Some(borrowed_local) = place.as_local() {
|
if let Some(borrowed_local) = place.as_local() {
|
||||||
if body.local_decls[borrowed_local].name.is_some()
|
if self.local_names[borrowed_local].is_some()
|
||||||
&& local != borrowed_local
|
&& local != borrowed_local
|
||||||
{
|
{
|
||||||
should_note_order = true;
|
should_note_order = true;
|
||||||
@ -295,6 +298,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
let (category, from_closure, span, region_name) =
|
let (category, from_closure, span, region_name) =
|
||||||
self.nonlexical_regioncx.free_region_constraint_info(
|
self.nonlexical_regioncx.free_region_constraint_info(
|
||||||
self.body,
|
self.body,
|
||||||
|
&self.local_names,
|
||||||
&self.upvars,
|
&self.upvars,
|
||||||
self.mir_def_id,
|
self.mir_def_id,
|
||||||
self.infcx,
|
self.infcx,
|
||||||
@ -495,7 +499,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
Operand::Move(place) => {
|
Operand::Move(place) => {
|
||||||
if let Some(l) = place.as_local() {
|
if let Some(l) = place.as_local() {
|
||||||
let local_decl = &self.body.local_decls[l];
|
let local_decl = &self.body.local_decls[l];
|
||||||
if local_decl.name.is_none() {
|
if self.local_names[l].is_none() {
|
||||||
local_decl.source_info.span
|
local_decl.source_info.span
|
||||||
} else {
|
} else {
|
||||||
span
|
span
|
||||||
|
@ -16,6 +16,7 @@ use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements,
|
|||||||
use rustc::ty::{self, RegionKind, RegionVid};
|
use rustc::ty::{self, RegionKind, RegionVid};
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
use rustc_errors::Diagnostic;
|
use rustc_errors::Diagnostic;
|
||||||
|
use syntax_pos::symbol::Symbol;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::io;
|
use std::io;
|
||||||
@ -158,6 +159,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
|
|||||||
universal_regions: UniversalRegions<'tcx>,
|
universal_regions: UniversalRegions<'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
promoted: &IndexVec<Promoted, Body<'tcx>>,
|
promoted: &IndexVec<Promoted, Body<'tcx>>,
|
||||||
|
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||||
upvars: &[Upvar],
|
upvars: &[Upvar],
|
||||||
location_table: &LocationTable,
|
location_table: &LocationTable,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
@ -281,7 +283,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
|
|||||||
|
|
||||||
// Solve the region constraints.
|
// Solve the region constraints.
|
||||||
let closure_region_requirements =
|
let closure_region_requirements =
|
||||||
regioncx.solve(infcx, &body, upvars, def_id, errors_buffer);
|
regioncx.solve(infcx, body, local_names, upvars, def_id, errors_buffer);
|
||||||
|
|
||||||
// Dump MIR results into a file, if that is enabled. This let us
|
// Dump MIR results into a file, if that is enabled. This let us
|
||||||
// write unit-tests, as well as helping with debugging.
|
// write unit-tests, as well as helping with debugging.
|
||||||
|
@ -9,7 +9,7 @@ use rustc::hir::def_id::DefId;
|
|||||||
use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
|
use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
|
||||||
use rustc::infer::InferCtxt;
|
use rustc::infer::InferCtxt;
|
||||||
use rustc::infer::NLLRegionVariableOrigin;
|
use rustc::infer::NLLRegionVariableOrigin;
|
||||||
use rustc::mir::{ConstraintCategory, Location, Body};
|
use rustc::mir::{ConstraintCategory, Local, Location, Body};
|
||||||
use rustc::ty::{self, RegionVid};
|
use rustc::ty::{self, RegionVid};
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
use rustc_errors::DiagnosticBuilder;
|
use rustc_errors::DiagnosticBuilder;
|
||||||
@ -17,6 +17,7 @@ use std::collections::VecDeque;
|
|||||||
use syntax::errors::Applicability;
|
use syntax::errors::Applicability;
|
||||||
use syntax::symbol::kw;
|
use syntax::symbol::kw;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
use syntax_pos::symbol::Symbol;
|
||||||
|
|
||||||
use self::outlives_suggestion::OutlivesSuggestionBuilder;
|
use self::outlives_suggestion::OutlivesSuggestionBuilder;
|
||||||
|
|
||||||
@ -71,6 +72,9 @@ pub struct ErrorReportingCtx<'a, 'b, 'tcx> {
|
|||||||
/// The MIR body we are reporting errors on (for convenience).
|
/// The MIR body we are reporting errors on (for convenience).
|
||||||
body: &'b Body<'tcx>,
|
body: &'b Body<'tcx>,
|
||||||
|
|
||||||
|
/// User variable names for MIR locals (where applicable).
|
||||||
|
local_names: &'b IndexVec<Local, Option<Symbol>>,
|
||||||
|
|
||||||
/// Any upvars for the MIR body we have kept track of during borrow checking.
|
/// Any upvars for the MIR body we have kept track of during borrow checking.
|
||||||
upvars: &'b [Upvar],
|
upvars: &'b [Upvar],
|
||||||
}
|
}
|
||||||
@ -367,13 +371,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
pub(super) fn report_error<'a>(
|
pub(super) fn report_error<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
|
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||||
upvars: &[Upvar],
|
upvars: &[Upvar],
|
||||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||||
mir_def_id: DefId,
|
mir_def_id: DefId,
|
||||||
fr: RegionVid,
|
fr: RegionVid,
|
||||||
fr_origin: NLLRegionVariableOrigin,
|
fr_origin: NLLRegionVariableOrigin,
|
||||||
outlived_fr: RegionVid,
|
outlived_fr: RegionVid,
|
||||||
outlives_suggestion: &mut OutlivesSuggestionBuilder,
|
outlives_suggestion: &mut OutlivesSuggestionBuilder<'_>,
|
||||||
renctx: &mut RegionErrorNamingCtx,
|
renctx: &mut RegionErrorNamingCtx,
|
||||||
) -> DiagnosticBuilder<'a> {
|
) -> DiagnosticBuilder<'a> {
|
||||||
debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
|
debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
|
||||||
@ -407,6 +412,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
infcx,
|
infcx,
|
||||||
mir_def_id,
|
mir_def_id,
|
||||||
body,
|
body,
|
||||||
|
local_names,
|
||||||
upvars,
|
upvars,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -551,7 +557,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
renctx: &mut RegionErrorNamingCtx,
|
renctx: &mut RegionErrorNamingCtx,
|
||||||
) -> DiagnosticBuilder<'_> {
|
) -> DiagnosticBuilder<'_> {
|
||||||
let ErrorReportingCtx {
|
let ErrorReportingCtx {
|
||||||
infcx, body, upvars, ..
|
infcx, body, upvars, local_names, ..
|
||||||
} = errctx;
|
} = errctx;
|
||||||
|
|
||||||
let ErrorConstraintInfo {
|
let ErrorConstraintInfo {
|
||||||
@ -559,9 +565,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
} = errci;
|
} = errci;
|
||||||
|
|
||||||
let fr_name_and_span =
|
let fr_name_and_span =
|
||||||
self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, errci.fr);
|
self.get_var_name_and_span_for_region(infcx.tcx, body, local_names, upvars, errci.fr);
|
||||||
let outlived_fr_name_and_span =
|
let outlived_fr_name_and_span = self.get_var_name_and_span_for_region(
|
||||||
self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, errci.outlived_fr);
|
infcx.tcx,
|
||||||
|
body,
|
||||||
|
local_names,
|
||||||
|
upvars,
|
||||||
|
errci.outlived_fr,
|
||||||
|
);
|
||||||
|
|
||||||
let escapes_from = match self.universal_regions.defining_ty {
|
let escapes_from = match self.universal_regions.defining_ty {
|
||||||
DefiningTy::Closure(..) => "closure",
|
DefiningTy::Closure(..) => "closure",
|
||||||
@ -789,6 +800,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
crate fn free_region_constraint_info(
|
crate fn free_region_constraint_info(
|
||||||
&self,
|
&self,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
|
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||||
upvars: &[Upvar],
|
upvars: &[Upvar],
|
||||||
mir_def_id: DefId,
|
mir_def_id: DefId,
|
||||||
infcx: &InferCtxt<'_, 'tcx>,
|
infcx: &InferCtxt<'_, 'tcx>,
|
||||||
@ -804,7 +816,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
|
|
||||||
let mut renctx = RegionErrorNamingCtx::new();
|
let mut renctx = RegionErrorNamingCtx::new();
|
||||||
let errctx = ErrorReportingCtx {
|
let errctx = ErrorReportingCtx {
|
||||||
infcx, body, upvars, mir_def_id,
|
infcx, body, local_names, upvars, mir_def_id,
|
||||||
region_infcx: self,
|
region_infcx: self,
|
||||||
};
|
};
|
||||||
let outlived_fr_name = self.give_region_a_name(&errctx, &mut renctx, outlived_region);
|
let outlived_fr_name = self.give_region_a_name(&errctx, &mut renctx, outlived_region);
|
||||||
|
@ -4,9 +4,12 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use rustc::{hir::def_id::DefId, infer::InferCtxt, mir::Body, ty::RegionVid};
|
use rustc::{hir::def_id::DefId, infer::InferCtxt, ty::RegionVid};
|
||||||
|
use rustc::mir::{Body, Local};
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_errors::{Diagnostic, DiagnosticBuilder};
|
use rustc_errors::{Diagnostic, DiagnosticBuilder};
|
||||||
|
use rustc_index::vec::IndexVec;
|
||||||
|
use syntax_pos::symbol::Symbol;
|
||||||
|
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
@ -34,10 +37,12 @@ enum SuggestedConstraint {
|
|||||||
/// corresponding to a function definition.
|
/// corresponding to a function definition.
|
||||||
///
|
///
|
||||||
/// Adds a help note suggesting adding a where clause with the needed constraints.
|
/// Adds a help note suggesting adding a where clause with the needed constraints.
|
||||||
pub struct OutlivesSuggestionBuilder {
|
pub struct OutlivesSuggestionBuilder<'a> {
|
||||||
/// The MIR DefId of the fn with the lifetime error.
|
/// The MIR DefId of the fn with the lifetime error.
|
||||||
mir_def_id: DefId,
|
mir_def_id: DefId,
|
||||||
|
|
||||||
|
local_names: &'a IndexVec<Local, Option<Symbol>>,
|
||||||
|
|
||||||
/// The list of outlives constraints that need to be added. Specifically, we map each free
|
/// The list of outlives constraints that need to be added. Specifically, we map each free
|
||||||
/// region to all other regions that it must outlive. I will use the shorthand `fr:
|
/// region to all other regions that it must outlive. I will use the shorthand `fr:
|
||||||
/// outlived_frs`. Not all of these regions will already have names necessarily. Some could be
|
/// outlived_frs`. Not all of these regions will already have names necessarily. Some could be
|
||||||
@ -46,10 +51,17 @@ pub struct OutlivesSuggestionBuilder {
|
|||||||
constraints_to_add: BTreeMap<RegionVid, Vec<RegionVid>>,
|
constraints_to_add: BTreeMap<RegionVid, Vec<RegionVid>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OutlivesSuggestionBuilder {
|
impl OutlivesSuggestionBuilder<'a> {
|
||||||
/// Create a new builder for the given MIR node representing a fn definition.
|
/// Create a new builder for the given MIR node representing a fn definition.
|
||||||
crate fn new(mir_def_id: DefId) -> Self {
|
crate fn new(
|
||||||
OutlivesSuggestionBuilder { mir_def_id, constraints_to_add: BTreeMap::default() }
|
mir_def_id: DefId,
|
||||||
|
local_names: &'a IndexVec<Local, Option<Symbol>>,
|
||||||
|
) -> Self {
|
||||||
|
OutlivesSuggestionBuilder {
|
||||||
|
mir_def_id,
|
||||||
|
local_names,
|
||||||
|
constraints_to_add: BTreeMap::default(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` iff the `RegionNameSource` is a valid source for an outlives
|
/// Returns `true` iff the `RegionNameSource` is a valid source for an outlives
|
||||||
@ -125,6 +137,7 @@ impl OutlivesSuggestionBuilder {
|
|||||||
infcx,
|
infcx,
|
||||||
body,
|
body,
|
||||||
mir_def_id: self.mir_def_id,
|
mir_def_id: self.mir_def_id,
|
||||||
|
local_names: self.local_names,
|
||||||
|
|
||||||
// We should not be suggesting naming upvars, so we pass in a dummy set of upvars that
|
// We should not be suggesting naming upvars, so we pass in a dummy set of upvars that
|
||||||
// should never be used.
|
// should never be used.
|
||||||
|
@ -11,10 +11,11 @@ use rustc::hir;
|
|||||||
use rustc::hir::def::{Res, DefKind};
|
use rustc::hir::def::{Res, DefKind};
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::infer::InferCtxt;
|
use rustc::infer::InferCtxt;
|
||||||
use rustc::mir::Body;
|
use rustc::mir::{Local, Body};
|
||||||
use rustc::ty::subst::{SubstsRef, GenericArgKind};
|
use rustc::ty::subst::{SubstsRef, GenericArgKind};
|
||||||
use rustc::ty::{self, RegionKind, RegionVid, Ty, TyCtxt};
|
use rustc::ty::{self, RegionKind, RegionVid, Ty, TyCtxt};
|
||||||
use rustc::ty::print::RegionHighlightMode;
|
use rustc::ty::print::RegionHighlightMode;
|
||||||
|
use rustc_index::vec::IndexVec;
|
||||||
use rustc_errors::DiagnosticBuilder;
|
use rustc_errors::DiagnosticBuilder;
|
||||||
use syntax::symbol::kw;
|
use syntax::symbol::kw;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
@ -210,7 +211,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
fr: RegionVid,
|
fr: RegionVid,
|
||||||
) -> Option<RegionName> {
|
) -> Option<RegionName> {
|
||||||
let ErrorReportingCtx {
|
let ErrorReportingCtx {
|
||||||
infcx, body, mir_def_id, upvars, ..
|
infcx, body, mir_def_id, local_names, upvars, ..
|
||||||
} = errctx;
|
} = errctx;
|
||||||
|
|
||||||
debug!("give_region_a_name(fr={:?}, counter={:?})", fr, renctx.counter);
|
debug!("give_region_a_name(fr={:?}, counter={:?})", fr, renctx.counter);
|
||||||
@ -225,7 +226,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
.give_name_from_error_region(infcx.tcx, *mir_def_id, fr, renctx)
|
.give_name_from_error_region(infcx.tcx, *mir_def_id, fr, renctx)
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
self.give_name_if_anonymous_region_appears_in_arguments(
|
self.give_name_if_anonymous_region_appears_in_arguments(
|
||||||
infcx, body, *mir_def_id, fr, renctx,
|
infcx, body, local_names, *mir_def_id, fr, renctx,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
@ -395,6 +396,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
&self,
|
&self,
|
||||||
infcx: &InferCtxt<'_, 'tcx>,
|
infcx: &InferCtxt<'_, 'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
|
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||||
mir_def_id: DefId,
|
mir_def_id: DefId,
|
||||||
fr: RegionVid,
|
fr: RegionVid,
|
||||||
renctx: &mut RegionErrorNamingCtx,
|
renctx: &mut RegionErrorNamingCtx,
|
||||||
@ -415,7 +417,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
return Some(region_name);
|
return Some(region_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.give_name_if_we_cannot_match_hir_ty(infcx, body, fr, arg_ty, renctx)
|
self.give_name_if_we_cannot_match_hir_ty(infcx, body, local_names, fr, arg_ty, renctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn give_name_if_we_can_match_hir_ty_from_argument(
|
fn give_name_if_we_can_match_hir_ty_from_argument(
|
||||||
@ -463,6 +465,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
&self,
|
&self,
|
||||||
infcx: &InferCtxt<'_, 'tcx>,
|
infcx: &InferCtxt<'_, 'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
|
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||||
needle_fr: RegionVid,
|
needle_fr: RegionVid,
|
||||||
argument_ty: Ty<'tcx>,
|
argument_ty: Ty<'tcx>,
|
||||||
renctx: &mut RegionErrorNamingCtx,
|
renctx: &mut RegionErrorNamingCtx,
|
||||||
@ -479,7 +482,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
let assigned_region_name = if type_name.find(&format!("'{}", counter)).is_some() {
|
let assigned_region_name = if type_name.find(&format!("'{}", counter)).is_some() {
|
||||||
// Only add a label if we can confirm that a region was labelled.
|
// Only add a label if we can confirm that a region was labelled.
|
||||||
let argument_index = self.get_argument_index_for_region(infcx.tcx, needle_fr)?;
|
let argument_index = self.get_argument_index_for_region(infcx.tcx, needle_fr)?;
|
||||||
let (_, span) = self.get_argument_name_and_span_for_region(body, argument_index);
|
let (_, span) =
|
||||||
|
self.get_argument_name_and_span_for_region(body, local_names, argument_index);
|
||||||
|
|
||||||
Some(RegionName {
|
Some(RegionName {
|
||||||
// This counter value will already have been used, so this function will increment
|
// This counter value will already have been used, so this function will increment
|
||||||
|
@ -3,7 +3,7 @@ use crate::borrow_check::nll::ToRegionVid;
|
|||||||
use crate::borrow_check::Upvar;
|
use crate::borrow_check::Upvar;
|
||||||
use rustc::mir::{Local, Body};
|
use rustc::mir::{Local, Body};
|
||||||
use rustc::ty::{RegionVid, TyCtxt};
|
use rustc::ty::{RegionVid, TyCtxt};
|
||||||
use rustc_index::vec::Idx;
|
use rustc_index::vec::{Idx, IndexVec};
|
||||||
use syntax::source_map::Span;
|
use syntax::source_map::Span;
|
||||||
use syntax_pos::symbol::Symbol;
|
use syntax_pos::symbol::Symbol;
|
||||||
|
|
||||||
@ -12,6 +12,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
|
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||||
upvars: &[Upvar],
|
upvars: &[Upvar],
|
||||||
fr: RegionVid,
|
fr: RegionVid,
|
||||||
) -> Option<(Option<Symbol>, Span)> {
|
) -> Option<(Option<Symbol>, Span)> {
|
||||||
@ -27,8 +28,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
})
|
})
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
debug!("get_var_name_and_span_for_region: attempting argument");
|
debug!("get_var_name_and_span_for_region: attempting argument");
|
||||||
self.get_argument_index_for_region(tcx, fr)
|
self.get_argument_index_for_region(tcx, fr).map(|index| {
|
||||||
.map(|index| self.get_argument_name_and_span_for_region(body, index))
|
self.get_argument_name_and_span_for_region(body, local_names, index)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,13 +119,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
crate fn get_argument_name_and_span_for_region(
|
crate fn get_argument_name_and_span_for_region(
|
||||||
&self,
|
&self,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
|
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||||
argument_index: usize,
|
argument_index: usize,
|
||||||
) -> (Option<Symbol>, Span) {
|
) -> (Option<Symbol>, Span) {
|
||||||
let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
|
let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
|
||||||
let argument_local = Local::new(implicit_inputs + argument_index + 1);
|
let argument_local = Local::new(implicit_inputs + argument_index + 1);
|
||||||
debug!("get_argument_name_and_span_for_region: argument_local={:?}", argument_local);
|
debug!("get_argument_name_and_span_for_region: argument_local={:?}", argument_local);
|
||||||
|
|
||||||
let argument_name = body.local_decls[argument_local].name;
|
let argument_name = local_names[argument_local];
|
||||||
let argument_span = body.local_decls[argument_local].source_info.span;
|
let argument_span = body.local_decls[argument_local].source_info.span;
|
||||||
debug!("get_argument_name_and_span_for_region: argument_name={:?} argument_span={:?}",
|
debug!("get_argument_name_and_span_for_region: argument_name={:?} argument_span={:?}",
|
||||||
argument_name, argument_span);
|
argument_name, argument_span);
|
||||||
|
@ -36,6 +36,7 @@ use rustc_data_structures::graph::vec_graph::VecGraph;
|
|||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
use rustc_errors::{Diagnostic, DiagnosticBuilder};
|
use rustc_errors::{Diagnostic, DiagnosticBuilder};
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
use syntax_pos::symbol::Symbol;
|
||||||
|
|
||||||
crate use self::error_reporting::{RegionName, RegionNameSource, RegionErrorNamingCtx};
|
crate use self::error_reporting::{RegionName, RegionNameSource, RegionErrorNamingCtx};
|
||||||
use self::values::{LivenessValues, RegionValueElements, RegionValues};
|
use self::values::{LivenessValues, RegionValueElements, RegionValues};
|
||||||
@ -471,6 +472,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
infcx: &InferCtxt<'_, 'tcx>,
|
infcx: &InferCtxt<'_, 'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
|
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||||
upvars: &[Upvar],
|
upvars: &[Upvar],
|
||||||
mir_def_id: DefId,
|
mir_def_id: DefId,
|
||||||
errors_buffer: &mut Vec<Diagnostic>,
|
errors_buffer: &mut Vec<Diagnostic>,
|
||||||
@ -502,6 +504,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
self.check_universal_regions(
|
self.check_universal_regions(
|
||||||
infcx,
|
infcx,
|
||||||
body,
|
body,
|
||||||
|
local_names,
|
||||||
upvars,
|
upvars,
|
||||||
mir_def_id,
|
mir_def_id,
|
||||||
outlives_requirements.as_mut(),
|
outlives_requirements.as_mut(),
|
||||||
@ -1321,13 +1324,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
&self,
|
&self,
|
||||||
infcx: &InferCtxt<'_, 'tcx>,
|
infcx: &InferCtxt<'_, 'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
|
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||||
upvars: &[Upvar],
|
upvars: &[Upvar],
|
||||||
mir_def_id: DefId,
|
mir_def_id: DefId,
|
||||||
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
|
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
|
||||||
errors_buffer: &mut Vec<Diagnostic>,
|
errors_buffer: &mut Vec<Diagnostic>,
|
||||||
region_naming: &mut RegionErrorNamingCtx,
|
region_naming: &mut RegionErrorNamingCtx,
|
||||||
) {
|
) {
|
||||||
let mut outlives_suggestion = OutlivesSuggestionBuilder::new(mir_def_id);
|
let mut outlives_suggestion = OutlivesSuggestionBuilder::new(mir_def_id, local_names);
|
||||||
|
|
||||||
for (fr, fr_definition) in self.definitions.iter_enumerated() {
|
for (fr, fr_definition) in self.definitions.iter_enumerated() {
|
||||||
match fr_definition.origin {
|
match fr_definition.origin {
|
||||||
@ -1338,6 +1342,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
self.check_universal_region(
|
self.check_universal_region(
|
||||||
infcx,
|
infcx,
|
||||||
body,
|
body,
|
||||||
|
local_names,
|
||||||
upvars,
|
upvars,
|
||||||
mir_def_id,
|
mir_def_id,
|
||||||
fr,
|
fr,
|
||||||
@ -1374,11 +1379,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
&self,
|
&self,
|
||||||
infcx: &InferCtxt<'_, 'tcx>,
|
infcx: &InferCtxt<'_, 'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
|
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||||
upvars: &[Upvar],
|
upvars: &[Upvar],
|
||||||
mir_def_id: DefId,
|
mir_def_id: DefId,
|
||||||
longer_fr: RegionVid,
|
longer_fr: RegionVid,
|
||||||
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
|
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
|
||||||
outlives_suggestion: &mut OutlivesSuggestionBuilder,
|
outlives_suggestion: &mut OutlivesSuggestionBuilder<'_>,
|
||||||
errors_buffer: &mut Vec<Diagnostic>,
|
errors_buffer: &mut Vec<Diagnostic>,
|
||||||
region_naming: &mut RegionErrorNamingCtx,
|
region_naming: &mut RegionErrorNamingCtx,
|
||||||
) {
|
) {
|
||||||
@ -1404,6 +1410,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
representative,
|
representative,
|
||||||
infcx,
|
infcx,
|
||||||
body,
|
body,
|
||||||
|
local_names,
|
||||||
upvars,
|
upvars,
|
||||||
mir_def_id,
|
mir_def_id,
|
||||||
propagated_outlives_requirements,
|
propagated_outlives_requirements,
|
||||||
@ -1422,6 +1429,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
shorter_fr,
|
shorter_fr,
|
||||||
infcx,
|
infcx,
|
||||||
body,
|
body,
|
||||||
|
local_names,
|
||||||
upvars,
|
upvars,
|
||||||
mir_def_id,
|
mir_def_id,
|
||||||
propagated_outlives_requirements,
|
propagated_outlives_requirements,
|
||||||
@ -1445,10 +1453,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
shorter_fr: RegionVid,
|
shorter_fr: RegionVid,
|
||||||
infcx: &InferCtxt<'_, 'tcx>,
|
infcx: &InferCtxt<'_, 'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
|
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||||
upvars: &[Upvar],
|
upvars: &[Upvar],
|
||||||
mir_def_id: DefId,
|
mir_def_id: DefId,
|
||||||
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
|
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
|
||||||
outlives_suggestion: &mut OutlivesSuggestionBuilder,
|
outlives_suggestion: &mut OutlivesSuggestionBuilder<'_>,
|
||||||
errors_buffer: &mut Vec<Diagnostic>,
|
errors_buffer: &mut Vec<Diagnostic>,
|
||||||
region_naming: &mut RegionErrorNamingCtx,
|
region_naming: &mut RegionErrorNamingCtx,
|
||||||
) -> Option<ErrorReported> {
|
) -> Option<ErrorReported> {
|
||||||
@ -1502,6 +1511,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
// error. This gives better error messages in some cases.
|
// error. This gives better error messages in some cases.
|
||||||
let db = self.report_error(
|
let db = self.report_error(
|
||||||
body,
|
body,
|
||||||
|
local_names,
|
||||||
upvars,
|
upvars,
|
||||||
infcx,
|
infcx,
|
||||||
mir_def_id,
|
mir_def_id,
|
||||||
|
@ -227,9 +227,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
mutability: Mutability::Mut,
|
mutability: Mutability::Mut,
|
||||||
ty: ptr_ty,
|
ty: ptr_ty,
|
||||||
user_ty: UserTypeProjections::none(),
|
user_ty: UserTypeProjections::none(),
|
||||||
name: None,
|
|
||||||
source_info,
|
source_info,
|
||||||
visibility_scope: source_info.scope,
|
|
||||||
internal: true,
|
internal: true,
|
||||||
local_info: LocalInfo::Other,
|
local_info: LocalInfo::Other,
|
||||||
is_block_tail: None,
|
is_block_tail: None,
|
||||||
|
@ -1721,6 +1721,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let tcx = self.hir.tcx();
|
let tcx = self.hir.tcx();
|
||||||
|
let debug_source_info = SourceInfo {
|
||||||
|
span: source_info.span,
|
||||||
|
scope: visibility_scope,
|
||||||
|
};
|
||||||
let binding_mode = match mode {
|
let binding_mode = match mode {
|
||||||
BindingMode::ByValue => ty::BindingMode::BindByValue(mutability.into()),
|
BindingMode::ByValue => ty::BindingMode::BindByValue(mutability.into()),
|
||||||
BindingMode::ByRef(_) => ty::BindingMode::BindByReference(mutability.into()),
|
BindingMode::ByRef(_) => ty::BindingMode::BindByReference(mutability.into()),
|
||||||
@ -1730,9 +1734,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
mutability,
|
mutability,
|
||||||
ty: var_ty,
|
ty: var_ty,
|
||||||
user_ty,
|
user_ty,
|
||||||
name: Some(name),
|
|
||||||
source_info,
|
source_info,
|
||||||
visibility_scope,
|
|
||||||
internal: false,
|
internal: false,
|
||||||
is_block_tail: None,
|
is_block_tail: None,
|
||||||
local_info: LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
|
local_info: LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
|
||||||
@ -1749,6 +1751,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
))),
|
))),
|
||||||
};
|
};
|
||||||
let for_arm_body = self.local_decls.push(local);
|
let for_arm_body = self.local_decls.push(local);
|
||||||
|
self.var_debug_info.push(VarDebugInfo {
|
||||||
|
name,
|
||||||
|
source_info: debug_source_info,
|
||||||
|
place: for_arm_body.into(),
|
||||||
|
});
|
||||||
let locals = if has_guard.0 {
|
let locals = if has_guard.0 {
|
||||||
let ref_for_guard = self.local_decls.push(LocalDecl::<'tcx> {
|
let ref_for_guard = self.local_decls.push(LocalDecl::<'tcx> {
|
||||||
// This variable isn't mutated but has a name, so has to be
|
// This variable isn't mutated but has a name, so has to be
|
||||||
@ -1756,13 +1763,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
mutability: Mutability::Not,
|
mutability: Mutability::Not,
|
||||||
ty: tcx.mk_imm_ref(tcx.lifetimes.re_erased, var_ty),
|
ty: tcx.mk_imm_ref(tcx.lifetimes.re_erased, var_ty),
|
||||||
user_ty: UserTypeProjections::none(),
|
user_ty: UserTypeProjections::none(),
|
||||||
name: Some(name),
|
|
||||||
source_info,
|
source_info,
|
||||||
visibility_scope,
|
|
||||||
internal: false,
|
internal: false,
|
||||||
is_block_tail: None,
|
is_block_tail: None,
|
||||||
local_info: LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard)),
|
local_info: LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard)),
|
||||||
});
|
});
|
||||||
|
self.var_debug_info.push(VarDebugInfo {
|
||||||
|
name,
|
||||||
|
source_info: debug_source_info,
|
||||||
|
place: ref_for_guard.into(),
|
||||||
|
});
|
||||||
LocalsForNode::ForGuard {
|
LocalsForNode::ForGuard {
|
||||||
ref_for_guard,
|
ref_for_guard,
|
||||||
for_arm_body,
|
for_arm_body,
|
||||||
|
@ -161,8 +161,18 @@ pub fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> Body<'_> {
|
|||||||
(None, fn_sig.output())
|
(None, fn_sig.output())
|
||||||
};
|
};
|
||||||
|
|
||||||
build::construct_fn(cx, id, arguments, safety, abi,
|
let mut mir = build::construct_fn(
|
||||||
return_ty, yield_ty, return_ty_span, body)
|
cx,
|
||||||
|
id,
|
||||||
|
arguments,
|
||||||
|
safety,
|
||||||
|
abi,
|
||||||
|
return_ty,
|
||||||
|
return_ty_span,
|
||||||
|
body,
|
||||||
|
);
|
||||||
|
mir.yield_ty = yield_ty;
|
||||||
|
mir
|
||||||
} else {
|
} else {
|
||||||
// Get the revealed type of this const. This is *not* the adjusted
|
// Get the revealed type of this const. This is *not* the adjusted
|
||||||
// type of its body, which may be a subtype of this type. For
|
// type of its body, which may be a subtype of this type. For
|
||||||
@ -312,10 +322,11 @@ struct Builder<'a, 'tcx> {
|
|||||||
var_indices: HirIdMap<LocalsForNode>,
|
var_indices: HirIdMap<LocalsForNode>,
|
||||||
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
|
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
|
||||||
canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>,
|
canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>,
|
||||||
__upvar_debuginfo_codegen_only_do_not_use: Vec<UpvarDebuginfo>,
|
|
||||||
upvar_mutbls: Vec<Mutability>,
|
upvar_mutbls: Vec<Mutability>,
|
||||||
unit_temp: Option<Place<'tcx>>,
|
unit_temp: Option<Place<'tcx>>,
|
||||||
|
|
||||||
|
var_debug_info: Vec<VarDebugInfo<'tcx>>,
|
||||||
|
|
||||||
/// Cached block with the `RESUME` terminator; this is created
|
/// Cached block with the `RESUME` terminator; this is created
|
||||||
/// when first set of cleanups are built.
|
/// when first set of cleanups are built.
|
||||||
cached_resume_block: Option<BasicBlock>,
|
cached_resume_block: Option<BasicBlock>,
|
||||||
@ -539,7 +550,6 @@ fn construct_fn<'a, 'tcx, A>(
|
|||||||
safety: Safety,
|
safety: Safety,
|
||||||
abi: Abi,
|
abi: Abi,
|
||||||
return_ty: Ty<'tcx>,
|
return_ty: Ty<'tcx>,
|
||||||
yield_ty: Option<Ty<'tcx>>,
|
|
||||||
return_ty_span: Span,
|
return_ty_span: Span,
|
||||||
body: &'tcx hir::Body,
|
body: &'tcx hir::Body,
|
||||||
) -> Body<'tcx>
|
) -> Body<'tcx>
|
||||||
@ -552,58 +562,14 @@ where
|
|||||||
let tcx_hir = tcx.hir();
|
let tcx_hir = tcx.hir();
|
||||||
let span = tcx_hir.span(fn_id);
|
let span = tcx_hir.span(fn_id);
|
||||||
|
|
||||||
let hir_tables = hir.tables();
|
|
||||||
let fn_def_id = tcx_hir.local_def_id(fn_id);
|
let fn_def_id = tcx_hir.local_def_id(fn_id);
|
||||||
|
|
||||||
// Gather the upvars of a closure, if any.
|
|
||||||
let mut upvar_mutbls = vec![];
|
|
||||||
// In analyze_closure() in upvar.rs we gathered a list of upvars used by a
|
|
||||||
// closure and we stored in a map called upvar_list in TypeckTables indexed
|
|
||||||
// with the closure's DefId. Here, we run through that vec of UpvarIds for
|
|
||||||
// the given closure and use the necessary information to create UpvarDecl.
|
|
||||||
let upvar_debuginfo: Vec<_> = hir_tables
|
|
||||||
.upvar_list
|
|
||||||
.get(&fn_def_id)
|
|
||||||
.into_iter()
|
|
||||||
.flatten()
|
|
||||||
.map(|(&var_hir_id, &upvar_id)| {
|
|
||||||
let capture = hir_tables.upvar_capture(upvar_id);
|
|
||||||
let by_ref = match capture {
|
|
||||||
ty::UpvarCapture::ByValue => false,
|
|
||||||
ty::UpvarCapture::ByRef(..) => true,
|
|
||||||
};
|
|
||||||
let mut debuginfo = UpvarDebuginfo {
|
|
||||||
debug_name: kw::Invalid,
|
|
||||||
by_ref,
|
|
||||||
};
|
|
||||||
let mut mutability = Mutability::Not;
|
|
||||||
if let Some(Node::Binding(pat)) = tcx_hir.find(var_hir_id) {
|
|
||||||
if let hir::PatKind::Binding(_, _, ident, _) = pat.kind {
|
|
||||||
debuginfo.debug_name = ident.name;
|
|
||||||
if let Some(&bm) = hir.tables.pat_binding_modes().get(pat.hir_id) {
|
|
||||||
if bm == ty::BindByValue(hir::Mutability::Mutable) {
|
|
||||||
mutability = Mutability::Mut;
|
|
||||||
} else {
|
|
||||||
mutability = Mutability::Not;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tcx.sess.delay_span_bug(pat.span, "missing binding mode");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
upvar_mutbls.push(mutability);
|
|
||||||
debuginfo
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let mut builder = Builder::new(hir,
|
let mut builder = Builder::new(hir,
|
||||||
span,
|
span,
|
||||||
arguments.len(),
|
arguments.len(),
|
||||||
safety,
|
safety,
|
||||||
return_ty,
|
return_ty,
|
||||||
return_ty_span,
|
return_ty_span,
|
||||||
upvar_debuginfo,
|
|
||||||
upvar_mutbls,
|
|
||||||
body.generator_kind.is_some());
|
body.generator_kind.is_some());
|
||||||
|
|
||||||
let call_site_scope = region::Scope {
|
let call_site_scope = region::Scope {
|
||||||
@ -631,7 +597,7 @@ where
|
|||||||
Place::return_place(),
|
Place::return_place(),
|
||||||
|builder| {
|
|builder| {
|
||||||
builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
|
builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
|
||||||
builder.args_and_body(block, &arguments, arg_scope, &body.value)
|
builder.args_and_body(block, fn_def_id, &arguments, arg_scope, &body.value)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
@ -660,7 +626,7 @@ where
|
|||||||
info!("fn_id {:?} has attrs {:?}", fn_def_id,
|
info!("fn_id {:?} has attrs {:?}", fn_def_id,
|
||||||
tcx.get_attrs(fn_def_id));
|
tcx.get_attrs(fn_def_id));
|
||||||
|
|
||||||
let mut body = builder.finish(yield_ty);
|
let mut body = builder.finish();
|
||||||
body.spread_arg = spread_arg;
|
body.spread_arg = spread_arg;
|
||||||
body
|
body
|
||||||
}
|
}
|
||||||
@ -681,8 +647,6 @@ fn construct_const<'a, 'tcx>(
|
|||||||
Safety::Safe,
|
Safety::Safe,
|
||||||
const_ty,
|
const_ty,
|
||||||
const_ty_span,
|
const_ty_span,
|
||||||
vec![],
|
|
||||||
vec![],
|
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -704,7 +668,7 @@ fn construct_const<'a, 'tcx>(
|
|||||||
TerminatorKind::Unreachable);
|
TerminatorKind::Unreachable);
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.finish(None)
|
builder.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn construct_error<'a, 'tcx>(
|
fn construct_error<'a, 'tcx>(
|
||||||
@ -714,10 +678,10 @@ fn construct_error<'a, 'tcx>(
|
|||||||
let owner_id = hir.tcx().hir().body_owner(body_id);
|
let owner_id = hir.tcx().hir().body_owner(body_id);
|
||||||
let span = hir.tcx().hir().span(owner_id);
|
let span = hir.tcx().hir().span(owner_id);
|
||||||
let ty = hir.tcx().types.err;
|
let ty = hir.tcx().types.err;
|
||||||
let mut builder = Builder::new(hir, span, 0, Safety::Safe, ty, span, vec![], vec![], false);
|
let mut builder = Builder::new(hir, span, 0, Safety::Safe, ty, span, false);
|
||||||
let source_info = builder.source_info(span);
|
let source_info = builder.source_info(span);
|
||||||
builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
|
builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
|
||||||
builder.finish(None)
|
builder.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
@ -727,8 +691,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
safety: Safety,
|
safety: Safety,
|
||||||
return_ty: Ty<'tcx>,
|
return_ty: Ty<'tcx>,
|
||||||
return_span: Span,
|
return_span: Span,
|
||||||
__upvar_debuginfo_codegen_only_do_not_use: Vec<UpvarDebuginfo>,
|
|
||||||
upvar_mutbls: Vec<Mutability>,
|
|
||||||
is_generator: bool)
|
is_generator: bool)
|
||||||
-> Builder<'a, 'tcx> {
|
-> Builder<'a, 'tcx> {
|
||||||
let lint_level = LintLevel::Explicit(hir.root_lint_level);
|
let lint_level = LintLevel::Explicit(hir.root_lint_level);
|
||||||
@ -751,10 +713,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
1,
|
1,
|
||||||
),
|
),
|
||||||
canonical_user_type_annotations: IndexVec::new(),
|
canonical_user_type_annotations: IndexVec::new(),
|
||||||
__upvar_debuginfo_codegen_only_do_not_use,
|
upvar_mutbls: vec![],
|
||||||
upvar_mutbls,
|
|
||||||
var_indices: Default::default(),
|
var_indices: Default::default(),
|
||||||
unit_temp: None,
|
unit_temp: None,
|
||||||
|
var_debug_info: vec![],
|
||||||
cached_resume_block: None,
|
cached_resume_block: None,
|
||||||
cached_return_block: None,
|
cached_return_block: None,
|
||||||
cached_unreachable_block: None,
|
cached_unreachable_block: None,
|
||||||
@ -769,9 +731,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
builder
|
builder
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(self,
|
fn finish(self) -> Body<'tcx> {
|
||||||
yield_ty: Option<Ty<'tcx>>)
|
|
||||||
-> Body<'tcx> {
|
|
||||||
for (index, block) in self.cfg.basic_blocks.iter().enumerate() {
|
for (index, block) in self.cfg.basic_blocks.iter().enumerate() {
|
||||||
if block.terminator.is_none() {
|
if block.terminator.is_none() {
|
||||||
span_bug!(self.fn_span, "no terminator on block {:?}", index);
|
span_bug!(self.fn_span, "no terminator on block {:?}", index);
|
||||||
@ -782,11 +742,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
self.cfg.basic_blocks,
|
self.cfg.basic_blocks,
|
||||||
self.source_scopes,
|
self.source_scopes,
|
||||||
ClearCrossCrate::Set(self.source_scope_local_data),
|
ClearCrossCrate::Set(self.source_scope_local_data),
|
||||||
yield_ty,
|
|
||||||
self.local_decls,
|
self.local_decls,
|
||||||
self.canonical_user_type_annotations,
|
self.canonical_user_type_annotations,
|
||||||
self.arg_count,
|
self.arg_count,
|
||||||
self.__upvar_debuginfo_codegen_only_do_not_use,
|
self.var_debug_info,
|
||||||
self.fn_span,
|
self.fn_span,
|
||||||
self.hir.control_flow_destroyed(),
|
self.hir.control_flow_destroyed(),
|
||||||
)
|
)
|
||||||
@ -794,6 +753,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
|
|
||||||
fn args_and_body(&mut self,
|
fn args_and_body(&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
|
fn_def_id: DefId,
|
||||||
arguments: &[ArgInfo<'tcx>],
|
arguments: &[ArgInfo<'tcx>],
|
||||||
argument_scope: region::Scope,
|
argument_scope: region::Scope,
|
||||||
ast_body: &'tcx hir::Expr)
|
ast_body: &'tcx hir::Expr)
|
||||||
@ -801,28 +761,100 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
{
|
{
|
||||||
// Allocate locals for the function arguments
|
// Allocate locals for the function arguments
|
||||||
for &ArgInfo(ty, _, arg_opt, _) in arguments.iter() {
|
for &ArgInfo(ty, _, arg_opt, _) in arguments.iter() {
|
||||||
// If this is a simple binding pattern, give the local a name for
|
let source_info = SourceInfo {
|
||||||
// debuginfo and so that error reporting knows that this is a user
|
scope: OUTERMOST_SOURCE_SCOPE,
|
||||||
// variable. For any other pattern the pattern introduces new
|
span: arg_opt.map_or(self.fn_span, |arg| arg.pat.span)
|
||||||
// variables which will be named instead.
|
|
||||||
let (name, span) = if let Some(arg) = arg_opt {
|
|
||||||
(arg.pat.simple_ident().map(|ident| ident.name), arg.pat.span)
|
|
||||||
} else {
|
|
||||||
(None, self.fn_span)
|
|
||||||
};
|
};
|
||||||
|
let arg_local = self.local_decls.push(LocalDecl {
|
||||||
let source_info = SourceInfo { scope: OUTERMOST_SOURCE_SCOPE, span, };
|
|
||||||
self.local_decls.push(LocalDecl {
|
|
||||||
mutability: Mutability::Mut,
|
mutability: Mutability::Mut,
|
||||||
ty,
|
ty,
|
||||||
user_ty: UserTypeProjections::none(),
|
user_ty: UserTypeProjections::none(),
|
||||||
source_info,
|
source_info,
|
||||||
visibility_scope: source_info.scope,
|
|
||||||
name,
|
|
||||||
internal: false,
|
internal: false,
|
||||||
local_info: LocalInfo::Other,
|
local_info: LocalInfo::Other,
|
||||||
is_block_tail: None,
|
is_block_tail: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// If this is a simple binding pattern, give debuginfo a nice name.
|
||||||
|
if let Some(arg) = arg_opt {
|
||||||
|
if let Some(ident) = arg.pat.simple_ident() {
|
||||||
|
self.var_debug_info.push(VarDebugInfo {
|
||||||
|
name: ident.name,
|
||||||
|
source_info,
|
||||||
|
place: arg_local.into(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let tcx = self.hir.tcx();
|
||||||
|
let tcx_hir = tcx.hir();
|
||||||
|
let hir_tables = self.hir.tables();
|
||||||
|
|
||||||
|
// In analyze_closure() in upvar.rs we gathered a list of upvars used by a
|
||||||
|
// closure and we stored in a map called upvar_list in TypeckTables indexed
|
||||||
|
// with the closure's DefId. Here, we run through that vec of UpvarIds for
|
||||||
|
// the given closure and use the necessary information to create upvar
|
||||||
|
// debuginfo and to fill `self.upvar_mutbls`.
|
||||||
|
if let Some(upvars) = hir_tables.upvar_list.get(&fn_def_id) {
|
||||||
|
let closure_env_arg = Local::new(1);
|
||||||
|
let mut closure_env_projs = vec![];
|
||||||
|
let mut closure_ty = self.local_decls[closure_env_arg].ty;
|
||||||
|
if let ty::Ref(_, ty, _) = closure_ty.kind {
|
||||||
|
closure_env_projs.push(ProjectionElem::Deref);
|
||||||
|
closure_ty = ty;
|
||||||
|
}
|
||||||
|
let (def_id, upvar_substs) = match closure_ty.kind {
|
||||||
|
ty::Closure(def_id, substs) => (def_id, ty::UpvarSubsts::Closure(substs)),
|
||||||
|
ty::Generator(def_id, substs, _) => (def_id, ty::UpvarSubsts::Generator(substs)),
|
||||||
|
_ => span_bug!(self.fn_span, "upvars with non-closure env ty {:?}", closure_ty)
|
||||||
|
};
|
||||||
|
let upvar_tys = upvar_substs.upvar_tys(def_id, tcx);
|
||||||
|
let upvars_with_tys = upvars.iter().zip(upvar_tys);
|
||||||
|
self.upvar_mutbls = upvars_with_tys.enumerate().map(|(i, ((&var_id, &upvar_id), ty))| {
|
||||||
|
let capture = hir_tables.upvar_capture(upvar_id);
|
||||||
|
|
||||||
|
let mut mutability = Mutability::Not;
|
||||||
|
let mut name = kw::Invalid;
|
||||||
|
if let Some(Node::Binding(pat)) = tcx_hir.find(var_id) {
|
||||||
|
if let hir::PatKind::Binding(_, _, ident, _) = pat.kind {
|
||||||
|
name = ident.name;
|
||||||
|
|
||||||
|
if let Some(&bm) = hir_tables.pat_binding_modes().get(pat.hir_id) {
|
||||||
|
if bm == ty::BindByValue(hir::Mutability::Mutable) {
|
||||||
|
mutability = Mutability::Mut;
|
||||||
|
} else {
|
||||||
|
mutability = Mutability::Not;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tcx.sess.delay_span_bug(pat.span, "missing binding mode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut projs = closure_env_projs.clone();
|
||||||
|
projs.push(ProjectionElem::Field(Field::new(i), ty));
|
||||||
|
match capture {
|
||||||
|
ty::UpvarCapture::ByValue => {}
|
||||||
|
ty::UpvarCapture::ByRef(..) => {
|
||||||
|
projs.push(ProjectionElem::Deref);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.var_debug_info.push(VarDebugInfo {
|
||||||
|
name,
|
||||||
|
source_info: SourceInfo {
|
||||||
|
scope: OUTERMOST_SOURCE_SCOPE,
|
||||||
|
span: tcx_hir.span(var_id),
|
||||||
|
},
|
||||||
|
place: Place {
|
||||||
|
base: closure_env_arg.into(),
|
||||||
|
projection: tcx.intern_place_elems(&projs),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
mutability
|
||||||
|
}).collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut scope = None;
|
let mut scope = None;
|
||||||
|
@ -148,9 +148,7 @@ fn temp_decl(mutability: Mutability, ty: Ty<'_>, span: Span) -> LocalDecl<'_> {
|
|||||||
mutability,
|
mutability,
|
||||||
ty,
|
ty,
|
||||||
user_ty: UserTypeProjections::none(),
|
user_ty: UserTypeProjections::none(),
|
||||||
name: None,
|
|
||||||
source_info,
|
source_info,
|
||||||
visibility_scope: source_info.scope,
|
|
||||||
internal: false,
|
internal: false,
|
||||||
local_info: LocalInfo::Other,
|
local_info: LocalInfo::Other,
|
||||||
is_block_tail: None,
|
is_block_tail: None,
|
||||||
@ -204,7 +202,6 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
|
|||||||
SourceScopeData { span: span, parent_scope: None }, 1
|
SourceScopeData { span: span, parent_scope: None }, 1
|
||||||
),
|
),
|
||||||
ClearCrossCrate::Clear,
|
ClearCrossCrate::Clear,
|
||||||
None,
|
|
||||||
local_decls_for_sig(&sig, span),
|
local_decls_for_sig(&sig, span),
|
||||||
IndexVec::new(),
|
IndexVec::new(),
|
||||||
sig.inputs().len(),
|
sig.inputs().len(),
|
||||||
@ -371,7 +368,6 @@ impl CloneShimBuilder<'tcx> {
|
|||||||
SourceScopeData { span: self.span, parent_scope: None }, 1
|
SourceScopeData { span: self.span, parent_scope: None }, 1
|
||||||
),
|
),
|
||||||
ClearCrossCrate::Clear,
|
ClearCrossCrate::Clear,
|
||||||
None,
|
|
||||||
self.local_decls,
|
self.local_decls,
|
||||||
IndexVec::new(),
|
IndexVec::new(),
|
||||||
self.sig.inputs().len(),
|
self.sig.inputs().len(),
|
||||||
@ -832,7 +828,6 @@ fn build_call_shim<'tcx>(
|
|||||||
SourceScopeData { span: span, parent_scope: None }, 1
|
SourceScopeData { span: span, parent_scope: None }, 1
|
||||||
),
|
),
|
||||||
ClearCrossCrate::Clear,
|
ClearCrossCrate::Clear,
|
||||||
None,
|
|
||||||
local_decls,
|
local_decls,
|
||||||
IndexVec::new(),
|
IndexVec::new(),
|
||||||
sig.inputs().len(),
|
sig.inputs().len(),
|
||||||
@ -919,7 +914,6 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &Body<'_> {
|
|||||||
SourceScopeData { span: span, parent_scope: None }, 1
|
SourceScopeData { span: span, parent_scope: None }, 1
|
||||||
),
|
),
|
||||||
ClearCrossCrate::Clear,
|
ClearCrossCrate::Clear,
|
||||||
None,
|
|
||||||
local_decls,
|
local_decls,
|
||||||
IndexVec::new(),
|
IndexVec::new(),
|
||||||
sig.inputs().len(),
|
sig.inputs().len(),
|
||||||
|
@ -85,7 +85,6 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
|
|||||||
body.basic_blocks().clone(),
|
body.basic_blocks().clone(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
ClearCrossCrate::Clear,
|
ClearCrossCrate::Clear,
|
||||||
None,
|
|
||||||
body.local_decls.clone(),
|
body.local_decls.clone(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
body.arg_count,
|
body.arg_count,
|
||||||
|
@ -62,7 +62,6 @@ use rustc_index::vec::{Idx, IndexVec};
|
|||||||
use rustc_index::bit_set::{BitSet, BitMatrix};
|
use rustc_index::bit_set::{BitSet, BitMatrix};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::mem;
|
|
||||||
use crate::transform::{MirPass, MirSource};
|
use crate::transform::{MirPass, MirSource};
|
||||||
use crate::transform::simplify;
|
use crate::transform::simplify;
|
||||||
use crate::transform::no_landing_pads::no_landing_pads;
|
use crate::transform::no_landing_pads::no_landing_pads;
|
||||||
@ -427,9 +426,7 @@ fn replace_result_variable<'tcx>(
|
|||||||
mutability: Mutability::Mut,
|
mutability: Mutability::Mut,
|
||||||
ty: ret_ty,
|
ty: ret_ty,
|
||||||
user_ty: UserTypeProjections::none(),
|
user_ty: UserTypeProjections::none(),
|
||||||
name: None,
|
|
||||||
source_info,
|
source_info,
|
||||||
visibility_scope: source_info.scope,
|
|
||||||
internal: false,
|
internal: false,
|
||||||
is_block_tail: None,
|
is_block_tail: None,
|
||||||
local_info: LocalInfo::Other
|
local_info: LocalInfo::Other
|
||||||
@ -788,18 +785,12 @@ fn compute_layout<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let dummy_local = LocalDecl::new_internal(tcx.mk_unit(), body.span);
|
// Gather live local types and their indices.
|
||||||
|
|
||||||
// Gather live locals and their indices replacing values in body.local_decls
|
|
||||||
// with a dummy to avoid changing local indices.
|
|
||||||
let mut locals = IndexVec::<GeneratorSavedLocal, _>::new();
|
let mut locals = IndexVec::<GeneratorSavedLocal, _>::new();
|
||||||
let mut tys = IndexVec::<GeneratorSavedLocal, _>::new();
|
let mut tys = IndexVec::<GeneratorSavedLocal, _>::new();
|
||||||
let mut decls = IndexVec::<GeneratorSavedLocal, _>::new();
|
|
||||||
for (idx, local) in live_locals.iter().enumerate() {
|
for (idx, local) in live_locals.iter().enumerate() {
|
||||||
let var = mem::replace(&mut body.local_decls[local], dummy_local.clone());
|
|
||||||
locals.push(local);
|
locals.push(local);
|
||||||
tys.push(var.ty);
|
tys.push(body.local_decls[local].ty);
|
||||||
decls.push(var);
|
|
||||||
debug!("generator saved local {:?} => {:?}", GeneratorSavedLocal::from(idx), local);
|
debug!("generator saved local {:?} => {:?}", GeneratorSavedLocal::from(idx), local);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -831,7 +822,6 @@ fn compute_layout<'tcx>(
|
|||||||
field_tys: tys,
|
field_tys: tys,
|
||||||
variant_fields,
|
variant_fields,
|
||||||
storage_conflicts,
|
storage_conflicts,
|
||||||
__local_debuginfo_codegen_only_do_not_use: decls,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
(remap, layout, storage_liveness)
|
(remap, layout, storage_liveness)
|
||||||
@ -962,9 +952,7 @@ fn create_generator_drop_shim<'tcx>(
|
|||||||
mutability: Mutability::Mut,
|
mutability: Mutability::Mut,
|
||||||
ty: tcx.mk_unit(),
|
ty: tcx.mk_unit(),
|
||||||
user_ty: UserTypeProjections::none(),
|
user_ty: UserTypeProjections::none(),
|
||||||
name: None,
|
|
||||||
source_info,
|
source_info,
|
||||||
visibility_scope: source_info.scope,
|
|
||||||
internal: false,
|
internal: false,
|
||||||
is_block_tail: None,
|
is_block_tail: None,
|
||||||
local_info: LocalInfo::Other
|
local_info: LocalInfo::Other
|
||||||
@ -980,9 +968,7 @@ fn create_generator_drop_shim<'tcx>(
|
|||||||
mutbl: hir::Mutability::Mutable,
|
mutbl: hir::Mutability::Mutable,
|
||||||
}),
|
}),
|
||||||
user_ty: UserTypeProjections::none(),
|
user_ty: UserTypeProjections::none(),
|
||||||
name: None,
|
|
||||||
source_info,
|
source_info,
|
||||||
visibility_scope: source_info.scope,
|
|
||||||
internal: false,
|
internal: false,
|
||||||
is_block_tail: None,
|
is_block_tail: None,
|
||||||
local_info: LocalInfo::Other
|
local_info: LocalInfo::Other
|
||||||
|
@ -219,13 +219,6 @@ impl Inliner<'tcx> {
|
|||||||
debug!("should_inline({:?})", callsite);
|
debug!("should_inline({:?})", callsite);
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
|
||||||
// Don't inline closures that have capture debuginfo
|
|
||||||
// FIXME: Handle closures better
|
|
||||||
if callee_body.__upvar_debuginfo_codegen_only_do_not_use.len() > 0 {
|
|
||||||
debug!(" upvar debuginfo present - not inlining");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cannot inline generators which haven't been transformed yet
|
// Cannot inline generators which haven't been transformed yet
|
||||||
if callee_body.yield_ty.is_some() {
|
if callee_body.yield_ty.is_some() {
|
||||||
debug!(" yield ty present - not inlining");
|
debug!(" yield ty present - not inlining");
|
||||||
@ -413,7 +406,6 @@ impl Inliner<'tcx> {
|
|||||||
local.source_info.scope =
|
local.source_info.scope =
|
||||||
scope_map[local.source_info.scope];
|
scope_map[local.source_info.scope];
|
||||||
local.source_info.span = callsite.location.span;
|
local.source_info.span = callsite.location.span;
|
||||||
local.visibility_scope = scope_map[local.visibility_scope];
|
|
||||||
|
|
||||||
let idx = caller_body.local_decls.push(local);
|
let idx = caller_body.local_decls.push(local);
|
||||||
local_map.push(idx);
|
local_map.push(idx);
|
||||||
@ -484,6 +476,10 @@ impl Inliner<'tcx> {
|
|||||||
tcx: self.tcx,
|
tcx: self.tcx,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
for mut var_debug_info in callee_body.var_debug_info.drain(..) {
|
||||||
|
integrator.visit_var_debug_info(&mut var_debug_info);
|
||||||
|
caller_body.var_debug_info.push(var_debug_info);
|
||||||
|
}
|
||||||
|
|
||||||
for (bb, mut block) in callee_body.basic_blocks_mut().drain_enumerated(..) {
|
for (bb, mut block) in callee_body.basic_blocks_mut().drain_enumerated(..) {
|
||||||
integrator.visit_basic_block_data(bb, &mut block);
|
integrator.visit_basic_block_data(bb, &mut block);
|
||||||
|
@ -1098,7 +1098,6 @@ pub fn promote_candidates<'tcx>(
|
|||||||
// memory usage?
|
// memory usage?
|
||||||
body.source_scopes.clone(),
|
body.source_scopes.clone(),
|
||||||
body.source_scope_local_data.clone(),
|
body.source_scope_local_data.clone(),
|
||||||
None,
|
|
||||||
initial_locals,
|
initial_locals,
|
||||||
IndexVec::new(),
|
IndexVec::new(),
|
||||||
0,
|
0,
|
||||||
|
@ -32,7 +32,6 @@ use rustc_index::vec::{Idx, IndexVec};
|
|||||||
use rustc::ty::TyCtxt;
|
use rustc::ty::TyCtxt;
|
||||||
use rustc::mir::*;
|
use rustc::mir::*;
|
||||||
use rustc::mir::visit::{MutVisitor, Visitor, PlaceContext, MutatingUseContext};
|
use rustc::mir::visit::{MutVisitor, Visitor, PlaceContext, MutatingUseContext};
|
||||||
use rustc::session::config::DebugInfo;
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use crate::transform::{MirPass, MirSource};
|
use crate::transform::{MirPass, MirSource};
|
||||||
|
|
||||||
@ -307,13 +306,6 @@ impl<'tcx> MirPass<'tcx> for SimplifyLocals {
|
|||||||
marker.locals.insert(arg);
|
marker.locals.insert(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We may need to keep dead user variables live for debuginfo.
|
|
||||||
if tcx.sess.opts.debuginfo == DebugInfo::Full {
|
|
||||||
for local in body.vars_iter() {
|
|
||||||
marker.locals.insert(local);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
marker.locals
|
marker.locals
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -362,6 +362,7 @@ impl<'tcx> Visitor<'tcx> for RestoreDataCollector {
|
|||||||
match context {
|
match context {
|
||||||
PlaceContext::NonUse(NonUseContext::StorageLive) => local_use.alive = Some(location),
|
PlaceContext::NonUse(NonUseContext::StorageLive) => local_use.alive = Some(location),
|
||||||
PlaceContext::NonUse(NonUseContext::StorageDead) => local_use.dead = Some(location),
|
PlaceContext::NonUse(NonUseContext::StorageDead) => local_use.dead = Some(location),
|
||||||
|
PlaceContext::NonUse(NonUseContext::VarDebugInfo) => {}
|
||||||
_ => {
|
_ => {
|
||||||
local_use.use_count += 1;
|
local_use.use_count += 1;
|
||||||
if local_use.first_use.is_none() {
|
if local_use.first_use.is_none() {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Def-use analysis.
|
//! Def-use analysis.
|
||||||
|
|
||||||
use rustc::mir::{Body, Local, Location, PlaceElem};
|
use rustc::mir::{Body, Local, Location, PlaceElem, VarDebugInfo};
|
||||||
use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
|
use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
|
||||||
use rustc::ty::TyCtxt;
|
use rustc::ty::TyCtxt;
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
@ -12,7 +12,9 @@ pub struct DefUseAnalysis {
|
|||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Info {
|
pub struct Info {
|
||||||
|
// FIXME(eddyb) use smallvec where possible.
|
||||||
pub defs_and_uses: Vec<Use>,
|
pub defs_and_uses: Vec<Use>,
|
||||||
|
var_debug_info_indices: Vec<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -33,6 +35,8 @@ impl DefUseAnalysis {
|
|||||||
|
|
||||||
let mut finder = DefUseFinder {
|
let mut finder = DefUseFinder {
|
||||||
info: mem::take(&mut self.info),
|
info: mem::take(&mut self.info),
|
||||||
|
var_debug_info_index: 0,
|
||||||
|
in_var_debug_info: false,
|
||||||
};
|
};
|
||||||
finder.visit_body(body);
|
finder.visit_body(body);
|
||||||
self.info = finder.info
|
self.info = finder.info
|
||||||
@ -55,9 +59,14 @@ impl DefUseAnalysis {
|
|||||||
new_local: Local,
|
new_local: Local,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
) {
|
) {
|
||||||
for place_use in &self.info[local].defs_and_uses {
|
let mut visitor = MutateUseVisitor::new(local, new_local, body, tcx);
|
||||||
MutateUseVisitor::new(local, new_local, body, tcx)
|
let info = &self.info[local];
|
||||||
.visit_location(body, place_use.location)
|
for place_use in &info.defs_and_uses {
|
||||||
|
visitor.visit_location(body, place_use.location)
|
||||||
|
}
|
||||||
|
// Update debuginfo as well, alongside defs/uses.
|
||||||
|
for &i in &info.var_debug_info_indices {
|
||||||
|
visitor.visit_var_debug_info(&mut body.var_debug_info[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,6 +82,8 @@ impl DefUseAnalysis {
|
|||||||
|
|
||||||
struct DefUseFinder {
|
struct DefUseFinder {
|
||||||
info: IndexVec<Local, Info>,
|
info: IndexVec<Local, Info>,
|
||||||
|
var_debug_info_index: usize,
|
||||||
|
in_var_debug_info: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Visitor<'_> for DefUseFinder {
|
impl Visitor<'_> for DefUseFinder {
|
||||||
@ -80,22 +91,36 @@ impl Visitor<'_> for DefUseFinder {
|
|||||||
&local: &Local,
|
&local: &Local,
|
||||||
context: PlaceContext,
|
context: PlaceContext,
|
||||||
location: Location) {
|
location: Location) {
|
||||||
self.info[local].defs_and_uses.push(Use {
|
let info = &mut self.info[local];
|
||||||
|
if self.in_var_debug_info {
|
||||||
|
info.var_debug_info_indices.push(self.var_debug_info_index);
|
||||||
|
} else {
|
||||||
|
info.defs_and_uses.push(Use {
|
||||||
context,
|
context,
|
||||||
location,
|
location,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn visit_var_debug_info(&mut self, var_debug_info: &VarDebugInfo<'tcx>) {
|
||||||
|
assert!(!self.in_var_debug_info);
|
||||||
|
self.in_var_debug_info = true;
|
||||||
|
self.super_var_debug_info(var_debug_info);
|
||||||
|
self.in_var_debug_info = false;
|
||||||
|
self.var_debug_info_index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Info {
|
impl Info {
|
||||||
fn new() -> Info {
|
fn new() -> Info {
|
||||||
Info {
|
Info {
|
||||||
defs_and_uses: vec![],
|
defs_and_uses: vec![],
|
||||||
|
var_debug_info_indices: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear(&mut self) {
|
fn clear(&mut self) {
|
||||||
self.defs_and_uses.clear();
|
self.defs_and_uses.clear();
|
||||||
|
self.var_debug_info_indices.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn def_count(&self) -> usize {
|
pub fn def_count(&self) -> usize {
|
||||||
|
@ -197,13 +197,13 @@ fn write_graph_label<'tcx, W: Write>(
|
|||||||
write!(w, "mut ")?;
|
write!(w, "mut ")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(name) = decl.name {
|
|
||||||
write!(w, r#"{:?}: {}; // {}<br align="left"/>"#,
|
|
||||||
Place::from(local), escape(&decl.ty), name)?;
|
|
||||||
} else {
|
|
||||||
write!(w, r#"{:?}: {};<br align="left"/>"#,
|
write!(w, r#"{:?}: {};<br align="left"/>"#,
|
||||||
Place::from(local), escape(&decl.ty))?;
|
Place::from(local), escape(&decl.ty))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for var_debug_info in &body.var_debug_info {
|
||||||
|
write!(w, r#"debug {} => {};<br align="left"/>"#,
|
||||||
|
var_debug_info.name, escape(&var_debug_info.place))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeln!(w, ">;")
|
writeln!(w, ">;")
|
||||||
|
@ -183,6 +183,9 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
|
|||||||
|
|
||||||
PlaceContext::MutatingUse(MutatingUseContext::Drop) =>
|
PlaceContext::MutatingUse(MutatingUseContext::Drop) =>
|
||||||
Some(DefUse::Drop),
|
Some(DefUse::Drop),
|
||||||
|
|
||||||
|
// Debug info is neither def nor use.
|
||||||
|
PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,6 +463,30 @@ fn write_scope_tree(
|
|||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
let indent = depth * INDENT.len();
|
let indent = depth * INDENT.len();
|
||||||
|
|
||||||
|
// Local variable debuginfo.
|
||||||
|
for var_debug_info in &body.var_debug_info {
|
||||||
|
if var_debug_info.source_info.scope != parent {
|
||||||
|
// Not declared in this scope.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let indented_debug_info = format!(
|
||||||
|
"{0:1$}debug {2} => {3:?};",
|
||||||
|
INDENT,
|
||||||
|
indent,
|
||||||
|
var_debug_info.name,
|
||||||
|
var_debug_info.place,
|
||||||
|
);
|
||||||
|
|
||||||
|
writeln!(
|
||||||
|
w,
|
||||||
|
"{0:1$} // in {2}",
|
||||||
|
indented_debug_info,
|
||||||
|
ALIGN,
|
||||||
|
comment(tcx, var_debug_info.source_info),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
// Local variable types (including the user's name in a comment).
|
// Local variable types (including the user's name in a comment).
|
||||||
for (local, local_decl) in body.local_decls.iter_enumerated() {
|
for (local, local_decl) in body.local_decls.iter_enumerated() {
|
||||||
if (1..body.arg_count+1).contains(&local.index()) {
|
if (1..body.arg_count+1).contains(&local.index()) {
|
||||||
@ -496,8 +520,6 @@ fn write_scope_tree(
|
|||||||
|
|
||||||
let local_name = if local == RETURN_PLACE {
|
let local_name = if local == RETURN_PLACE {
|
||||||
format!(" return place")
|
format!(" return place")
|
||||||
} else if let Some(name) = local_decl.name {
|
|
||||||
format!(" \"{}\"", name)
|
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
};
|
};
|
||||||
|
@ -25,7 +25,7 @@ pub fn change_loop_body() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(cfail1))]
|
#[cfg(not(cfail1))]
|
||||||
#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")]
|
#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")]
|
||||||
#[rustc_clean(cfg="cfail3")]
|
#[rustc_clean(cfg="cfail3")]
|
||||||
pub fn change_loop_body() {
|
pub fn change_loop_body() {
|
||||||
let mut _x = 0;
|
let mut _x = 0;
|
||||||
|
@ -22,7 +22,7 @@ pub fn change_name() {
|
|||||||
|
|
||||||
#[cfg(not(cfail1))]
|
#[cfg(not(cfail1))]
|
||||||
#[rustc_clean(cfg="cfail2",
|
#[rustc_clean(cfg="cfail2",
|
||||||
except="HirBody,mir_built")]
|
except="HirBody,mir_built,optimized_mir")]
|
||||||
#[rustc_clean(cfg="cfail3")]
|
#[rustc_clean(cfg="cfail3")]
|
||||||
pub fn change_name() {
|
pub fn change_name() {
|
||||||
let _y = 2u64;
|
let _y = 2u64;
|
||||||
@ -86,7 +86,7 @@ pub fn change_mutability_of_slot() {
|
|||||||
|
|
||||||
#[cfg(not(cfail1))]
|
#[cfg(not(cfail1))]
|
||||||
#[rustc_clean(cfg="cfail2",
|
#[rustc_clean(cfg="cfail2",
|
||||||
except="HirBody,typeck_tables_of,mir_built")]
|
except="HirBody,typeck_tables_of,mir_built,optimized_mir")]
|
||||||
#[rustc_clean(cfg="cfail3")]
|
#[rustc_clean(cfg="cfail3")]
|
||||||
pub fn change_mutability_of_slot() {
|
pub fn change_mutability_of_slot() {
|
||||||
let _x: u64 = 0;
|
let _x: u64 = 0;
|
||||||
@ -182,7 +182,7 @@ pub fn add_initializer() {
|
|||||||
|
|
||||||
#[cfg(not(cfail1))]
|
#[cfg(not(cfail1))]
|
||||||
#[rustc_clean(cfg="cfail2",
|
#[rustc_clean(cfg="cfail2",
|
||||||
except="HirBody,typeck_tables_of,mir_built")]
|
except="HirBody,typeck_tables_of,mir_built,optimized_mir")]
|
||||||
#[rustc_clean(cfg="cfail3")]
|
#[rustc_clean(cfg="cfail3")]
|
||||||
pub fn add_initializer() {
|
pub fn add_initializer() {
|
||||||
let _x: i16 = 3i16;
|
let _x: i16 = 3i16;
|
||||||
@ -198,7 +198,7 @@ pub fn change_initializer() {
|
|||||||
|
|
||||||
#[cfg(not(cfail1))]
|
#[cfg(not(cfail1))]
|
||||||
#[rustc_clean(cfg="cfail2",
|
#[rustc_clean(cfg="cfail2",
|
||||||
except="HirBody,mir_built")]
|
except="HirBody,mir_built,optimized_mir")]
|
||||||
#[rustc_clean(cfg="cfail3")]
|
#[rustc_clean(cfg="cfail3")]
|
||||||
pub fn change_initializer() {
|
pub fn change_initializer() {
|
||||||
let _x = 5u16;
|
let _x = 5u16;
|
||||||
|
@ -25,7 +25,7 @@ pub fn change_loop_body() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(cfail1))]
|
#[cfg(not(cfail1))]
|
||||||
#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")]
|
#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")]
|
||||||
#[rustc_clean(cfg="cfail3")]
|
#[rustc_clean(cfg="cfail3")]
|
||||||
pub fn change_loop_body() {
|
pub fn change_loop_body() {
|
||||||
let mut _x = 0;
|
let mut _x = 0;
|
||||||
|
@ -25,7 +25,7 @@ pub fn change_loop_body() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(cfail1))]
|
#[cfg(not(cfail1))]
|
||||||
#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")]
|
#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")]
|
||||||
#[rustc_clean(cfg="cfail3")]
|
#[rustc_clean(cfg="cfail3")]
|
||||||
pub fn change_loop_body() {
|
pub fn change_loop_body() {
|
||||||
let mut _x = 0;
|
let mut _x = 0;
|
||||||
@ -48,7 +48,7 @@ pub fn change_loop_condition() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(cfail1))]
|
#[cfg(not(cfail1))]
|
||||||
#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")]
|
#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")]
|
||||||
#[rustc_clean(cfg="cfail3")]
|
#[rustc_clean(cfg="cfail3")]
|
||||||
pub fn change_loop_condition() {
|
pub fn change_loop_condition() {
|
||||||
let mut _x = 0;
|
let mut _x = 0;
|
||||||
|
@ -27,6 +27,7 @@ impl Drop for S {
|
|||||||
// let _3: ();
|
// let _3: ();
|
||||||
// let mut _4: std::boxed::Box<S>;
|
// let mut _4: std::boxed::Box<S>;
|
||||||
// scope 1 {
|
// scope 1 {
|
||||||
|
// debug x => _1;
|
||||||
// }
|
// }
|
||||||
// bb0: {
|
// bb0: {
|
||||||
// StorageLive(_1);
|
// StorageLive(_1);
|
||||||
|
@ -37,8 +37,10 @@ fn main() {
|
|||||||
// ...
|
// ...
|
||||||
// let mut _9: Bar;
|
// let mut _9: Bar;
|
||||||
// scope 1 {
|
// scope 1 {
|
||||||
|
// debug a => _2;
|
||||||
// let _3: Bar;
|
// let _3: Bar;
|
||||||
// scope 2 {
|
// scope 2 {
|
||||||
|
// debug b => _3;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// bb0: {
|
// bb0: {
|
||||||
|
@ -17,7 +17,27 @@ fn foo<T: Copy>(_t: T, q: &i32) -> i32 {
|
|||||||
|
|
||||||
// END RUST SOURCE
|
// END RUST SOURCE
|
||||||
// START rustc.foo.Inline.after.mir
|
// START rustc.foo.Inline.after.mir
|
||||||
// ...
|
// fn foo(_1: T, _2: &i32) -> i32{
|
||||||
|
// debug _t => _1;
|
||||||
|
// debug q => _2;
|
||||||
|
// let mut _0: i32;
|
||||||
|
// let _3: [closure@HirId { owner: DefIndex(4), local_id: 31 }];
|
||||||
|
// let mut _4: &[closure@HirId { owner: DefIndex(4), local_id: 31 }];
|
||||||
|
// let mut _5: (&i32, &i32);
|
||||||
|
// let mut _6: &i32;
|
||||||
|
// let mut _7: &i32;
|
||||||
|
// let mut _8: &i32;
|
||||||
|
// let mut _9: &i32;
|
||||||
|
// scope 1 {
|
||||||
|
// debug x => _3;
|
||||||
|
// scope 2 {
|
||||||
|
// debug r => _8;
|
||||||
|
// debug _s => _9;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// scope 3 {
|
||||||
|
// debug variable => _8;
|
||||||
|
// }
|
||||||
// bb0: {
|
// bb0: {
|
||||||
// ...
|
// ...
|
||||||
// _3 = [closure@HirId { owner: DefIndex(4), local_id: 31 }];
|
// _3 = [closure@HirId { owner: DefIndex(4), local_id: 31 }];
|
||||||
@ -35,5 +55,5 @@ fn foo<T: Copy>(_t: T, q: &i32) -> i32 {
|
|||||||
// ...
|
// ...
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
// ...
|
// }
|
||||||
// END rustc.foo.Inline.after.mir
|
// END rustc.foo.Inline.after.mir
|
||||||
|
60
src/test/mir-opt/inline-closure-captures.rs
Normal file
60
src/test/mir-opt/inline-closure-captures.rs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// compile-flags: -Z span_free_formats
|
||||||
|
|
||||||
|
// Tests that MIR inliner can handle closure captures.
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("{:?}", foo(0, 14));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo<T: Copy>(t: T, q: i32) -> (i32, T) {
|
||||||
|
let x = |_q| (q, t);
|
||||||
|
x(q)
|
||||||
|
}
|
||||||
|
|
||||||
|
// END RUST SOURCE
|
||||||
|
// START rustc.foo.Inline.after.mir
|
||||||
|
// fn foo(_1: T, _2: i32) -> (i32, T){
|
||||||
|
// debug t => _1;
|
||||||
|
// debug q => _2;
|
||||||
|
// let mut _0: (i32, T);
|
||||||
|
// let _3: [closure@HirId { owner: DefIndex(4), local_id: 15 } q:&i32, t:&T];
|
||||||
|
// let mut _4: &i32;
|
||||||
|
// let mut _5: &T;
|
||||||
|
// let mut _6: &[closure@HirId { owner: DefIndex(4), local_id: 15 } q:&i32, t:&T];
|
||||||
|
// let mut _7: (i32,);
|
||||||
|
// let mut _8: i32;
|
||||||
|
// let mut _11: i32;
|
||||||
|
// scope 1 {
|
||||||
|
// debug x => _3;
|
||||||
|
// scope 2 {
|
||||||
|
// debug _q => _11;
|
||||||
|
// debug q => (*((*_6).0: &i32));
|
||||||
|
// debug t => (*((*_6).1: &T));
|
||||||
|
// let mut _9: i32;
|
||||||
|
// let mut _10: T;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// bb0: {
|
||||||
|
// ...
|
||||||
|
// _4 = &_2;
|
||||||
|
// ...
|
||||||
|
// _5 = &_1;
|
||||||
|
// _3 = [closure@HirId { owner: DefIndex(4), local_id: 15 }] { q: move _4, t: move _5 };
|
||||||
|
// ...
|
||||||
|
// _6 = &_3;
|
||||||
|
// ...
|
||||||
|
// ...
|
||||||
|
// _8 = _2;
|
||||||
|
// _7 = (move _8,);
|
||||||
|
// _11 = move (_7.0: i32);
|
||||||
|
// ...
|
||||||
|
// _9 = (*((*_6).0: &i32));
|
||||||
|
// ...
|
||||||
|
// _10 = (*((*_6).1: &T));
|
||||||
|
// (_0.0: i32) = move _9;
|
||||||
|
// (_0.1: T) = move _10;
|
||||||
|
// ...
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// END rustc.foo.Inline.after.mir
|
@ -13,7 +13,24 @@ fn foo<T: Copy>(_t: T, q: i32) -> i32 {
|
|||||||
|
|
||||||
// END RUST SOURCE
|
// END RUST SOURCE
|
||||||
// START rustc.foo.Inline.after.mir
|
// START rustc.foo.Inline.after.mir
|
||||||
// ...
|
// fn foo(_1: T, _2: i32) -> i32{
|
||||||
|
// debug _t => _1;
|
||||||
|
// debug q => _2;
|
||||||
|
// let mut _0: i32;
|
||||||
|
// let _3: [closure@HirId { owner: DefIndex(4), local_id: 15 }];
|
||||||
|
// let mut _4: &[closure@HirId { owner: DefIndex(4), local_id: 15 }];
|
||||||
|
// let mut _5: (i32, i32);
|
||||||
|
// let mut _6: i32;
|
||||||
|
// let mut _7: i32;
|
||||||
|
// let mut _8: i32;
|
||||||
|
// let mut _9: i32;
|
||||||
|
// scope 1 {
|
||||||
|
// debug x => _3;
|
||||||
|
// scope 2 {
|
||||||
|
// debug _t => _8;
|
||||||
|
// debug _q => _9;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
// bb0: {
|
// bb0: {
|
||||||
// ...
|
// ...
|
||||||
// _3 = [closure@HirId { owner: DefIndex(4), local_id: 15 }];
|
// _3 = [closure@HirId { owner: DefIndex(4), local_id: 15 }];
|
||||||
@ -30,5 +47,4 @@ fn foo<T: Copy>(_t: T, q: i32) -> i32 {
|
|||||||
// ...
|
// ...
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
// ...
|
|
||||||
// END rustc.foo.Inline.after.mir
|
// END rustc.foo.Inline.after.mir
|
||||||
|
@ -35,6 +35,7 @@ impl S {
|
|||||||
// let mut _4: S;
|
// let mut _4: S;
|
||||||
// let mut _5: bool;
|
// let mut _5: bool;
|
||||||
// scope 1 {
|
// scope 1 {
|
||||||
|
// debug x => _1;
|
||||||
// }
|
// }
|
||||||
// ...
|
// ...
|
||||||
// bb0: {
|
// bb0: {
|
||||||
@ -47,7 +48,11 @@ impl S {
|
|||||||
// let mut _5: S;
|
// let mut _5: S;
|
||||||
// let mut _6: bool;
|
// let mut _6: bool;
|
||||||
// ...
|
// ...
|
||||||
|
// debug u => _1;
|
||||||
|
// ...
|
||||||
// let mut _2: S;
|
// let mut _2: S;
|
||||||
// ...
|
// ...
|
||||||
|
// debug v => _2;
|
||||||
|
// ...
|
||||||
// bb0: {
|
// bb0: {
|
||||||
// END rustc.test.ElaborateDrops.after.mir
|
// END rustc.test.ElaborateDrops.after.mir
|
||||||
|
@ -25,9 +25,11 @@ enum E {
|
|||||||
// fn main() -> () {
|
// fn main() -> () {
|
||||||
// let mut _0: ();
|
// let mut _0: ();
|
||||||
// scope 1 {
|
// scope 1 {
|
||||||
// let _1: E; // `e`
|
// let _1: E;
|
||||||
|
// debug e => _1;
|
||||||
// scope 2 {
|
// scope 2 {
|
||||||
// let _6: K;
|
// let _6: K;
|
||||||
|
// debug _k => _6;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// let mut _2: bool;
|
// let mut _2: bool;
|
||||||
|
@ -24,6 +24,7 @@ fn main() {
|
|||||||
// let _5: ();
|
// let _5: ();
|
||||||
// let mut _6: &i32;
|
// let mut _6: &i32;
|
||||||
// scope 1 {
|
// scope 1 {
|
||||||
|
// debug beacon => _2;
|
||||||
// }
|
// }
|
||||||
// bb0: {
|
// bb0: {
|
||||||
// goto -> bb1;
|
// goto -> bb1;
|
||||||
|
@ -53,8 +53,14 @@ fn main() {
|
|||||||
// let _15: bool; // `b`
|
// let _15: bool; // `b`
|
||||||
// let _16: std::string::String; // `t`
|
// let _16: std::string::String; // `t`
|
||||||
// scope 1 {
|
// scope 1 {
|
||||||
|
// debug a => _5;
|
||||||
|
// debug a => _6;
|
||||||
|
// debug s => _7;
|
||||||
|
// debug s => _8;
|
||||||
// }
|
// }
|
||||||
// scope 2 {
|
// scope 2 {
|
||||||
|
// debug b => _15;
|
||||||
|
// debug t => _16;
|
||||||
// }
|
// }
|
||||||
// bb0: {
|
// bb0: {
|
||||||
// FakeRead(ForMatchedPlace, _2);
|
// FakeRead(ForMatchedPlace, _2);
|
||||||
|
@ -29,8 +29,12 @@ fn main() {
|
|||||||
// START rustc.main.nll.0.mir
|
// START rustc.main.nll.0.mir
|
||||||
// let _2: &'_#3r usize;
|
// let _2: &'_#3r usize;
|
||||||
// ...
|
// ...
|
||||||
|
// debug p => _2;
|
||||||
|
// ...
|
||||||
// let _6: &'_#4r usize;
|
// let _6: &'_#4r usize;
|
||||||
// ...
|
// ...
|
||||||
|
// debug q => _6;
|
||||||
|
// ...
|
||||||
// _2 = &'_#2r _1[_3];
|
// _2 = &'_#2r _1[_3];
|
||||||
// ...
|
// ...
|
||||||
// _6 = _2;
|
// _6 = _2;
|
||||||
|
@ -25,6 +25,7 @@ impl Drop for Droppy {
|
|||||||
// let mut _5: Droppy;
|
// let mut _5: Droppy;
|
||||||
// let mut _6: Aligned;
|
// let mut _6: Aligned;
|
||||||
// scope 1 {
|
// scope 1 {
|
||||||
|
// debug x => _1;
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// bb0: {
|
// bb0: {
|
||||||
|
@ -10,6 +10,7 @@ fn main() {
|
|||||||
// END RUST SOURCE
|
// END RUST SOURCE
|
||||||
// START rustc.try_identity.SimplifyArmIdentity.before.mir
|
// START rustc.try_identity.SimplifyArmIdentity.before.mir
|
||||||
// fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
|
// fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
|
||||||
|
// debug x => _1;
|
||||||
// let mut _0: std::result::Result<u32, i32>;
|
// let mut _0: std::result::Result<u32, i32>;
|
||||||
// let _2: u32;
|
// let _2: u32;
|
||||||
// let mut _3: std::result::Result<u32, i32>;
|
// let mut _3: std::result::Result<u32, i32>;
|
||||||
@ -22,21 +23,27 @@ fn main() {
|
|||||||
// let _10: u32;
|
// let _10: u32;
|
||||||
// let mut _11: u32;
|
// let mut _11: u32;
|
||||||
// scope 1 {
|
// scope 1 {
|
||||||
|
// debug y => _10;
|
||||||
// }
|
// }
|
||||||
// scope 2 {
|
// scope 2 {
|
||||||
|
// debug err => _6;
|
||||||
// scope 3 {
|
// scope 3 {
|
||||||
// scope 7 {
|
// scope 7 {
|
||||||
|
// debug t => _6;
|
||||||
// }
|
// }
|
||||||
// scope 8 {
|
// scope 8 {
|
||||||
|
// debug v => _6;
|
||||||
// let mut _12: i32;
|
// let mut _12: i32;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// scope 4 {
|
// scope 4 {
|
||||||
|
// debug val => _10;
|
||||||
// scope 5 {
|
// scope 5 {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// scope 6 {
|
// scope 6 {
|
||||||
|
// debug self => _1;
|
||||||
// }
|
// }
|
||||||
// bb0: {
|
// bb0: {
|
||||||
// _5 = discriminant(_1);
|
// _5 = discriminant(_1);
|
||||||
@ -65,6 +72,7 @@ fn main() {
|
|||||||
|
|
||||||
// START rustc.try_identity.SimplifyArmIdentity.after.mir
|
// START rustc.try_identity.SimplifyArmIdentity.after.mir
|
||||||
// fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
|
// fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
|
||||||
|
// debug x => _1;
|
||||||
// let mut _0: std::result::Result<u32, i32>;
|
// let mut _0: std::result::Result<u32, i32>;
|
||||||
// let _2: u32;
|
// let _2: u32;
|
||||||
// let mut _3: std::result::Result<u32, i32>;
|
// let mut _3: std::result::Result<u32, i32>;
|
||||||
@ -77,21 +85,27 @@ fn main() {
|
|||||||
// let _10: u32;
|
// let _10: u32;
|
||||||
// let mut _11: u32;
|
// let mut _11: u32;
|
||||||
// scope 1 {
|
// scope 1 {
|
||||||
|
// debug y => _10;
|
||||||
// }
|
// }
|
||||||
// scope 2 {
|
// scope 2 {
|
||||||
|
// debug err => _6;
|
||||||
// scope 3 {
|
// scope 3 {
|
||||||
// scope 7 {
|
// scope 7 {
|
||||||
|
// debug t => _6;
|
||||||
// }
|
// }
|
||||||
// scope 8 {
|
// scope 8 {
|
||||||
|
// debug v => _6;
|
||||||
// let mut _12: i32;
|
// let mut _12: i32;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// scope 4 {
|
// scope 4 {
|
||||||
|
// debug val => _10;
|
||||||
// scope 5 {
|
// scope 5 {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// scope 6 {
|
// scope 6 {
|
||||||
|
// debug self => _1;
|
||||||
// }
|
// }
|
||||||
// bb0: {
|
// bb0: {
|
||||||
// _5 = discriminant(_1);
|
// _5 = discriminant(_1);
|
||||||
@ -120,6 +134,7 @@ fn main() {
|
|||||||
|
|
||||||
// START rustc.try_identity.SimplifyBranchSame.after.mir
|
// START rustc.try_identity.SimplifyBranchSame.after.mir
|
||||||
// fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
|
// fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
|
||||||
|
// debug x => _1;
|
||||||
// let mut _0: std::result::Result<u32, i32>;
|
// let mut _0: std::result::Result<u32, i32>;
|
||||||
// let _2: u32;
|
// let _2: u32;
|
||||||
// let mut _3: std::result::Result<u32, i32>;
|
// let mut _3: std::result::Result<u32, i32>;
|
||||||
@ -132,21 +147,27 @@ fn main() {
|
|||||||
// let _10: u32;
|
// let _10: u32;
|
||||||
// let mut _11: u32;
|
// let mut _11: u32;
|
||||||
// scope 1 {
|
// scope 1 {
|
||||||
|
// debug y => _10;
|
||||||
// }
|
// }
|
||||||
// scope 2 {
|
// scope 2 {
|
||||||
|
// debug err => _6;
|
||||||
// scope 3 {
|
// scope 3 {
|
||||||
// scope 7 {
|
// scope 7 {
|
||||||
|
// debug t => _6;
|
||||||
// }
|
// }
|
||||||
// scope 8 {
|
// scope 8 {
|
||||||
|
// debug v => _6;
|
||||||
// let mut _12: i32;
|
// let mut _12: i32;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// scope 4 {
|
// scope 4 {
|
||||||
|
// debug val => _10;
|
||||||
// scope 5 {
|
// scope 5 {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// scope 6 {
|
// scope 6 {
|
||||||
|
// debug self => _1;
|
||||||
// }
|
// }
|
||||||
// bb0: {
|
// bb0: {
|
||||||
// _5 = discriminant(_1);
|
// _5 = discriminant(_1);
|
||||||
@ -166,23 +187,32 @@ fn main() {
|
|||||||
|
|
||||||
// START rustc.try_identity.SimplifyLocals.after.mir
|
// START rustc.try_identity.SimplifyLocals.after.mir
|
||||||
// fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
|
// fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
|
||||||
|
// debug x => _1;
|
||||||
// let mut _0: std::result::Result<u32, i32>;
|
// let mut _0: std::result::Result<u32, i32>;
|
||||||
// let mut _2: isize;
|
// let mut _2: isize;
|
||||||
|
// let _3: i32;
|
||||||
|
// let _4: u32;
|
||||||
// scope 1 {
|
// scope 1 {
|
||||||
|
// debug y => _4;
|
||||||
// }
|
// }
|
||||||
// scope 2 {
|
// scope 2 {
|
||||||
|
// debug err => _3;
|
||||||
// scope 3 {
|
// scope 3 {
|
||||||
// scope 7 {
|
// scope 7 {
|
||||||
|
// debug t => _3;
|
||||||
// }
|
// }
|
||||||
// scope 8 {
|
// scope 8 {
|
||||||
|
// debug v => _3;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// scope 4 {
|
// scope 4 {
|
||||||
|
// debug val => _4;
|
||||||
// scope 5 {
|
// scope 5 {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// scope 6 {
|
// scope 6 {
|
||||||
|
// debug self => _1;
|
||||||
// }
|
// }
|
||||||
// bb0: {
|
// bb0: {
|
||||||
// _2 = discriminant(_1);
|
// _2 = discriminant(_1);
|
||||||
|
Loading…
Reference in New Issue
Block a user