From 563ed27c01c204d734355709c905f9a14246d4ff Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 16 May 2018 18:58:54 +0300 Subject: [PATCH] rustc: move debug info from LocalDecl and UpvarDecl into a dedicated VarDebugInfo. --- src/librustc/mir/mod.rs | 73 +++---- src/librustc/mir/visit.rs | 31 ++- .../debuginfo/create_scope_map.rs | 6 +- .../debuginfo/metadata.rs | 100 ++++++++-- src/librustc_codegen_ssa/mir/analyze.rs | 113 ++++++++--- src/librustc_codegen_ssa/mir/debuginfo.rs | 139 ++----------- src/librustc_codegen_ssa/mir/mod.rs | 4 +- .../borrow_check/conflict_errors.rs | 66 +++++-- .../borrow_check/error_reporting.rs | 8 +- src/librustc_mir/borrow_check/mod.rs | 26 ++- src/librustc_mir/borrow_check/move_errors.rs | 4 +- .../borrow_check/mutability_errors.rs | 9 +- .../borrow_check/nll/explain_borrow/mod.rs | 12 +- src/librustc_mir/borrow_check/nll/mod.rs | 4 +- .../nll/region_infer/error_reporting/mod.rs | 26 ++- .../error_reporting/outlives_suggestion.rs | 23 ++- .../error_reporting/region_name.rs | 14 +- .../region_infer/error_reporting/var_name.rs | 11 +- .../borrow_check/nll/region_infer/mod.rs | 16 +- src/librustc_mir/build/expr/into.rs | 2 - src/librustc_mir/build/matches/mod.rs | 18 +- src/librustc_mir/build/mod.rs | 186 ++++++++++-------- src/librustc_mir/shim.rs | 6 - src/librustc_mir/transform/const_prop.rs | 1 - src/librustc_mir/transform/generator.rs | 18 +- src/librustc_mir/transform/inline.rs | 12 +- src/librustc_mir/transform/promote_consts.rs | 1 - src/librustc_mir/transform/simplify.rs | 8 - .../transform/uniform_array_move_out.rs | 1 + src/librustc_mir/util/def_use.rs | 41 +++- src/librustc_mir/util/graphviz.rs | 14 +- src/librustc_mir/util/liveness.rs | 3 + src/librustc_mir/util/pretty.rs | 26 ++- src/test/incremental/hashes/for_loops.rs | 2 +- .../incremental/hashes/let_expressions.rs | 8 +- .../incremental/hashes/loop_expressions.rs | 2 +- src/test/incremental/hashes/while_loops.rs | 4 +- src/test/mir-opt/box_expr.rs | 1 + .../mir-opt/generator-storage-dead-unwind.rs | 2 + .../mir-opt/inline-closure-borrows-arg.rs | 56 ++++-- src/test/mir-opt/inline-closure-captures.rs | 60 ++++++ src/test/mir-opt/inline-closure.rs | 52 +++-- src/test/mir-opt/issue-41110.rs | 5 + src/test/mir-opt/issue-41888.rs | 4 +- src/test/mir-opt/issue-49232.rs | 1 + src/test/mir-opt/match-arm-scopes.rs | 6 + .../mir-opt/nll/region-subtyping-basic.rs | 4 + .../mir-opt/packed-struct-drop-aligned.rs | 1 + src/test/mir-opt/simplify_try.rs | 30 +++ 49 files changed, 780 insertions(+), 480 deletions(-) create mode 100644 src/test/mir-opt/inline-closure-captures.rs diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index bd793fd07bf22..4103d25fbd173 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -141,14 +141,8 @@ pub struct Body<'tcx> { /// This is used for the "rust-call" ABI. pub spread_arg: Option, - /// 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, + /// Debug information pertaining to user variables, including captures. + pub var_debug_info: Vec>, /// 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>, source_scopes: IndexVec, source_scope_local_data: ClearCrossCrate>, - yield_ty: Option>, local_decls: LocalDecls<'tcx>, user_type_annotations: CanonicalUserTypeAnnotations<'tcx>, arg_count: usize, - __upvar_debuginfo_codegen_only_do_not_use: Vec, + var_debug_info: Vec>, 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, - /// 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, - - /// 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>, } #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] @@ -2946,7 +2922,6 @@ CloneTypeFoldableAndLiftImpls! { MirPhase, Mutability, SourceInfo, - UpvarDebuginfo, FakeReadCause, RetagKind, SourceScope, diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index fc0e77aab43a4..464d4c74366e5 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -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)] diff --git a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs index 6ee76b71fced6..91d5a22b0228d 100644 --- a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs +++ b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs @@ -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. diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index 2e16ae4c73f88..1847e4e9fa951 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -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>) { + 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> { + 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>, + variant_index: VariantIdx, + }, } -impl<'tcx> VariantInfo<'tcx> { +impl<'tcx> VariantInfo<'_, 'tcx> { fn map_struct_name(&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, diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index 2e5dc3db31af9..e44551fcbcdfe 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -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> 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> 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; - // 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) + }; + } - 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); } - - 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) => {} diff --git a/src/librustc_codegen_ssa/mir/debuginfo.rs b/src/librustc_codegen_ssa/mir/debuginfo.rs index c215db34ccbc8..bb2679e214db4 100644 --- a/src/librustc_codegen_ssa/mir/debuginfo.rs +++ b/src/librustc_codegen_ssa/mir/debuginfo.rs @@ -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>>> { + body: &'a mir::Body<'tcx>, +) -> Option>>> { 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(), - }); - } - } - - 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), - }, - }); + for var in &body.var_debug_info { + if let mir::PlaceBase::Local(local) = var.place.base { + per_local[local].push(var); } } - 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>, -} diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index fec31f07a349b..6041232489d0d 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -74,7 +74,9 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { /// notably `expect`. locals: IndexVec>, - per_local_var_debug_info: Option>>>, + /// 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>>>, } impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs index 9364bbedb0c58..8508bf62d8f60 100644 --- a/src/librustc_mir/borrow_check/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/conflict_errors.rs @@ -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, diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 3835503b0ef35..a555e0b74c2b7 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -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(()) } diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 90e39286ec84d..8a74e3a74add7 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -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, + + /// Names of local (user) variables (extracted from `var_debug_info`). + local_names: IndexVec>, } // Check that: diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index c7cfda79b9383..bf61eb9f0c5c7 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -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) ); diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index 404684c07a09c..bf070c3f07d48 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -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, diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs index 26bead3047d5d..c7058531958e1 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -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>, err: &mut DiagnosticBuilder<'_>, borrow_desc: &str, borrow_span: Option, @@ -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 diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index b2e5751b902e7..4d67b72c98c57 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -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>, + local_names: &IndexVec>, 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. diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs index e6795dbfd449c..5e79a2fea9b73 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs @@ -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>, + /// 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>, 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>, 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); diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/outlives_suggestion.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/outlives_suggestion.rs index 62142efe505b2..c0cf4eb5285c9 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/outlives_suggestion.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/outlives_suggestion.rs @@ -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>, + /// 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>, } -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>, + ) -> 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. diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs index a8cc0cc044a01..e59928987a03c 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs @@ -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 { 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>, 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>, 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 diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs index 7f0e97c9ae426..1ac44c4fdb101 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs @@ -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>, upvars: &[Upvar], fr: RegionVid, ) -> Option<(Option, 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>, argument_index: usize, ) -> (Option, 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); diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 4de8200e6a0c7..d44e85fa7900d 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -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>, upvars: &[Upvar], mir_def_id: DefId, errors_buffer: &mut Vec, @@ -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>, upvars: &[Upvar], mir_def_id: DefId, mut propagated_outlives_requirements: Option<&mut Vec>>, errors_buffer: &mut Vec, 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>, upvars: &[Upvar], mir_def_id: DefId, longer_fr: RegionVid, propagated_outlives_requirements: &mut Option<&mut Vec>>, - outlives_suggestion: &mut OutlivesSuggestionBuilder, + outlives_suggestion: &mut OutlivesSuggestionBuilder<'_>, errors_buffer: &mut Vec, 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>, upvars: &[Upvar], mir_def_id: DefId, propagated_outlives_requirements: &mut Option<&mut Vec>>, - outlives_suggestion: &mut OutlivesSuggestionBuilder, + outlives_suggestion: &mut OutlivesSuggestionBuilder<'_>, errors_buffer: &mut Vec, region_naming: &mut RegionErrorNamingCtx, ) -> Option { @@ -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, diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index e991181189f41..f5dc09ccebc1e 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -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, diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 514dd74dc0b3e..032ea7d8161cb 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -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, diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 6b458cc244c9e..180f2cc089f02 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -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, local_decls: IndexVec>, canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>, - __upvar_debuginfo_codegen_only_do_not_use: Vec, upvar_mutbls: Vec, unit_temp: Option>, + var_debug_info: Vec>, + /// Cached block with the `RESUME` terminator; this is created /// when first set of cleanups are built. cached_resume_block: Option, @@ -539,7 +550,6 @@ fn construct_fn<'a, 'tcx, A>( safety: Safety, abi: Abi, return_ty: Ty<'tcx>, - yield_ty: Option>, 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, - upvar_mutbls: Vec, 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>) - -> 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; diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 17f5e3d4e47a9..b5cb6a92816be 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -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>) 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(), diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 6f0b960cab107..8de16308e8375 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -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, diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 524b6b087908c..a904c6a3ada0f 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -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::::new(); let mut tys = IndexVec::::new(); - let mut decls = IndexVec::::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 diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 5a34e3f471f66..867673beb35cc 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -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); diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 86ecfbb4fbea5..c92c59dd2f79c 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -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, diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index f6b09f20bab67..c9185d14148c1 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -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 }; diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs index e4c2f7d389b50..28f68ac2de037 100644 --- a/src/librustc_mir/transform/uniform_array_move_out.rs +++ b/src/librustc_mir/transform/uniform_array_move_out.rs @@ -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() { diff --git a/src/librustc_mir/util/def_use.rs b/src/librustc_mir/util/def_use.rs index 725ec84ca6237..1611caddad1a6 100644 --- a/src/librustc_mir/util/def_use.rs +++ b/src/librustc_mir/util/def_use.rs @@ -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, + var_debug_info_indices: Vec, } #[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, + 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 { diff --git a/src/librustc_mir/util/graphviz.rs b/src/librustc_mir/util/graphviz.rs index ff2946d3a690e..3a7ec9f038aa5 100644 --- a/src/librustc_mir/util/graphviz.rs +++ b/src/librustc_mir/util/graphviz.rs @@ -197,13 +197,13 @@ fn write_graph_label<'tcx, W: Write>( write!(w, "mut ")?; } - if let Some(name) = decl.name { - write!(w, r#"{:?}: {}; // {}
"#, - Place::from(local), escape(&decl.ty), name)?; - } else { - write!(w, r#"{:?}: {};
"#, - Place::from(local), escape(&decl.ty))?; - } + write!(w, r#"{:?}: {};
"#, + Place::from(local), escape(&decl.ty))?; + } + + for var_debug_info in &body.var_debug_info { + write!(w, r#"debug {} => {};
"#, + var_debug_info.name, escape(&var_debug_info.place))?; } writeln!(w, ">;") diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index 9757f4ac392ec..63e4af0a56a75 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -183,6 +183,9 @@ pub fn categorize(context: PlaceContext) -> Option { PlaceContext::MutatingUse(MutatingUseContext::Drop) => Some(DefUse::Drop), + + // Debug info is neither def nor use. + PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None, } } diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 89f298846d2f5..36194335a555a 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -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() }; diff --git a/src/test/incremental/hashes/for_loops.rs b/src/test/incremental/hashes/for_loops.rs index 8e134ad14fc14..70820dfaea4a0 100644 --- a/src/test/incremental/hashes/for_loops.rs +++ b/src/test/incremental/hashes/for_loops.rs @@ -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; diff --git a/src/test/incremental/hashes/let_expressions.rs b/src/test/incremental/hashes/let_expressions.rs index 4e8ba5a209df8..68545b7daaa5c 100644 --- a/src/test/incremental/hashes/let_expressions.rs +++ b/src/test/incremental/hashes/let_expressions.rs @@ -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; diff --git a/src/test/incremental/hashes/loop_expressions.rs b/src/test/incremental/hashes/loop_expressions.rs index ca85ee39e3671..a2222db4c59ad 100644 --- a/src/test/incremental/hashes/loop_expressions.rs +++ b/src/test/incremental/hashes/loop_expressions.rs @@ -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; diff --git a/src/test/incremental/hashes/while_loops.rs b/src/test/incremental/hashes/while_loops.rs index 70d0f86c3d268..a427ffb96e339 100644 --- a/src/test/incremental/hashes/while_loops.rs +++ b/src/test/incremental/hashes/while_loops.rs @@ -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; diff --git a/src/test/mir-opt/box_expr.rs b/src/test/mir-opt/box_expr.rs index 8dc6b73edf6d4..fa1a291858bec 100644 --- a/src/test/mir-opt/box_expr.rs +++ b/src/test/mir-opt/box_expr.rs @@ -27,6 +27,7 @@ impl Drop for S { // let _3: (); // let mut _4: std::boxed::Box; // scope 1 { +// debug x => _1; // } // bb0: { // StorageLive(_1); diff --git a/src/test/mir-opt/generator-storage-dead-unwind.rs b/src/test/mir-opt/generator-storage-dead-unwind.rs index 109304d6d22cc..ecce0a08c7bf0 100644 --- a/src/test/mir-opt/generator-storage-dead-unwind.rs +++ b/src/test/mir-opt/generator-storage-dead-unwind.rs @@ -37,8 +37,10 @@ fn main() { // ... // let mut _9: Bar; // scope 1 { +// debug a => _2; // let _3: Bar; // scope 2 { +// debug b => _3; // } // } // bb0: { diff --git a/src/test/mir-opt/inline-closure-borrows-arg.rs b/src/test/mir-opt/inline-closure-borrows-arg.rs index 491130b7c5d32..b5bfeef5e9c56 100644 --- a/src/test/mir-opt/inline-closure-borrows-arg.rs +++ b/src/test/mir-opt/inline-closure-borrows-arg.rs @@ -17,23 +17,43 @@ fn foo(_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 diff --git a/src/test/mir-opt/inline-closure-captures.rs b/src/test/mir-opt/inline-closure-captures.rs new file mode 100644 index 0000000000000..e73dbe48bd143 --- /dev/null +++ b/src/test/mir-opt/inline-closure-captures.rs @@ -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: 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 diff --git a/src/test/mir-opt/inline-closure.rs b/src/test/mir-opt/inline-closure.rs index 7c0259b643a63..ddf027f4be38a 100644 --- a/src/test/mir-opt/inline-closure.rs +++ b/src/test/mir-opt/inline-closure.rs @@ -13,22 +13,38 @@ fn foo(_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 diff --git a/src/test/mir-opt/issue-41110.rs b/src/test/mir-opt/issue-41110.rs index e73390f52b5d5..5ba54f98d00da 100644 --- a/src/test/mir-opt/issue-41110.rs +++ b/src/test/mir-opt/issue-41110.rs @@ -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 diff --git a/src/test/mir-opt/issue-41888.rs b/src/test/mir-opt/issue-41888.rs index 58f321d6df170..efe2b249d4a86 100644 --- a/src/test/mir-opt/issue-41888.rs +++ b/src/test/mir-opt/issue-41888.rs @@ -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; diff --git a/src/test/mir-opt/issue-49232.rs b/src/test/mir-opt/issue-49232.rs index d0dbcbd7515f8..54c89b85f42d7 100644 --- a/src/test/mir-opt/issue-49232.rs +++ b/src/test/mir-opt/issue-49232.rs @@ -24,6 +24,7 @@ fn main() { // let _5: (); // let mut _6: &i32; // scope 1 { +// debug beacon => _2; // } // bb0: { // goto -> bb1; diff --git a/src/test/mir-opt/match-arm-scopes.rs b/src/test/mir-opt/match-arm-scopes.rs index c898d3a6f168c..4412a16e74d5e 100644 --- a/src/test/mir-opt/match-arm-scopes.rs +++ b/src/test/mir-opt/match-arm-scopes.rs @@ -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); diff --git a/src/test/mir-opt/nll/region-subtyping-basic.rs b/src/test/mir-opt/nll/region-subtyping-basic.rs index 8228d9740f0d3..16e357fc16255 100644 --- a/src/test/mir-opt/nll/region-subtyping-basic.rs +++ b/src/test/mir-opt/nll/region-subtyping-basic.rs @@ -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; diff --git a/src/test/mir-opt/packed-struct-drop-aligned.rs b/src/test/mir-opt/packed-struct-drop-aligned.rs index da73cc96348f0..113f81c441f7c 100644 --- a/src/test/mir-opt/packed-struct-drop-aligned.rs +++ b/src/test/mir-opt/packed-struct-drop-aligned.rs @@ -25,6 +25,7 @@ impl Drop for Droppy { // let mut _5: Droppy; // let mut _6: Aligned; // scope 1 { +// debug x => _1; // } // // bb0: { diff --git a/src/test/mir-opt/simplify_try.rs b/src/test/mir-opt/simplify_try.rs index 7911fbd0a984d..656b405ef340e 100644 --- a/src/test/mir-opt/simplify_try.rs +++ b/src/test/mir-opt/simplify_try.rs @@ -10,6 +10,7 @@ fn main() { // END RUST SOURCE // START rustc.try_identity.SimplifyArmIdentity.before.mir // fn try_identity(_1: std::result::Result) -> std::result::Result { +// debug x => _1; // let mut _0: std::result::Result; // let _2: u32; // let mut _3: std::result::Result; @@ -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) -> std::result::Result { +// debug x => _1; // let mut _0: std::result::Result; // let _2: u32; // let mut _3: std::result::Result; @@ -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) -> std::result::Result { +// debug x => _1; // let mut _0: std::result::Result; // let _2: u32; // let mut _3: std::result::Result; @@ -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) -> std::result::Result { +// debug x => _1; // let mut _0: std::result::Result; // 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);