|
| 1 | +use rustc_index::vec::Idx; |
1 | 2 | use rustc::hir::def_id::CrateNum;
|
2 | 3 | use rustc::mir;
|
| 4 | +use rustc::session::config::DebugInfo; |
| 5 | +use rustc::ty::{self, UpvarSubsts}; |
| 6 | +use rustc::ty::layout::HasTyCtxt; |
| 7 | +use rustc_target::abi::{Variants, VariantIdx}; |
3 | 8 | use crate::traits::*;
|
4 | 9 |
|
5 | 10 | use syntax_pos::{DUMMY_SP, BytePos, Span};
|
| 11 | +use syntax::symbol::kw; |
6 | 12 |
|
7 |
| -use super::FunctionCx; |
| 13 | +use super::{FunctionCx, LocalRef}; |
8 | 14 |
|
9 | 15 | pub enum FunctionDebugContext<D> {
|
10 | 16 | RegularContext(FunctionDebugContextData<D>),
|
@@ -142,4 +148,175 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
142 | 148 | scope_metadata
|
143 | 149 | }
|
144 | 150 | }
|
| 151 | + |
| 152 | + pub fn debug_declare_locals(&self, bx: &mut Bx) { |
| 153 | + let tcx = self.cx.tcx(); |
| 154 | + let upvar_debuginfo = &self.mir.__upvar_debuginfo_codegen_only_do_not_use; |
| 155 | + |
| 156 | + if bx.sess().opts.debuginfo != DebugInfo::Full { |
| 157 | + return; |
| 158 | + } |
| 159 | + |
| 160 | + for (local, local_ref) in self.locals.iter_enumerated() { |
| 161 | + if local == mir::RETURN_PLACE { |
| 162 | + continue; |
| 163 | + } |
| 164 | + |
| 165 | + // FIXME(eddyb) add debuginfo for unsized places too. |
| 166 | + let place = match local_ref { |
| 167 | + LocalRef::Place(place) => place, |
| 168 | + _ => continue, |
| 169 | + }; |
| 170 | + |
| 171 | + let decl = &self.mir.local_decls[local]; |
| 172 | + let (name, kind) = if self.mir.local_kind(local) == mir::LocalKind::Arg { |
| 173 | + let arg_index = local.index() - 1; |
| 174 | + |
| 175 | + // Add debuginfo even to unnamed arguments. |
| 176 | + // FIXME(eddyb) is this really needed? |
| 177 | + let name = if arg_index == 0 && !upvar_debuginfo.is_empty() { |
| 178 | + // Hide closure environments from debuginfo. |
| 179 | + // FIXME(eddyb) shouldn't `ArgumentVariable` indices |
| 180 | + // be offset to account for the hidden environment? |
| 181 | + None |
| 182 | + } else { |
| 183 | + Some(decl.name.unwrap_or(kw::Invalid)) |
| 184 | + }; |
| 185 | + (name, VariableKind::ArgumentVariable(arg_index + 1)) |
| 186 | + } else { |
| 187 | + (decl.name, VariableKind::LocalVariable) |
| 188 | + }; |
| 189 | + if let Some(name) = name { |
| 190 | + let (scope, span) = self.debug_loc(mir::SourceInfo { |
| 191 | + span: decl.source_info.span, |
| 192 | + scope: decl.visibility_scope, |
| 193 | + }); |
| 194 | + if let Some(scope) = scope { |
| 195 | + bx.declare_local(&self.debug_context, name, place.layout.ty, scope, |
| 196 | + VariableAccess::DirectVariable { alloca: place.llval }, |
| 197 | + kind, span); |
| 198 | + } |
| 199 | + } |
| 200 | + } |
| 201 | + |
| 202 | + // Declare closure captures as if they were local variables. |
| 203 | + // FIXME(eddyb) generalize this to `name => place` mappings. |
| 204 | + let upvar_scope = if !upvar_debuginfo.is_empty() { |
| 205 | + self.scopes[mir::OUTERMOST_SOURCE_SCOPE].scope_metadata |
| 206 | + } else { |
| 207 | + None |
| 208 | + }; |
| 209 | + if let Some(scope) = upvar_scope { |
| 210 | + let place = match self.locals[mir::Local::new(1)] { |
| 211 | + LocalRef::Place(place) => place, |
| 212 | + _ => bug!(), |
| 213 | + }; |
| 214 | + |
| 215 | + let pin_did = tcx.lang_items().pin_type(); |
| 216 | + let (closure_layout, env_ref) = match place.layout.ty.kind { |
| 217 | + ty::RawPtr(ty::TypeAndMut { ty, .. }) | |
| 218 | + ty::Ref(_, ty, _) => (bx.layout_of(ty), true), |
| 219 | + ty::Adt(def, substs) if Some(def.did) == pin_did => { |
| 220 | + match substs.type_at(0).kind { |
| 221 | + ty::Ref(_, ty, _) => (bx.layout_of(ty), true), |
| 222 | + _ => (place.layout, false), |
| 223 | + } |
| 224 | + } |
| 225 | + _ => (place.layout, false) |
| 226 | + }; |
| 227 | + |
| 228 | + let (def_id, upvar_substs) = match closure_layout.ty.kind { |
| 229 | + ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs)), |
| 230 | + ty::Generator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)), |
| 231 | + _ => bug!("upvar debuginfo with non-closure arg0 type `{}`", closure_layout.ty) |
| 232 | + }; |
| 233 | + let upvar_tys = upvar_substs.upvar_tys(def_id, tcx); |
| 234 | + |
| 235 | + let extra_locals = { |
| 236 | + let upvars = upvar_debuginfo |
| 237 | + .iter() |
| 238 | + .zip(upvar_tys) |
| 239 | + .enumerate() |
| 240 | + .map(|(i, (upvar, ty))| { |
| 241 | + (None, i, upvar.debug_name, upvar.by_ref, ty, scope, DUMMY_SP) |
| 242 | + }); |
| 243 | + |
| 244 | + let generator_fields = self.mir.generator_layout.as_ref().map(|generator_layout| { |
| 245 | + let (def_id, gen_substs) = match closure_layout.ty.kind { |
| 246 | + ty::Generator(def_id, substs, _) => (def_id, substs), |
| 247 | + _ => bug!("generator layout without generator substs"), |
| 248 | + }; |
| 249 | + let state_tys = gen_substs.as_generator().state_tys(def_id, tcx); |
| 250 | + |
| 251 | + generator_layout.variant_fields.iter() |
| 252 | + .zip(state_tys) |
| 253 | + .enumerate() |
| 254 | + .flat_map(move |(variant_idx, (fields, tys))| { |
| 255 | + let variant_idx = Some(VariantIdx::from(variant_idx)); |
| 256 | + fields.iter() |
| 257 | + .zip(tys) |
| 258 | + .enumerate() |
| 259 | + .filter_map(move |(i, (field, ty))| { |
| 260 | + let decl = &generator_layout. |
| 261 | + __local_debuginfo_codegen_only_do_not_use[*field]; |
| 262 | + if let Some(name) = decl.name { |
| 263 | + let ty = self.monomorphize(&ty); |
| 264 | + let (var_scope, var_span) = self.debug_loc(mir::SourceInfo { |
| 265 | + span: decl.source_info.span, |
| 266 | + scope: decl.visibility_scope, |
| 267 | + }); |
| 268 | + let var_scope = var_scope.unwrap_or(scope); |
| 269 | + Some((variant_idx, i, name, false, ty, var_scope, var_span)) |
| 270 | + } else { |
| 271 | + None |
| 272 | + } |
| 273 | + }) |
| 274 | + }) |
| 275 | + }).into_iter().flatten(); |
| 276 | + |
| 277 | + upvars.chain(generator_fields) |
| 278 | + }; |
| 279 | + |
| 280 | + for (variant_idx, field, name, by_ref, ty, var_scope, var_span) in extra_locals { |
| 281 | + let fields = match variant_idx { |
| 282 | + Some(variant_idx) => { |
| 283 | + match &closure_layout.variants { |
| 284 | + Variants::Multiple { variants, .. } => { |
| 285 | + &variants[variant_idx].fields |
| 286 | + }, |
| 287 | + _ => bug!("variant index on univariant layout"), |
| 288 | + } |
| 289 | + } |
| 290 | + None => &closure_layout.fields, |
| 291 | + }; |
| 292 | + let byte_offset_of_var_in_env = fields.offset(field).bytes(); |
| 293 | + |
| 294 | + let ops = bx.debuginfo_upvar_ops_sequence(byte_offset_of_var_in_env); |
| 295 | + |
| 296 | + // The environment and the capture can each be indirect. |
| 297 | + let mut ops = if env_ref { &ops[..] } else { &ops[1..] }; |
| 298 | + |
| 299 | + let ty = if let (true, &ty::Ref(_, ty, _)) = (by_ref, &ty.kind) { |
| 300 | + ty |
| 301 | + } else { |
| 302 | + ops = &ops[..ops.len() - 1]; |
| 303 | + ty |
| 304 | + }; |
| 305 | + |
| 306 | + let variable_access = VariableAccess::IndirectVariable { |
| 307 | + alloca: place.llval, |
| 308 | + address_operations: &ops |
| 309 | + }; |
| 310 | + bx.declare_local( |
| 311 | + &self.debug_context, |
| 312 | + name, |
| 313 | + ty, |
| 314 | + var_scope, |
| 315 | + variable_access, |
| 316 | + VariableKind::LocalVariable, |
| 317 | + var_span |
| 318 | + ); |
| 319 | + } |
| 320 | + } |
| 321 | + } |
145 | 322 | }
|
0 commit comments