mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-05 14:37:37 +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.
|
||||
pub spread_arg: Option<Local>,
|
||||
|
||||
/// Names and capture modes of all the closure upvars, assuming
|
||||
/// the first argument is either the closure or a reference to it.
|
||||
//
|
||||
// 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>,
|
||||
/// Debug information pertaining to user variables, including captures.
|
||||
pub var_debug_info: Vec<VarDebugInfo<'tcx>>,
|
||||
|
||||
/// 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
|
||||
@ -170,11 +164,10 @@ impl<'tcx> Body<'tcx> {
|
||||
basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
|
||||
source_scopes: IndexVec<SourceScope, SourceScopeData>,
|
||||
source_scope_local_data: ClearCrossCrate<IndexVec<SourceScope, SourceScopeLocalData>>,
|
||||
yield_ty: Option<Ty<'tcx>>,
|
||||
local_decls: LocalDecls<'tcx>,
|
||||
user_type_annotations: CanonicalUserTypeAnnotations<'tcx>,
|
||||
arg_count: usize,
|
||||
__upvar_debuginfo_codegen_only_do_not_use: Vec<UpvarDebuginfo>,
|
||||
var_debug_info: Vec<VarDebugInfo<'tcx>>,
|
||||
span: Span,
|
||||
control_flow_destroyed: Vec<(Span, String)>,
|
||||
) -> Self {
|
||||
@ -191,14 +184,14 @@ impl<'tcx> Body<'tcx> {
|
||||
basic_blocks,
|
||||
source_scopes,
|
||||
source_scope_local_data,
|
||||
yield_ty,
|
||||
yield_ty: None,
|
||||
generator_drop: None,
|
||||
generator_layout: None,
|
||||
local_decls,
|
||||
user_type_annotations,
|
||||
arg_count,
|
||||
__upvar_debuginfo_codegen_only_do_not_use,
|
||||
spread_arg: None,
|
||||
var_debug_info,
|
||||
span,
|
||||
cache: cache::Cache::new(),
|
||||
control_flow_destroyed,
|
||||
@ -280,7 +273,7 @@ impl<'tcx> Body<'tcx> {
|
||||
LocalKind::ReturnPointer
|
||||
} else if index < self.arg_count + 1 {
|
||||
LocalKind::Arg
|
||||
} else if self.local_decls[local].name.is_some() {
|
||||
} else if self.local_decls[local].is_user_variable() {
|
||||
LocalKind::Var
|
||||
} else {
|
||||
LocalKind::Temp
|
||||
@ -728,12 +721,6 @@ pub struct LocalDecl<'tcx> {
|
||||
// FIXME(matthewjasper) Don't store in this in `Body`
|
||||
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
|
||||
/// in. If the local was defined in a let-statement, this
|
||||
/// 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`.
|
||||
///
|
||||
/// 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
|
||||
/// "syntactic" lint scope (with a variable being under its let
|
||||
/// block) while the `visibility_scope` represents the "local variable"
|
||||
/// for a local. We have the `source_info.scope` represent the "syntactic"
|
||||
/// lint scope (with a variable being under its let block) while the
|
||||
/// `var_debug_info.source_info.scope` represents the "local variable"
|
||||
/// scope (where the "rest" of a block is under all prior let-statements).
|
||||
///
|
||||
/// The end result looks like this:
|
||||
@ -806,18 +793,14 @@ pub struct LocalDecl<'tcx> {
|
||||
/// │ │
|
||||
/// │ │ │{ let y: u32 }
|
||||
/// │ │ │
|
||||
/// │ │ │← y.visibility_scope
|
||||
/// │ │ │← y.var_debug_info.source_info.scope
|
||||
/// │ │ │← `y + 2`
|
||||
/// │
|
||||
/// │ │{ let x: u32 }
|
||||
/// │ │← x.visibility_scope
|
||||
/// │ │← x.var_debug_info.source_info.scope
|
||||
/// │ │← `drop(x)` // This accesses `x: u32`.
|
||||
/// ```
|
||||
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.
|
||||
@ -955,9 +938,7 @@ impl<'tcx> LocalDecl<'tcx> {
|
||||
mutability,
|
||||
ty,
|
||||
user_ty: UserTypeProjections::none(),
|
||||
name: None,
|
||||
source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE },
|
||||
visibility_scope: OUTERMOST_SOURCE_SCOPE,
|
||||
internal,
|
||||
local_info: LocalInfo::Other,
|
||||
is_block_tail: None,
|
||||
@ -974,22 +955,27 @@ impl<'tcx> LocalDecl<'tcx> {
|
||||
ty: return_ty,
|
||||
user_ty: UserTypeProjections::none(),
|
||||
source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE },
|
||||
visibility_scope: OUTERMOST_SOURCE_SCOPE,
|
||||
internal: false,
|
||||
is_block_tail: None,
|
||||
name: None, // FIXME maybe we do want some name here?
|
||||
local_info: LocalInfo::Other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A closure capture, with its name and mode.
|
||||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
|
||||
pub struct UpvarDebuginfo {
|
||||
pub debug_name: Name,
|
||||
/// Debug information pertaining to a user variable.
|
||||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
|
||||
pub struct VarDebugInfo<'tcx> {
|
||||
pub name: Name,
|
||||
|
||||
/// If true, the capture is behind a reference.
|
||||
pub by_ref: bool,
|
||||
/// 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: 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
|
||||
/// layout.
|
||||
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)]
|
||||
@ -2946,7 +2922,6 @@ CloneTypeFoldableAndLiftImpls! {
|
||||
MirPhase,
|
||||
Mutability,
|
||||
SourceInfo,
|
||||
UpvarDebuginfo,
|
||||
FakeReadCause,
|
||||
RetagKind,
|
||||
SourceScope,
|
||||
|
@ -221,6 +221,11 @@ macro_rules! make_mir_visitor {
|
||||
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,
|
||||
_local: & $($mutability)? Local,
|
||||
_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);
|
||||
}
|
||||
|
||||
@ -687,9 +696,7 @@ macro_rules! make_mir_visitor {
|
||||
mutability: _,
|
||||
ty,
|
||||
user_ty,
|
||||
name: _,
|
||||
source_info,
|
||||
visibility_scope,
|
||||
internal: _,
|
||||
local_info: _,
|
||||
is_block_tail: _,
|
||||
@ -703,7 +710,23 @@ macro_rules! make_mir_visitor {
|
||||
self.visit_user_type_projection(user_ty);
|
||||
}
|
||||
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,
|
||||
@ -1029,6 +1052,8 @@ pub enum NonUseContext {
|
||||
StorageDead,
|
||||
/// User type annotation assertions for NLL.
|
||||
AscribeUserTy,
|
||||
/// The data of an user variable, for debug info.
|
||||
VarDebugInfo,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -23,12 +23,10 @@ pub fn compute_mir_scopes(
|
||||
) {
|
||||
// Find all the scopes with variables defined in them.
|
||||
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,
|
||||
// irrespective of their name (assuming full debuginfo is enabled).
|
||||
for var in mir.vars_iter() {
|
||||
let decl = &mir.local_decls[var];
|
||||
has_variables.insert(decl.visibility_scope);
|
||||
for var_debug_info in &mir.var_debug_info {
|
||||
has_variables.insert(var_debug_info.source_info.scope);
|
||||
}
|
||||
|
||||
// Instantiate all scopes.
|
||||
|
@ -17,13 +17,13 @@ use crate::llvm_util;
|
||||
use crate::value::Value;
|
||||
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc::hir::CodegenFnAttrFlags;
|
||||
use rustc::hir::def::CtorKind;
|
||||
use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
|
||||
use rustc::ich::NodeIdHashingMode;
|
||||
use rustc::mir::Field;
|
||||
use rustc::mir::GeneratorLayout;
|
||||
use rustc::mir::{self, Field, GeneratorLayout};
|
||||
use rustc::mir::interpret::truncate;
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc::ty::Instance;
|
||||
@ -1316,6 +1316,45 @@ fn use_enum_fallback(cx: &CodegenCx<'_, '_>) -> bool {
|
||||
|| 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
|
||||
/// structs in DWARF. This `MemberDescriptionFactory` provides the description for
|
||||
/// 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> {
|
||||
fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>)
|
||||
-> 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| {
|
||||
match &self.enum_type.kind {
|
||||
match self.enum_type.kind {
|
||||
ty::Adt(adt, _) => VariantInfo::Adt(&adt.variants[index]),
|
||||
ty::Generator(def_id, substs, _) => {
|
||||
let generator_layout = cx.tcx.generator_layout(*def_id);
|
||||
VariantInfo::Generator(substs, generator_layout, index)
|
||||
ty::Generator(_, substs, _) => {
|
||||
let (generator_layout, generator_saved_local_names) =
|
||||
generator_variant_info_data.as_ref().unwrap();
|
||||
VariantInfo::Generator {
|
||||
substs,
|
||||
generator_layout: *generator_layout,
|
||||
generator_saved_local_names,
|
||||
variant_index: index,
|
||||
}
|
||||
}
|
||||
_ => bug!(),
|
||||
}
|
||||
@ -1608,16 +1660,21 @@ enum EnumDiscriminantInfo<'ll> {
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum VariantInfo<'tcx> {
|
||||
enum VariantInfo<'a, 'tcx> {
|
||||
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 {
|
||||
match self {
|
||||
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)),
|
||||
}
|
||||
}
|
||||
@ -1625,7 +1682,7 @@ impl<'tcx> VariantInfo<'tcx> {
|
||||
fn variant_name(&self) -> String {
|
||||
match self {
|
||||
VariantInfo::Adt(variant) => variant.ident.to_string(),
|
||||
VariantInfo::Generator(_, _, variant_index) => {
|
||||
VariantInfo::Generator { variant_index, .. } => {
|
||||
// Since GDB currently prints out the raw discriminant along
|
||||
// with every variant, make each variant name be just the value
|
||||
// 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 {
|
||||
let field_name = match self {
|
||||
let field_name = match *self {
|
||||
VariantInfo::Adt(variant) if variant.ctor_kind != CtorKind::Fn =>
|
||||
Some(variant.fields[i].ident.to_string()),
|
||||
VariantInfo::Generator(_, generator_layout, variant_index) => {
|
||||
let field = generator_layout.variant_fields[*variant_index][i.into()];
|
||||
let decl = &generator_layout.__local_debuginfo_codegen_only_do_not_use[field];
|
||||
decl.name.map(|name| name.to_string())
|
||||
}
|
||||
Some(variant.fields[i].ident.name),
|
||||
VariantInfo::Generator {
|
||||
generator_layout,
|
||||
generator_saved_local_names,
|
||||
variant_index,
|
||||
..
|
||||
} => generator_saved_local_names[
|
||||
generator_layout.variant_fields[variant_index][i.into()]
|
||||
],
|
||||
_ => 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(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
layout: layout::TyLayout<'tcx>,
|
||||
variant: VariantInfo<'tcx>,
|
||||
variant: VariantInfo<'_, 'tcx>,
|
||||
discriminant_info: EnumDiscriminantInfo<'ll>,
|
||||
containing_scope: &'ll DIScope,
|
||||
span: Span,
|
||||
|
@ -5,7 +5,9 @@ use rustc_index::bit_set::BitSet;
|
||||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
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::session::config::DebugInfo;
|
||||
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
|
||||
// of putting everything in allocas just so we can use llvm.dbg.declare.
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
@ -114,6 +116,12 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
||||
let cx = self.fx.cx;
|
||||
|
||||
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.
|
||||
let is_consume = match context {
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
|
||||
@ -145,47 +153,81 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
||||
// Recurse with the same context, instead of `Projection`,
|
||||
// potentially stopping at non-operand projections,
|
||||
// which would trigger `not_ssa` on locals.
|
||||
self.process_place(
|
||||
&mir::PlaceRef {
|
||||
base: place_ref.base,
|
||||
projection: proj_base,
|
||||
},
|
||||
context,
|
||||
location,
|
||||
);
|
||||
return;
|
||||
base_context = context;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A deref projection only reads the pointer, never needs the place.
|
||||
if let mir::ProjectionElem::Deref = elem {
|
||||
self.process_place(
|
||||
&mir::PlaceRef {
|
||||
base: place_ref.base,
|
||||
projection: proj_base,
|
||||
},
|
||||
// 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(
|
||||
&mir::PlaceRef {
|
||||
base: place_ref.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),
|
||||
location
|
||||
);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// FIXME this is super_place code, is repeated here to avoid cloning place or changing
|
||||
// visit_place API
|
||||
let mut context = context;
|
||||
|
||||
if !place_ref.projection.is_empty() {
|
||||
context = if context.is_mutating_use() {
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Projection)
|
||||
} else {
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
|
||||
};
|
||||
}
|
||||
|
||||
self.visit_place_base(place_ref.base, context, location);
|
||||
self.visit_projection(place_ref.base, place_ref.projection, context, location);
|
||||
}
|
||||
|
||||
// FIXME this is super_place code, is repeated here to avoid cloning place or changing
|
||||
// visit_place API
|
||||
let mut context = context;
|
||||
|
||||
if !place_ref.projection.is_empty() {
|
||||
context = if context.is_mutating_use() {
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Projection)
|
||||
} else {
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
|
||||
};
|
||||
}
|
||||
|
||||
self.visit_place_base(place_ref.base, 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);
|
||||
}
|
||||
|
||||
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::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::mir;
|
||||
use rustc::session::config::DebugInfo;
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::ty::layout::{LayoutOf, Size, VariantIdx};
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc::ty::layout::{LayoutOf, Size};
|
||||
use crate::traits::*;
|
||||
|
||||
use syntax_pos::{BytePos, Span, Symbol};
|
||||
use syntax_pos::{BytePos, Span};
|
||||
use syntax::symbol::kw;
|
||||
|
||||
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],
|
||||
None => return,
|
||||
};
|
||||
let whole_local_var = vars.iter().find(|var| {
|
||||
let whole_local_var = vars.iter().copied().find(|var| {
|
||||
var.place.projection.is_empty()
|
||||
});
|
||||
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?
|
||||
None
|
||||
} else {
|
||||
Some(VarDebugInfo {
|
||||
Some(mir::VarDebugInfo {
|
||||
name: kw::Invalid,
|
||||
source_info: self.mir.local_decls[local].source_info,
|
||||
place: local.into(),
|
||||
@ -185,7 +185,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
_ => 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()
|
||||
} else {
|
||||
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(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &mir::Body<'tcx>,
|
||||
) -> Option<IndexVec<mir::Local, Vec<VarDebugInfo<'tcx>>>> {
|
||||
body: &'a mir::Body<'tcx>,
|
||||
) -> Option<IndexVec<mir::Local, Vec<&'a mir::VarDebugInfo<'tcx>>>> {
|
||||
if tcx.sess.opts.debuginfo == DebugInfo::Full || !tcx.sess.fewer_names() {
|
||||
let mut per_local = IndexVec::from_elem(vec![], &body.local_decls);
|
||||
for (local, decl) in body.local_decls.iter_enumerated() {
|
||||
if let Some(name) = decl.name {
|
||||
per_local[local].push(VarDebugInfo {
|
||||
name,
|
||||
source_info: mir::SourceInfo {
|
||||
span: decl.source_info.span,
|
||||
scope: decl.visibility_scope,
|
||||
},
|
||||
place: local.into(),
|
||||
});
|
||||
for var in &body.var_debug_info {
|
||||
if let mir::PlaceBase::Local(local) = var.place.base {
|
||||
per_local[local].push(var);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
} else {
|
||||
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`.
|
||||
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> {
|
||||
|
@ -308,7 +308,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
location,
|
||||
borrow,
|
||||
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);
|
||||
}
|
||||
|
||||
@ -343,7 +350,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
});
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@ -561,6 +575,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
explanation.add_explanation_to_diagnostic(
|
||||
self.infcx.tcx,
|
||||
self.body,
|
||||
&self.local_names,
|
||||
&mut err,
|
||||
first_borrow_desc,
|
||||
None,
|
||||
@ -947,6 +962,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
explanation.add_explanation_to_diagnostic(
|
||||
self.infcx.tcx,
|
||||
self.body,
|
||||
&self.local_names,
|
||||
&mut err,
|
||||
"",
|
||||
None,
|
||||
@ -971,7 +987,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
);
|
||||
|
||||
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
|
||||
@ -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);
|
||||
}
|
||||
@ -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() {
|
||||
" by generator"
|
||||
@ -1478,7 +1508,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
);
|
||||
|
||||
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);
|
||||
}
|
||||
@ -1496,14 +1533,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
assigned_span: Span,
|
||||
err_place: &Place<'tcx>,
|
||||
) {
|
||||
let (from_arg, local_decl) = if let Some(local) = err_place.as_local() {
|
||||
if let LocalKind::Arg = self.body.local_kind(local) {
|
||||
(true, Some(&self.body.local_decls[local]))
|
||||
} else {
|
||||
(false, Some(&self.body.local_decls[local]))
|
||||
}
|
||||
} else {
|
||||
(false, None)
|
||||
let (from_arg, local_decl, local_name) = match err_place.as_local() {
|
||||
Some(local) => (
|
||||
self.body.local_kind(local) == LocalKind::Arg,
|
||||
Some(&self.body.local_decls[local]),
|
||||
self.local_names[local],
|
||||
),
|
||||
None => (false, None, None),
|
||||
};
|
||||
|
||||
// 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(name) = decl.name {
|
||||
if let Some(name) = local_name {
|
||||
if decl.can_be_made_mutable() {
|
||||
err.span_suggestion(
|
||||
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
|
||||
/// 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<(), ()> {
|
||||
let local = &self.body.local_decls[local_index];
|
||||
match local.name {
|
||||
Some(name) if !local.from_compiler_desugaring() => {
|
||||
fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> {
|
||||
let decl = &self.body.local_decls[local];
|
||||
match self.local_names[local] {
|
||||
Some(name) if !decl.from_compiler_desugaring() => {
|
||||
buf.push_str(&name.as_str());
|
||||
Ok(())
|
||||
}
|
||||
|
@ -115,6 +115,20 @@ fn do_mir_borrowck<'a, 'tcx>(
|
||||
.as_local_hir_id(def_id)
|
||||
.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.
|
||||
let tables = tcx.typeck_tables_of(def_id);
|
||||
let upvars: Vec<_> = tables
|
||||
@ -189,6 +203,7 @@ fn do_mir_borrowck<'a, 'tcx>(
|
||||
free_regions,
|
||||
body,
|
||||
&promoted,
|
||||
&local_names,
|
||||
&upvars,
|
||||
location_table,
|
||||
param_env,
|
||||
@ -264,6 +279,7 @@ fn do_mir_borrowck<'a, 'tcx>(
|
||||
borrow_set,
|
||||
dominators,
|
||||
upvars,
|
||||
local_names,
|
||||
};
|
||||
|
||||
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 {
|
||||
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
|
||||
match local_decl.name {
|
||||
match mbcx.local_names[local] {
|
||||
Some(name) => if name.as_str().starts_with("_") {
|
||||
continue;
|
||||
},
|
||||
@ -463,6 +474,9 @@ crate struct MirBorrowckCtxt<'cx, 'tcx> {
|
||||
|
||||
/// Information about upvars not necessarily preserved in types or MIR
|
||||
upvars: Vec<Upvar>,
|
||||
|
||||
/// Names of local (user) variables (extracted from `var_debug_info`).
|
||||
local_names: IndexVec<Local, Option<Name>>,
|
||||
}
|
||||
|
||||
// Check that:
|
||||
|
@ -322,7 +322,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
if decl.is_ref_for_guard() {
|
||||
let mut err = self.cannot_move_out_of(
|
||||
span,
|
||||
&format!("`{}` in pattern guard", decl.name.unwrap()),
|
||||
&format!("`{}` in pattern guard", self.local_names[*local].unwrap()),
|
||||
);
|
||||
err.note(
|
||||
"variables bound in patterns cannot be moved from \
|
||||
@ -571,7 +571,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
if binds_to.len() == 1 {
|
||||
self.note_type_does_not_implement_copy(
|
||||
err,
|
||||
&format!("`{}`", bind_to.name.unwrap()),
|
||||
&format!("`{}`", self.local_names[*local].unwrap()),
|
||||
bind_to.ty,
|
||||
Some(binding_span)
|
||||
);
|
||||
|
@ -50,8 +50,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
if access_place.as_local().is_some() {
|
||||
reason = ", as it is not declared as mutable".to_string();
|
||||
} else {
|
||||
let name = self.body.local_decls[*local]
|
||||
.name
|
||||
let name = self.local_names[*local]
|
||||
.expect("immutable unnamed local");
|
||||
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,
|
||||
// so that we don't fall in to the next case with them.
|
||||
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
|
||||
// we have an explicit self. Do the same thing in this case and check
|
||||
// for a `self: &mut Self` to suggest removing the `&mut`.
|
||||
@ -290,7 +289,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
err.span_suggestion(
|
||||
local_decl.source_info.span,
|
||||
"consider changing this to be mutable",
|
||||
format!("mut {}", local_decl.name.unwrap()),
|
||||
format!("mut {}", self.local_names[*local].unwrap()),
|
||||
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() => {
|
||||
err.span_label(
|
||||
span,
|
||||
|
@ -11,9 +11,11 @@ use rustc::mir::{
|
||||
};
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::ty::adjustment::{PointerCast};
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
use syntax_pos::Span;
|
||||
use syntax_pos::symbol::Symbol;
|
||||
|
||||
mod find_use;
|
||||
|
||||
@ -56,6 +58,7 @@ impl BorrowExplanation {
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
borrow_desc: &str,
|
||||
borrow_span: Option<Span>,
|
||||
@ -112,7 +115,7 @@ impl BorrowExplanation {
|
||||
_ => ("destructor", format!("type `{}`", local_decl.ty)),
|
||||
};
|
||||
|
||||
match local_decl.name {
|
||||
match local_names[dropped_local] {
|
||||
Some(local_name) if !local_decl.from_compiler_desugaring() => {
|
||||
let message = format!(
|
||||
"{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)) => {
|
||||
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(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
|
||||
{
|
||||
should_note_order = true;
|
||||
@ -295,6 +298,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
let (category, from_closure, span, region_name) =
|
||||
self.nonlexical_regioncx.free_region_constraint_info(
|
||||
self.body,
|
||||
&self.local_names,
|
||||
&self.upvars,
|
||||
self.mir_def_id,
|
||||
self.infcx,
|
||||
@ -495,7 +499,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
Operand::Move(place) => {
|
||||
if let Some(l) = place.as_local() {
|
||||
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
|
||||
} else {
|
||||
span
|
||||
|
@ -16,6 +16,7 @@ use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements,
|
||||
use rustc::ty::{self, RegionKind, RegionVid};
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_errors::Diagnostic;
|
||||
use syntax_pos::symbol::Symbol;
|
||||
use std::fmt::Debug;
|
||||
use std::env;
|
||||
use std::io;
|
||||
@ -158,6 +159,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
|
||||
universal_regions: UniversalRegions<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
promoted: &IndexVec<Promoted, Body<'tcx>>,
|
||||
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||
upvars: &[Upvar],
|
||||
location_table: &LocationTable,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
@ -281,7 +283,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
|
||||
|
||||
// Solve the region constraints.
|
||||
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
|
||||
// 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::InferCtxt;
|
||||
use rustc::infer::NLLRegionVariableOrigin;
|
||||
use rustc::mir::{ConstraintCategory, Location, Body};
|
||||
use rustc::mir::{ConstraintCategory, Local, Location, Body};
|
||||
use rustc::ty::{self, RegionVid};
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
@ -17,6 +17,7 @@ use std::collections::VecDeque;
|
||||
use syntax::errors::Applicability;
|
||||
use syntax::symbol::kw;
|
||||
use syntax_pos::Span;
|
||||
use syntax_pos::symbol::Symbol;
|
||||
|
||||
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).
|
||||
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.
|
||||
upvars: &'b [Upvar],
|
||||
}
|
||||
@ -367,13 +371,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
pub(super) fn report_error<'a>(
|
||||
&'a self,
|
||||
body: &Body<'tcx>,
|
||||
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||
upvars: &[Upvar],
|
||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||
mir_def_id: DefId,
|
||||
fr: RegionVid,
|
||||
fr_origin: NLLRegionVariableOrigin,
|
||||
outlived_fr: RegionVid,
|
||||
outlives_suggestion: &mut OutlivesSuggestionBuilder,
|
||||
outlives_suggestion: &mut OutlivesSuggestionBuilder<'_>,
|
||||
renctx: &mut RegionErrorNamingCtx,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
|
||||
@ -407,6 +412,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
infcx,
|
||||
mir_def_id,
|
||||
body,
|
||||
local_names,
|
||||
upvars,
|
||||
};
|
||||
|
||||
@ -551,7 +557,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
renctx: &mut RegionErrorNamingCtx,
|
||||
) -> DiagnosticBuilder<'_> {
|
||||
let ErrorReportingCtx {
|
||||
infcx, body, upvars, ..
|
||||
infcx, body, upvars, local_names, ..
|
||||
} = errctx;
|
||||
|
||||
let ErrorConstraintInfo {
|
||||
@ -559,9 +565,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
} = errci;
|
||||
|
||||
let fr_name_and_span =
|
||||
self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, errci.fr);
|
||||
let outlived_fr_name_and_span =
|
||||
self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, errci.outlived_fr);
|
||||
self.get_var_name_and_span_for_region(infcx.tcx, body, local_names, upvars, errci.fr);
|
||||
let outlived_fr_name_and_span = self.get_var_name_and_span_for_region(
|
||||
infcx.tcx,
|
||||
body,
|
||||
local_names,
|
||||
upvars,
|
||||
errci.outlived_fr,
|
||||
);
|
||||
|
||||
let escapes_from = match self.universal_regions.defining_ty {
|
||||
DefiningTy::Closure(..) => "closure",
|
||||
@ -789,6 +800,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
crate fn free_region_constraint_info(
|
||||
&self,
|
||||
body: &Body<'tcx>,
|
||||
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||
upvars: &[Upvar],
|
||||
mir_def_id: DefId,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
@ -804,7 +816,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
|
||||
let mut renctx = RegionErrorNamingCtx::new();
|
||||
let errctx = ErrorReportingCtx {
|
||||
infcx, body, upvars, mir_def_id,
|
||||
infcx, body, local_names, upvars, mir_def_id,
|
||||
region_infcx: self,
|
||||
};
|
||||
let outlived_fr_name = self.give_region_a_name(&errctx, &mut renctx, outlived_region);
|
||||
|
@ -4,9 +4,12 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
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_errors::{Diagnostic, DiagnosticBuilder};
|
||||
use rustc_index::vec::IndexVec;
|
||||
use syntax_pos::symbol::Symbol;
|
||||
|
||||
use smallvec::SmallVec;
|
||||
|
||||
@ -34,10 +37,12 @@ enum SuggestedConstraint {
|
||||
/// corresponding to a function definition.
|
||||
///
|
||||
/// 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.
|
||||
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
|
||||
/// 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
|
||||
@ -46,10 +51,17 @@ pub struct OutlivesSuggestionBuilder {
|
||||
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.
|
||||
crate fn new(mir_def_id: DefId) -> Self {
|
||||
OutlivesSuggestionBuilder { mir_def_id, constraints_to_add: BTreeMap::default() }
|
||||
crate fn new(
|
||||
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
|
||||
@ -125,6 +137,7 @@ impl OutlivesSuggestionBuilder {
|
||||
infcx,
|
||||
body,
|
||||
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
|
||||
// should never be used.
|
||||
|
@ -11,10 +11,11 @@ use rustc::hir;
|
||||
use rustc::hir::def::{Res, DefKind};
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::infer::InferCtxt;
|
||||
use rustc::mir::Body;
|
||||
use rustc::mir::{Local, Body};
|
||||
use rustc::ty::subst::{SubstsRef, GenericArgKind};
|
||||
use rustc::ty::{self, RegionKind, RegionVid, Ty, TyCtxt};
|
||||
use rustc::ty::print::RegionHighlightMode;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
use syntax::symbol::kw;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
@ -210,7 +211,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
fr: RegionVid,
|
||||
) -> Option<RegionName> {
|
||||
let ErrorReportingCtx {
|
||||
infcx, body, mir_def_id, upvars, ..
|
||||
infcx, body, mir_def_id, local_names, upvars, ..
|
||||
} = errctx;
|
||||
|
||||
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)
|
||||
.or_else(|| {
|
||||
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(|| {
|
||||
@ -395,6 +396,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
&self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||
mir_def_id: DefId,
|
||||
fr: RegionVid,
|
||||
renctx: &mut RegionErrorNamingCtx,
|
||||
@ -415,7 +417,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
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(
|
||||
@ -463,6 +465,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
&self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||
needle_fr: RegionVid,
|
||||
argument_ty: Ty<'tcx>,
|
||||
renctx: &mut RegionErrorNamingCtx,
|
||||
@ -479,7 +482,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
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.
|
||||
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 {
|
||||
// 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 rustc::mir::{Local, Body};
|
||||
use rustc::ty::{RegionVid, TyCtxt};
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use syntax::source_map::Span;
|
||||
use syntax_pos::symbol::Symbol;
|
||||
|
||||
@ -12,6 +12,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||
upvars: &[Upvar],
|
||||
fr: RegionVid,
|
||||
) -> Option<(Option<Symbol>, Span)> {
|
||||
@ -27,8 +28,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
})
|
||||
.or_else(|| {
|
||||
debug!("get_var_name_and_span_for_region: attempting argument");
|
||||
self.get_argument_index_for_region(tcx, fr)
|
||||
.map(|index| self.get_argument_name_and_span_for_region(body, index))
|
||||
self.get_argument_index_for_region(tcx, fr).map(|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(
|
||||
&self,
|
||||
body: &Body<'tcx>,
|
||||
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||
argument_index: usize,
|
||||
) -> (Option<Symbol>, Span) {
|
||||
let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
|
||||
let argument_local = Local::new(implicit_inputs + argument_index + 1);
|
||||
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;
|
||||
debug!("get_argument_name_and_span_for_region: 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_errors::{Diagnostic, DiagnosticBuilder};
|
||||
use syntax_pos::Span;
|
||||
use syntax_pos::symbol::Symbol;
|
||||
|
||||
crate use self::error_reporting::{RegionName, RegionNameSource, RegionErrorNamingCtx};
|
||||
use self::values::{LivenessValues, RegionValueElements, RegionValues};
|
||||
@ -471,6 +472,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
&mut self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||
upvars: &[Upvar],
|
||||
mir_def_id: DefId,
|
||||
errors_buffer: &mut Vec<Diagnostic>,
|
||||
@ -502,6 +504,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
self.check_universal_regions(
|
||||
infcx,
|
||||
body,
|
||||
local_names,
|
||||
upvars,
|
||||
mir_def_id,
|
||||
outlives_requirements.as_mut(),
|
||||
@ -1321,13 +1324,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
&self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||
upvars: &[Upvar],
|
||||
mir_def_id: DefId,
|
||||
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
|
||||
errors_buffer: &mut Vec<Diagnostic>,
|
||||
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() {
|
||||
match fr_definition.origin {
|
||||
@ -1338,6 +1342,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
self.check_universal_region(
|
||||
infcx,
|
||||
body,
|
||||
local_names,
|
||||
upvars,
|
||||
mir_def_id,
|
||||
fr,
|
||||
@ -1374,11 +1379,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
&self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||
upvars: &[Upvar],
|
||||
mir_def_id: DefId,
|
||||
longer_fr: RegionVid,
|
||||
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
|
||||
outlives_suggestion: &mut OutlivesSuggestionBuilder,
|
||||
outlives_suggestion: &mut OutlivesSuggestionBuilder<'_>,
|
||||
errors_buffer: &mut Vec<Diagnostic>,
|
||||
region_naming: &mut RegionErrorNamingCtx,
|
||||
) {
|
||||
@ -1404,6 +1410,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
representative,
|
||||
infcx,
|
||||
body,
|
||||
local_names,
|
||||
upvars,
|
||||
mir_def_id,
|
||||
propagated_outlives_requirements,
|
||||
@ -1422,6 +1429,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
shorter_fr,
|
||||
infcx,
|
||||
body,
|
||||
local_names,
|
||||
upvars,
|
||||
mir_def_id,
|
||||
propagated_outlives_requirements,
|
||||
@ -1445,10 +1453,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
shorter_fr: RegionVid,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||
upvars: &[Upvar],
|
||||
mir_def_id: DefId,
|
||||
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
|
||||
outlives_suggestion: &mut OutlivesSuggestionBuilder,
|
||||
outlives_suggestion: &mut OutlivesSuggestionBuilder<'_>,
|
||||
errors_buffer: &mut Vec<Diagnostic>,
|
||||
region_naming: &mut RegionErrorNamingCtx,
|
||||
) -> Option<ErrorReported> {
|
||||
@ -1502,6 +1511,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
// error. This gives better error messages in some cases.
|
||||
let db = self.report_error(
|
||||
body,
|
||||
local_names,
|
||||
upvars,
|
||||
infcx,
|
||||
mir_def_id,
|
||||
|
@ -227,9 +227,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
mutability: Mutability::Mut,
|
||||
ty: ptr_ty,
|
||||
user_ty: UserTypeProjections::none(),
|
||||
name: None,
|
||||
source_info,
|
||||
visibility_scope: source_info.scope,
|
||||
internal: true,
|
||||
local_info: LocalInfo::Other,
|
||||
is_block_tail: None,
|
||||
|
@ -1721,6 +1721,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
);
|
||||
|
||||
let tcx = self.hir.tcx();
|
||||
let debug_source_info = SourceInfo {
|
||||
span: source_info.span,
|
||||
scope: visibility_scope,
|
||||
};
|
||||
let binding_mode = match mode {
|
||||
BindingMode::ByValue => ty::BindingMode::BindByValue(mutability.into()),
|
||||
BindingMode::ByRef(_) => ty::BindingMode::BindByReference(mutability.into()),
|
||||
@ -1730,9 +1734,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
mutability,
|
||||
ty: var_ty,
|
||||
user_ty,
|
||||
name: Some(name),
|
||||
source_info,
|
||||
visibility_scope,
|
||||
internal: false,
|
||||
is_block_tail: None,
|
||||
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);
|
||||
self.var_debug_info.push(VarDebugInfo {
|
||||
name,
|
||||
source_info: debug_source_info,
|
||||
place: for_arm_body.into(),
|
||||
});
|
||||
let locals = if has_guard.0 {
|
||||
let ref_for_guard = self.local_decls.push(LocalDecl::<'tcx> {
|
||||
// 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,
|
||||
ty: tcx.mk_imm_ref(tcx.lifetimes.re_erased, var_ty),
|
||||
user_ty: UserTypeProjections::none(),
|
||||
name: Some(name),
|
||||
source_info,
|
||||
visibility_scope,
|
||||
internal: false,
|
||||
is_block_tail: None,
|
||||
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 {
|
||||
ref_for_guard,
|
||||
for_arm_body,
|
||||
|
@ -161,8 +161,18 @@ pub fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> Body<'_> {
|
||||
(None, fn_sig.output())
|
||||
};
|
||||
|
||||
build::construct_fn(cx, id, arguments, safety, abi,
|
||||
return_ty, yield_ty, return_ty_span, body)
|
||||
let mut mir = build::construct_fn(
|
||||
cx,
|
||||
id,
|
||||
arguments,
|
||||
safety,
|
||||
abi,
|
||||
return_ty,
|
||||
return_ty_span,
|
||||
body,
|
||||
);
|
||||
mir.yield_ty = yield_ty;
|
||||
mir
|
||||
} else {
|
||||
// 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
|
||||
@ -312,10 +322,11 @@ struct Builder<'a, 'tcx> {
|
||||
var_indices: HirIdMap<LocalsForNode>,
|
||||
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
|
||||
canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>,
|
||||
__upvar_debuginfo_codegen_only_do_not_use: Vec<UpvarDebuginfo>,
|
||||
upvar_mutbls: Vec<Mutability>,
|
||||
unit_temp: Option<Place<'tcx>>,
|
||||
|
||||
var_debug_info: Vec<VarDebugInfo<'tcx>>,
|
||||
|
||||
/// Cached block with the `RESUME` terminator; this is created
|
||||
/// when first set of cleanups are built.
|
||||
cached_resume_block: Option<BasicBlock>,
|
||||
@ -539,7 +550,6 @@ fn construct_fn<'a, 'tcx, A>(
|
||||
safety: Safety,
|
||||
abi: Abi,
|
||||
return_ty: Ty<'tcx>,
|
||||
yield_ty: Option<Ty<'tcx>>,
|
||||
return_ty_span: Span,
|
||||
body: &'tcx hir::Body,
|
||||
) -> Body<'tcx>
|
||||
@ -552,58 +562,14 @@ where
|
||||
let tcx_hir = tcx.hir();
|
||||
let span = tcx_hir.span(fn_id);
|
||||
|
||||
let hir_tables = hir.tables();
|
||||
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,
|
||||
span,
|
||||
arguments.len(),
|
||||
safety,
|
||||
return_ty,
|
||||
return_ty_span,
|
||||
upvar_debuginfo,
|
||||
upvar_mutbls,
|
||||
body.generator_kind.is_some());
|
||||
|
||||
let call_site_scope = region::Scope {
|
||||
@ -631,7 +597,7 @@ where
|
||||
Place::return_place(),
|
||||
|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,
|
||||
tcx.get_attrs(fn_def_id));
|
||||
|
||||
let mut body = builder.finish(yield_ty);
|
||||
let mut body = builder.finish();
|
||||
body.spread_arg = spread_arg;
|
||||
body
|
||||
}
|
||||
@ -681,8 +647,6 @@ fn construct_const<'a, 'tcx>(
|
||||
Safety::Safe,
|
||||
const_ty,
|
||||
const_ty_span,
|
||||
vec![],
|
||||
vec![],
|
||||
false,
|
||||
);
|
||||
|
||||
@ -704,7 +668,7 @@ fn construct_const<'a, 'tcx>(
|
||||
TerminatorKind::Unreachable);
|
||||
}
|
||||
|
||||
builder.finish(None)
|
||||
builder.finish()
|
||||
}
|
||||
|
||||
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 span = hir.tcx().hir().span(owner_id);
|
||||
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);
|
||||
builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
|
||||
builder.finish(None)
|
||||
builder.finish()
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
@ -727,8 +691,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
safety: Safety,
|
||||
return_ty: Ty<'tcx>,
|
||||
return_span: Span,
|
||||
__upvar_debuginfo_codegen_only_do_not_use: Vec<UpvarDebuginfo>,
|
||||
upvar_mutbls: Vec<Mutability>,
|
||||
is_generator: bool)
|
||||
-> Builder<'a, 'tcx> {
|
||||
let lint_level = LintLevel::Explicit(hir.root_lint_level);
|
||||
@ -751,10 +713,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
1,
|
||||
),
|
||||
canonical_user_type_annotations: IndexVec::new(),
|
||||
__upvar_debuginfo_codegen_only_do_not_use,
|
||||
upvar_mutbls,
|
||||
upvar_mutbls: vec![],
|
||||
var_indices: Default::default(),
|
||||
unit_temp: None,
|
||||
var_debug_info: vec![],
|
||||
cached_resume_block: None,
|
||||
cached_return_block: None,
|
||||
cached_unreachable_block: None,
|
||||
@ -769,9 +731,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
builder
|
||||
}
|
||||
|
||||
fn finish(self,
|
||||
yield_ty: Option<Ty<'tcx>>)
|
||||
-> Body<'tcx> {
|
||||
fn finish(self) -> Body<'tcx> {
|
||||
for (index, block) in self.cfg.basic_blocks.iter().enumerate() {
|
||||
if block.terminator.is_none() {
|
||||
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.source_scopes,
|
||||
ClearCrossCrate::Set(self.source_scope_local_data),
|
||||
yield_ty,
|
||||
self.local_decls,
|
||||
self.canonical_user_type_annotations,
|
||||
self.arg_count,
|
||||
self.__upvar_debuginfo_codegen_only_do_not_use,
|
||||
self.var_debug_info,
|
||||
self.fn_span,
|
||||
self.hir.control_flow_destroyed(),
|
||||
)
|
||||
@ -794,6 +753,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
|
||||
fn args_and_body(&mut self,
|
||||
mut block: BasicBlock,
|
||||
fn_def_id: DefId,
|
||||
arguments: &[ArgInfo<'tcx>],
|
||||
argument_scope: region::Scope,
|
||||
ast_body: &'tcx hir::Expr)
|
||||
@ -801,28 +761,100 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
{
|
||||
// Allocate locals for the function arguments
|
||||
for &ArgInfo(ty, _, arg_opt, _) in arguments.iter() {
|
||||
// If this is a simple binding pattern, give the local a name for
|
||||
// debuginfo and so that error reporting knows that this is a user
|
||||
// variable. For any other pattern the pattern introduces new
|
||||
// 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 source_info = SourceInfo {
|
||||
scope: OUTERMOST_SOURCE_SCOPE,
|
||||
span: arg_opt.map_or(self.fn_span, |arg| arg.pat.span)
|
||||
};
|
||||
|
||||
let source_info = SourceInfo { scope: OUTERMOST_SOURCE_SCOPE, span, };
|
||||
self.local_decls.push(LocalDecl {
|
||||
let arg_local = self.local_decls.push(LocalDecl {
|
||||
mutability: Mutability::Mut,
|
||||
ty,
|
||||
user_ty: UserTypeProjections::none(),
|
||||
source_info,
|
||||
visibility_scope: source_info.scope,
|
||||
name,
|
||||
internal: false,
|
||||
local_info: LocalInfo::Other,
|
||||
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;
|
||||
|
@ -148,9 +148,7 @@ fn temp_decl(mutability: Mutability, ty: Ty<'_>, span: Span) -> LocalDecl<'_> {
|
||||
mutability,
|
||||
ty,
|
||||
user_ty: UserTypeProjections::none(),
|
||||
name: None,
|
||||
source_info,
|
||||
visibility_scope: source_info.scope,
|
||||
internal: false,
|
||||
local_info: LocalInfo::Other,
|
||||
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
|
||||
),
|
||||
ClearCrossCrate::Clear,
|
||||
None,
|
||||
local_decls_for_sig(&sig, span),
|
||||
IndexVec::new(),
|
||||
sig.inputs().len(),
|
||||
@ -371,7 +368,6 @@ impl CloneShimBuilder<'tcx> {
|
||||
SourceScopeData { span: self.span, parent_scope: None }, 1
|
||||
),
|
||||
ClearCrossCrate::Clear,
|
||||
None,
|
||||
self.local_decls,
|
||||
IndexVec::new(),
|
||||
self.sig.inputs().len(),
|
||||
@ -832,7 +828,6 @@ fn build_call_shim<'tcx>(
|
||||
SourceScopeData { span: span, parent_scope: None }, 1
|
||||
),
|
||||
ClearCrossCrate::Clear,
|
||||
None,
|
||||
local_decls,
|
||||
IndexVec::new(),
|
||||
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
|
||||
),
|
||||
ClearCrossCrate::Clear,
|
||||
None,
|
||||
local_decls,
|
||||
IndexVec::new(),
|
||||
sig.inputs().len(),
|
||||
|
@ -85,7 +85,6 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
|
||||
body.basic_blocks().clone(),
|
||||
Default::default(),
|
||||
ClearCrossCrate::Clear,
|
||||
None,
|
||||
body.local_decls.clone(),
|
||||
Default::default(),
|
||||
body.arg_count,
|
||||
|
@ -62,7 +62,6 @@ use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_index::bit_set::{BitSet, BitMatrix};
|
||||
use std::borrow::Cow;
|
||||
use std::iter;
|
||||
use std::mem;
|
||||
use crate::transform::{MirPass, MirSource};
|
||||
use crate::transform::simplify;
|
||||
use crate::transform::no_landing_pads::no_landing_pads;
|
||||
@ -427,9 +426,7 @@ fn replace_result_variable<'tcx>(
|
||||
mutability: Mutability::Mut,
|
||||
ty: ret_ty,
|
||||
user_ty: UserTypeProjections::none(),
|
||||
name: None,
|
||||
source_info,
|
||||
visibility_scope: source_info.scope,
|
||||
internal: false,
|
||||
is_block_tail: None,
|
||||
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 locals and their indices replacing values in body.local_decls
|
||||
// with a dummy to avoid changing local indices.
|
||||
// Gather live local types and their indices.
|
||||
let mut locals = IndexVec::<GeneratorSavedLocal, _>::new();
|
||||
let mut tys = IndexVec::<GeneratorSavedLocal, _>::new();
|
||||
let mut decls = IndexVec::<GeneratorSavedLocal, _>::new();
|
||||
for (idx, local) in live_locals.iter().enumerate() {
|
||||
let var = mem::replace(&mut body.local_decls[local], dummy_local.clone());
|
||||
locals.push(local);
|
||||
tys.push(var.ty);
|
||||
decls.push(var);
|
||||
tys.push(body.local_decls[local].ty);
|
||||
debug!("generator saved local {:?} => {:?}", GeneratorSavedLocal::from(idx), local);
|
||||
}
|
||||
|
||||
@ -831,7 +822,6 @@ fn compute_layout<'tcx>(
|
||||
field_tys: tys,
|
||||
variant_fields,
|
||||
storage_conflicts,
|
||||
__local_debuginfo_codegen_only_do_not_use: decls,
|
||||
};
|
||||
|
||||
(remap, layout, storage_liveness)
|
||||
@ -962,9 +952,7 @@ fn create_generator_drop_shim<'tcx>(
|
||||
mutability: Mutability::Mut,
|
||||
ty: tcx.mk_unit(),
|
||||
user_ty: UserTypeProjections::none(),
|
||||
name: None,
|
||||
source_info,
|
||||
visibility_scope: source_info.scope,
|
||||
internal: false,
|
||||
is_block_tail: None,
|
||||
local_info: LocalInfo::Other
|
||||
@ -980,9 +968,7 @@ fn create_generator_drop_shim<'tcx>(
|
||||
mutbl: hir::Mutability::Mutable,
|
||||
}),
|
||||
user_ty: UserTypeProjections::none(),
|
||||
name: None,
|
||||
source_info,
|
||||
visibility_scope: source_info.scope,
|
||||
internal: false,
|
||||
is_block_tail: None,
|
||||
local_info: LocalInfo::Other
|
||||
|
@ -219,13 +219,6 @@ impl Inliner<'tcx> {
|
||||
debug!("should_inline({:?})", callsite);
|
||||
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
|
||||
if callee_body.yield_ty.is_some() {
|
||||
debug!(" yield ty present - not inlining");
|
||||
@ -413,7 +406,6 @@ impl Inliner<'tcx> {
|
||||
local.source_info.scope =
|
||||
scope_map[local.source_info.scope];
|
||||
local.source_info.span = callsite.location.span;
|
||||
local.visibility_scope = scope_map[local.visibility_scope];
|
||||
|
||||
let idx = caller_body.local_decls.push(local);
|
||||
local_map.push(idx);
|
||||
@ -484,6 +476,10 @@ impl Inliner<'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(..) {
|
||||
integrator.visit_basic_block_data(bb, &mut block);
|
||||
|
@ -1098,7 +1098,6 @@ pub fn promote_candidates<'tcx>(
|
||||
// memory usage?
|
||||
body.source_scopes.clone(),
|
||||
body.source_scope_local_data.clone(),
|
||||
None,
|
||||
initial_locals,
|
||||
IndexVec::new(),
|
||||
0,
|
||||
|
@ -32,7 +32,6 @@ use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc::mir::*;
|
||||
use rustc::mir::visit::{MutVisitor, Visitor, PlaceContext, MutatingUseContext};
|
||||
use rustc::session::config::DebugInfo;
|
||||
use std::borrow::Cow;
|
||||
use crate::transform::{MirPass, MirSource};
|
||||
|
||||
@ -307,13 +306,6 @@ impl<'tcx> MirPass<'tcx> for SimplifyLocals {
|
||||
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
|
||||
};
|
||||
|
||||
|
@ -362,6 +362,7 @@ impl<'tcx> Visitor<'tcx> for RestoreDataCollector {
|
||||
match context {
|
||||
PlaceContext::NonUse(NonUseContext::StorageLive) => local_use.alive = Some(location),
|
||||
PlaceContext::NonUse(NonUseContext::StorageDead) => local_use.dead = Some(location),
|
||||
PlaceContext::NonUse(NonUseContext::VarDebugInfo) => {}
|
||||
_ => {
|
||||
local_use.use_count += 1;
|
||||
if local_use.first_use.is_none() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! 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::ty::TyCtxt;
|
||||
use rustc_index::vec::IndexVec;
|
||||
@ -12,7 +12,9 @@ pub struct DefUseAnalysis {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Info {
|
||||
// FIXME(eddyb) use smallvec where possible.
|
||||
pub defs_and_uses: Vec<Use>,
|
||||
var_debug_info_indices: Vec<usize>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -33,6 +35,8 @@ impl DefUseAnalysis {
|
||||
|
||||
let mut finder = DefUseFinder {
|
||||
info: mem::take(&mut self.info),
|
||||
var_debug_info_index: 0,
|
||||
in_var_debug_info: false,
|
||||
};
|
||||
finder.visit_body(body);
|
||||
self.info = finder.info
|
||||
@ -55,9 +59,14 @@ impl DefUseAnalysis {
|
||||
new_local: Local,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) {
|
||||
for place_use in &self.info[local].defs_and_uses {
|
||||
MutateUseVisitor::new(local, new_local, body, tcx)
|
||||
.visit_location(body, place_use.location)
|
||||
let mut visitor = MutateUseVisitor::new(local, new_local, body, tcx);
|
||||
let info = &self.info[local];
|
||||
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 {
|
||||
info: IndexVec<Local, Info>,
|
||||
var_debug_info_index: usize,
|
||||
in_var_debug_info: bool,
|
||||
}
|
||||
|
||||
impl Visitor<'_> for DefUseFinder {
|
||||
@ -80,10 +91,22 @@ impl Visitor<'_> for DefUseFinder {
|
||||
&local: &Local,
|
||||
context: PlaceContext,
|
||||
location: Location) {
|
||||
self.info[local].defs_and_uses.push(Use {
|
||||
context,
|
||||
location,
|
||||
});
|
||||
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,
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,11 +114,13 @@ impl Info {
|
||||
fn new() -> Info {
|
||||
Info {
|
||||
defs_and_uses: vec![],
|
||||
var_debug_info_indices: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.defs_and_uses.clear();
|
||||
self.var_debug_info_indices.clear();
|
||||
}
|
||||
|
||||
pub fn def_count(&self) -> usize {
|
||||
|
@ -197,13 +197,13 @@ fn write_graph_label<'tcx, W: Write>(
|
||||
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"/>"#,
|
||||
Place::from(local), escape(&decl.ty))?;
|
||||
}
|
||||
write!(w, r#"{:?}: {};<br align="left"/>"#,
|
||||
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, ">;")
|
||||
|
@ -183,6 +183,9 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
|
||||
|
||||
PlaceContext::MutatingUse(MutatingUseContext::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<()> {
|
||||
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).
|
||||
for (local, local_decl) in body.local_decls.iter_enumerated() {
|
||||
if (1..body.arg_count+1).contains(&local.index()) {
|
||||
@ -496,8 +520,6 @@ fn write_scope_tree(
|
||||
|
||||
let local_name = if local == RETURN_PLACE {
|
||||
format!(" return place")
|
||||
} else if let Some(name) = local_decl.name {
|
||||
format!(" \"{}\"", name)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
@ -25,7 +25,7 @@ pub fn change_loop_body() {
|
||||
}
|
||||
|
||||
#[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")]
|
||||
pub fn change_loop_body() {
|
||||
let mut _x = 0;
|
||||
|
@ -22,7 +22,7 @@ pub fn change_name() {
|
||||
|
||||
#[cfg(not(cfail1))]
|
||||
#[rustc_clean(cfg="cfail2",
|
||||
except="HirBody,mir_built")]
|
||||
except="HirBody,mir_built,optimized_mir")]
|
||||
#[rustc_clean(cfg="cfail3")]
|
||||
pub fn change_name() {
|
||||
let _y = 2u64;
|
||||
@ -86,7 +86,7 @@ pub fn change_mutability_of_slot() {
|
||||
|
||||
#[cfg(not(cfail1))]
|
||||
#[rustc_clean(cfg="cfail2",
|
||||
except="HirBody,typeck_tables_of,mir_built")]
|
||||
except="HirBody,typeck_tables_of,mir_built,optimized_mir")]
|
||||
#[rustc_clean(cfg="cfail3")]
|
||||
pub fn change_mutability_of_slot() {
|
||||
let _x: u64 = 0;
|
||||
@ -182,7 +182,7 @@ pub fn add_initializer() {
|
||||
|
||||
#[cfg(not(cfail1))]
|
||||
#[rustc_clean(cfg="cfail2",
|
||||
except="HirBody,typeck_tables_of,mir_built")]
|
||||
except="HirBody,typeck_tables_of,mir_built,optimized_mir")]
|
||||
#[rustc_clean(cfg="cfail3")]
|
||||
pub fn add_initializer() {
|
||||
let _x: i16 = 3i16;
|
||||
@ -198,7 +198,7 @@ pub fn change_initializer() {
|
||||
|
||||
#[cfg(not(cfail1))]
|
||||
#[rustc_clean(cfg="cfail2",
|
||||
except="HirBody,mir_built")]
|
||||
except="HirBody,mir_built,optimized_mir")]
|
||||
#[rustc_clean(cfg="cfail3")]
|
||||
pub fn change_initializer() {
|
||||
let _x = 5u16;
|
||||
|
@ -25,7 +25,7 @@ pub fn change_loop_body() {
|
||||
}
|
||||
|
||||
#[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")]
|
||||
pub fn change_loop_body() {
|
||||
let mut _x = 0;
|
||||
|
@ -25,7 +25,7 @@ pub fn change_loop_body() {
|
||||
}
|
||||
|
||||
#[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")]
|
||||
pub fn change_loop_body() {
|
||||
let mut _x = 0;
|
||||
@ -48,7 +48,7 @@ pub fn change_loop_condition() {
|
||||
}
|
||||
|
||||
#[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")]
|
||||
pub fn change_loop_condition() {
|
||||
let mut _x = 0;
|
||||
|
@ -27,6 +27,7 @@ impl Drop for S {
|
||||
// let _3: ();
|
||||
// let mut _4: std::boxed::Box<S>;
|
||||
// scope 1 {
|
||||
// debug x => _1;
|
||||
// }
|
||||
// bb0: {
|
||||
// StorageLive(_1);
|
||||
|
@ -37,8 +37,10 @@ fn main() {
|
||||
// ...
|
||||
// let mut _9: Bar;
|
||||
// scope 1 {
|
||||
// debug a => _2;
|
||||
// let _3: Bar;
|
||||
// scope 2 {
|
||||
// debug b => _3;
|
||||
// }
|
||||
// }
|
||||
// bb0: {
|
||||
|
@ -17,23 +17,43 @@ fn foo<T: Copy>(_t: T, q: &i32) -> i32 {
|
||||
|
||||
// END RUST SOURCE
|
||||
// START rustc.foo.Inline.after.mir
|
||||
// ...
|
||||
// bb0: {
|
||||
// ...
|
||||
// _3 = [closure@HirId { owner: DefIndex(4), local_id: 31 }];
|
||||
// ...
|
||||
// _4 = &_3;
|
||||
// ...
|
||||
// _6 = &(*_2);
|
||||
// ...
|
||||
// _7 = &(*_2);
|
||||
// _5 = (move _6, move _7);
|
||||
// _8 = move (_5.0: &i32);
|
||||
// _9 = move (_5.1: &i32);
|
||||
// ...
|
||||
// _0 = (*_8);
|
||||
// ...
|
||||
// return;
|
||||
// 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: {
|
||||
// ...
|
||||
// _3 = [closure@HirId { owner: DefIndex(4), local_id: 31 }];
|
||||
// ...
|
||||
// _4 = &_3;
|
||||
// ...
|
||||
// _6 = &(*_2);
|
||||
// ...
|
||||
// _7 = &(*_2);
|
||||
// _5 = (move _6, move _7);
|
||||
// _8 = move (_5.0: &i32);
|
||||
// _9 = move (_5.1: &i32);
|
||||
// ...
|
||||
// _0 = (*_8);
|
||||
// ...
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// ...
|
||||
// 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,22 +13,38 @@ fn foo<T: Copy>(_t: T, q: i32) -> i32 {
|
||||
|
||||
// END RUST SOURCE
|
||||
// START rustc.foo.Inline.after.mir
|
||||
// ...
|
||||
// bb0: {
|
||||
// ...
|
||||
// _3 = [closure@HirId { owner: DefIndex(4), local_id: 15 }];
|
||||
// ...
|
||||
// _4 = &_3;
|
||||
// ...
|
||||
// _6 = _2;
|
||||
// ...
|
||||
// _7 = _2;
|
||||
// _5 = (move _6, move _7);
|
||||
// _8 = move (_5.0: i32);
|
||||
// _9 = move (_5.1: i32);
|
||||
// _0 = _8;
|
||||
// ...
|
||||
// return;
|
||||
// }
|
||||
// ...
|
||||
// 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: {
|
||||
// ...
|
||||
// _3 = [closure@HirId { owner: DefIndex(4), local_id: 15 }];
|
||||
// ...
|
||||
// _4 = &_3;
|
||||
// ...
|
||||
// _6 = _2;
|
||||
// ...
|
||||
// _7 = _2;
|
||||
// _5 = (move _6, move _7);
|
||||
// _8 = move (_5.0: i32);
|
||||
// _9 = move (_5.1: i32);
|
||||
// _0 = _8;
|
||||
// ...
|
||||
// return;
|
||||
// }
|
||||
// END rustc.foo.Inline.after.mir
|
||||
|
@ -35,6 +35,7 @@ impl S {
|
||||
// let mut _4: S;
|
||||
// let mut _5: bool;
|
||||
// scope 1 {
|
||||
// debug x => _1;
|
||||
// }
|
||||
// ...
|
||||
// bb0: {
|
||||
@ -47,7 +48,11 @@ impl S {
|
||||
// let mut _5: S;
|
||||
// let mut _6: bool;
|
||||
// ...
|
||||
// debug u => _1;
|
||||
// ...
|
||||
// let mut _2: S;
|
||||
// ...
|
||||
// debug v => _2;
|
||||
// ...
|
||||
// bb0: {
|
||||
// END rustc.test.ElaborateDrops.after.mir
|
||||
|
@ -25,9 +25,11 @@ enum E {
|
||||
// fn main() -> () {
|
||||
// let mut _0: ();
|
||||
// scope 1 {
|
||||
// let _1: E; // `e`
|
||||
// let _1: E;
|
||||
// debug e => _1;
|
||||
// scope 2 {
|
||||
// let _6: K;
|
||||
// debug _k => _6;
|
||||
// }
|
||||
// }
|
||||
// let mut _2: bool;
|
||||
|
@ -24,6 +24,7 @@ fn main() {
|
||||
// let _5: ();
|
||||
// let mut _6: &i32;
|
||||
// scope 1 {
|
||||
// debug beacon => _2;
|
||||
// }
|
||||
// bb0: {
|
||||
// goto -> bb1;
|
||||
|
@ -53,8 +53,14 @@ fn main() {
|
||||
// let _15: bool; // `b`
|
||||
// let _16: std::string::String; // `t`
|
||||
// scope 1 {
|
||||
// debug a => _5;
|
||||
// debug a => _6;
|
||||
// debug s => _7;
|
||||
// debug s => _8;
|
||||
// }
|
||||
// scope 2 {
|
||||
// debug b => _15;
|
||||
// debug t => _16;
|
||||
// }
|
||||
// bb0: {
|
||||
// FakeRead(ForMatchedPlace, _2);
|
||||
|
@ -29,8 +29,12 @@ fn main() {
|
||||
// START rustc.main.nll.0.mir
|
||||
// let _2: &'_#3r usize;
|
||||
// ...
|
||||
// debug p => _2;
|
||||
// ...
|
||||
// let _6: &'_#4r usize;
|
||||
// ...
|
||||
// debug q => _6;
|
||||
// ...
|
||||
// _2 = &'_#2r _1[_3];
|
||||
// ...
|
||||
// _6 = _2;
|
||||
|
@ -25,6 +25,7 @@ impl Drop for Droppy {
|
||||
// let mut _5: Droppy;
|
||||
// let mut _6: Aligned;
|
||||
// scope 1 {
|
||||
// debug x => _1;
|
||||
// }
|
||||
//
|
||||
// bb0: {
|
||||
|
@ -10,6 +10,7 @@ fn main() {
|
||||
// END RUST SOURCE
|
||||
// START rustc.try_identity.SimplifyArmIdentity.before.mir
|
||||
// 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 _2: u32;
|
||||
// let mut _3: std::result::Result<u32, i32>;
|
||||
@ -22,21 +23,27 @@ fn main() {
|
||||
// let _10: u32;
|
||||
// let mut _11: u32;
|
||||
// scope 1 {
|
||||
// debug y => _10;
|
||||
// }
|
||||
// scope 2 {
|
||||
// debug err => _6;
|
||||
// scope 3 {
|
||||
// scope 7 {
|
||||
// debug t => _6;
|
||||
// }
|
||||
// scope 8 {
|
||||
// debug v => _6;
|
||||
// let mut _12: i32;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// scope 4 {
|
||||
// debug val => _10;
|
||||
// scope 5 {
|
||||
// }
|
||||
// }
|
||||
// scope 6 {
|
||||
// debug self => _1;
|
||||
// }
|
||||
// bb0: {
|
||||
// _5 = discriminant(_1);
|
||||
@ -65,6 +72,7 @@ fn main() {
|
||||
|
||||
// START rustc.try_identity.SimplifyArmIdentity.after.mir
|
||||
// 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 _2: u32;
|
||||
// let mut _3: std::result::Result<u32, i32>;
|
||||
@ -77,21 +85,27 @@ fn main() {
|
||||
// let _10: u32;
|
||||
// let mut _11: u32;
|
||||
// scope 1 {
|
||||
// debug y => _10;
|
||||
// }
|
||||
// scope 2 {
|
||||
// debug err => _6;
|
||||
// scope 3 {
|
||||
// scope 7 {
|
||||
// debug t => _6;
|
||||
// }
|
||||
// scope 8 {
|
||||
// debug v => _6;
|
||||
// let mut _12: i32;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// scope 4 {
|
||||
// debug val => _10;
|
||||
// scope 5 {
|
||||
// }
|
||||
// }
|
||||
// scope 6 {
|
||||
// debug self => _1;
|
||||
// }
|
||||
// bb0: {
|
||||
// _5 = discriminant(_1);
|
||||
@ -120,6 +134,7 @@ fn main() {
|
||||
|
||||
// START rustc.try_identity.SimplifyBranchSame.after.mir
|
||||
// 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 _2: u32;
|
||||
// let mut _3: std::result::Result<u32, i32>;
|
||||
@ -132,21 +147,27 @@ fn main() {
|
||||
// let _10: u32;
|
||||
// let mut _11: u32;
|
||||
// scope 1 {
|
||||
// debug y => _10;
|
||||
// }
|
||||
// scope 2 {
|
||||
// debug err => _6;
|
||||
// scope 3 {
|
||||
// scope 7 {
|
||||
// debug t => _6;
|
||||
// }
|
||||
// scope 8 {
|
||||
// debug v => _6;
|
||||
// let mut _12: i32;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// scope 4 {
|
||||
// debug val => _10;
|
||||
// scope 5 {
|
||||
// }
|
||||
// }
|
||||
// scope 6 {
|
||||
// debug self => _1;
|
||||
// }
|
||||
// bb0: {
|
||||
// _5 = discriminant(_1);
|
||||
@ -166,23 +187,32 @@ fn main() {
|
||||
|
||||
// START rustc.try_identity.SimplifyLocals.after.mir
|
||||
// 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 _2: isize;
|
||||
// let _3: i32;
|
||||
// let _4: u32;
|
||||
// scope 1 {
|
||||
// debug y => _4;
|
||||
// }
|
||||
// scope 2 {
|
||||
// debug err => _3;
|
||||
// scope 3 {
|
||||
// scope 7 {
|
||||
// debug t => _3;
|
||||
// }
|
||||
// scope 8 {
|
||||
// debug v => _3;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// scope 4 {
|
||||
// debug val => _4;
|
||||
// scope 5 {
|
||||
// }
|
||||
// }
|
||||
// scope 6 {
|
||||
// debug self => _1;
|
||||
// }
|
||||
// bb0: {
|
||||
// _2 = discriminant(_1);
|
||||
|
Loading…
Reference in New Issue
Block a user