about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-12-25 14:21:47 +0000
committerbors <bors@rust-lang.org>2014-12-25 14:21:47 +0000
commitf673e9841f58a2196efd3b757804efa2575f8b79 (patch)
treeddc92fbfca99d63685e99b9a53c350aa3121f373 /src
parentead198c5133fd649d1e385cfc46f344a2baaef8b (diff)
parent875a30c492b0eaa745f88db4d4c14887a6dd6ae0 (diff)
downloadrust-f673e9841f58a2196efd3b757804efa2575f8b79.tar.gz
rust-f673e9841f58a2196efd3b757804efa2575f8b79.zip
auto merge of #20167 : michaelwoerister/rust/for-loop-var, r=alexcrichton
... really this time `:)`

I went for the simpler fix after all since it turned out to become a bit too complicated to extract the current iteration value from its containing `Option` with the different memory layouts it can have. It's also what we already do for match bindings.

I also extended the new test case to include the "simple identifier" case.

Fixes #20127, fixes #19732
Diffstat (limited to 'src')
-rw-r--r--src/librustc_trans/trans/_match.rs3
-rw-r--r--src/librustc_trans/trans/controlflow.rs3
-rw-r--r--src/librustc_trans/trans/debuginfo.rs191
-rw-r--r--src/test/debuginfo/destructured-for-loop-variable.rs219
-rw-r--r--src/test/debuginfo/lexical-scope-in-for-loop.rs1
5 files changed, 345 insertions, 72 deletions
diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs
index 33fd14a441b..fb8006905f9 100644
--- a/src/librustc_trans/trans/_match.rs
+++ b/src/librustc_trans/trans/_match.rs
@@ -1554,7 +1554,8 @@ pub fn store_for_loop_binding<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                           -> Block<'blk, 'tcx> {
     let _icx = push_ctxt("match::store_for_loop_binding");
 
-    if simple_identifier(&*pat).is_some() {
+    if simple_identifier(&*pat).is_some() &&
+       bcx.sess().opts.debuginfo != FullDebugInfo {
         // Generate nicer LLVM for the common case of a `for` loop pattern
         // like `for x in blahblah { ... }`.
         let binding_type = node_id_type(bcx, pat.id);
diff --git a/src/librustc_trans/trans/controlflow.rs b/src/librustc_trans/trans/controlflow.rs
index b19faf4df1f..3b24ded6717 100644
--- a/src/librustc_trans/trans/controlflow.rs
+++ b/src/librustc_trans/trans/controlflow.rs
@@ -286,6 +286,7 @@ pub fn trans_for<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
     debug!("iterator type is {}, datum type is {}",
            ppaux::ty_to_string(bcx.tcx(), iterator_type),
            ppaux::ty_to_string(bcx.tcx(), iterator_datum.ty));
+
     let lliterator = load_ty(bcx, iterator_datum.val, iterator_datum.ty);
 
     // Create our basic blocks and set up our loop cleanups.
@@ -365,6 +366,8 @@ pub fn trans_for<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                                        llpayload,
                                        binding_cleanup_scope_id);
 
+    debuginfo::create_for_loop_var_metadata(body_bcx_in, pat);
+
     // Codegen the body.
     body_bcx_out = trans_block(body_bcx_out, body, expr::Ignore);
     body_bcx_out =
diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs
index 8fadaa05203..f829a8ec248 100644
--- a/src/librustc_trans/trans/debuginfo.rs
+++ b/src/librustc_trans/trans/debuginfo.rs
@@ -182,7 +182,6 @@
 //! comparatively expensive to construct, though, `ty::type_id()` is still used
 //! additionally as an optimization for cases where the exact same type has been
 //! seen before (which is most of the time).
-use self::FunctionDebugContextRepr::*;
 use self::VariableAccess::*;
 use self::VariableKind::*;
 use self::MemberOffset::*;
@@ -679,12 +678,8 @@ impl<'tcx> CrateDebugContext<'tcx> {
     }
 }
 
-pub struct FunctionDebugContext {
-    repr: FunctionDebugContextRepr,
-}
-
-enum FunctionDebugContextRepr {
-    DebugInfo(Box<FunctionDebugContextData>),
+pub enum FunctionDebugContext {
+    RegularContext(Box<FunctionDebugContextData>),
     DebugInfoDisabled,
     FunctionWithoutDebugInfo,
 }
@@ -694,13 +689,13 @@ impl FunctionDebugContext {
                    cx: &CrateContext,
                    span: Span)
                    -> &'a FunctionDebugContextData {
-        match self.repr {
-            DebugInfo(box ref data) => data,
-            DebugInfoDisabled => {
+        match *self {
+            FunctionDebugContext::RegularContext(box ref data) => data,
+            FunctionDebugContext::DebugInfoDisabled => {
                 cx.sess().span_bug(span,
                                    FunctionDebugContext::debuginfo_disabled_message());
             }
-            FunctionWithoutDebugInfo => {
+            FunctionDebugContext::FunctionWithoutDebugInfo => {
                 cx.sess().span_bug(span,
                                    FunctionDebugContext::should_be_ignored_message());
             }
@@ -844,6 +839,8 @@ pub fn create_global_var_metadata(cx: &CrateContext,
 
 /// Creates debug information for the given local variable.
 ///
+/// This function assumes that there's a datum for each pattern component of the
+/// local in `bcx.fcx.lllocals`.
 /// Adds the created metadata nodes directly to the crate's IR.
 pub fn create_local_var_metadata(bcx: Block, local: &ast::Local) {
     if fn_should_be_ignored(bcx.fcx) {
@@ -852,11 +849,10 @@ pub fn create_local_var_metadata(bcx: Block, local: &ast::Local) {
 
     let cx = bcx.ccx();
     let def_map = &cx.tcx().def_map;
+    let locals = bcx.fcx.lllocals.borrow();
 
-    pat_util::pat_bindings(def_map, &*local.pat, |_, node_id, span, path1| {
-        let var_ident = path1.node;
-
-        let datum = match bcx.fcx.lllocals.borrow().get(&node_id).cloned() {
+    pat_util::pat_bindings(def_map, &*local.pat, |_, node_id, span, var_ident| {
+        let datum = match locals.get(&node_id) {
             Some(datum) => datum,
             None => {
                 bcx.sess().span_bug(span,
@@ -865,10 +861,15 @@ pub fn create_local_var_metadata(bcx: Block, local: &ast::Local) {
             }
         };
 
+        if unsafe { llvm::LLVMIsAAllocaInst(datum.val) } == ptr::null_mut() {
+            cx.sess().span_bug(span, "debuginfo::create_local_var_metadata() - \
+                                      Referenced variable location is not an alloca!");
+        }
+
         let scope_metadata = scope_metadata(bcx.fcx, node_id, span);
 
         declare_local(bcx,
-                      var_ident,
+                      var_ident.node,
                       datum.ty,
                       scope_metadata,
                       DirectVariable { alloca: datum.val },
@@ -981,7 +982,7 @@ pub fn create_match_binding_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     // for the binding. For ByRef bindings that's a `T*` but for ByMove bindings we
     // actually have `T**`. So to get the actual variable we need to dereference once
     // more. For ByCopy we just use the stack slot we created for the binding.
-    let var_type = match binding.trmode {
+    let var_access = match binding.trmode {
         TrByCopy(llbinding) => DirectVariable {
             alloca: llbinding
         },
@@ -998,27 +999,31 @@ pub fn create_match_binding_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                   variable_ident,
                   binding.ty,
                   scope_metadata,
-                  var_type,
+                  var_access,
                   LocalVariable,
                   binding.span);
 }
 
 /// Creates debug information for the given function argument.
 ///
+/// This function assumes that there's a datum for each pattern component of the
+/// argument in `bcx.fcx.lllocals`.
 /// Adds the created metadata nodes directly to the crate's IR.
 pub fn create_argument_metadata(bcx: Block, arg: &ast::Arg) {
     if fn_should_be_ignored(bcx.fcx) {
         return;
     }
 
-    let fcx = bcx.fcx;
-    let cx = fcx.ccx;
+    let def_map = &bcx.tcx().def_map;
+    let scope_metadata = bcx
+                         .fcx
+                         .debug_context
+                         .get_ref(bcx.ccx(), arg.pat.span)
+                         .fn_metadata;
+    let locals = bcx.fcx.lllocals.borrow();
 
-    let def_map = &cx.tcx().def_map;
-    let scope_metadata = bcx.fcx.debug_context.get_ref(cx, arg.pat.span).fn_metadata;
-
-    pat_util::pat_bindings(def_map, &*arg.pat, |_, node_id, span, path1| {
-        let llarg = match bcx.fcx.lllocals.borrow().get(&node_id).cloned() {
+    pat_util::pat_bindings(def_map, &*arg.pat, |_, node_id, span, var_ident| {
+        let datum = match locals.get(&node_id) {
             Some(v) => v,
             None => {
                 bcx.sess().span_bug(span,
@@ -1027,28 +1032,72 @@ pub fn create_argument_metadata(bcx: Block, arg: &ast::Arg) {
             }
         };
 
-        if unsafe { llvm::LLVMIsAAllocaInst(llarg.val) } == ptr::null_mut() {
-            cx.sess().span_bug(span, "debuginfo::create_argument_metadata() - \
-                                    Referenced variable location is not an alloca!");
+        if unsafe { llvm::LLVMIsAAllocaInst(datum.val) } == ptr::null_mut() {
+            bcx.sess().span_bug(span, "debuginfo::create_argument_metadata() - \
+                                       Referenced variable location is not an alloca!");
         }
 
         let argument_index = {
-            let counter = &fcx.debug_context.get_ref(cx, span).argument_counter;
+            let counter = &bcx
+                          .fcx
+                          .debug_context
+                          .get_ref(bcx.ccx(), span)
+                          .argument_counter;
             let argument_index = counter.get();
             counter.set(argument_index + 1);
             argument_index
         };
 
         declare_local(bcx,
-                      path1.node,
-                      llarg.ty,
+                      var_ident.node,
+                      datum.ty,
                       scope_metadata,
-                      DirectVariable { alloca: llarg.val },
+                      DirectVariable { alloca: datum.val },
                       ArgumentVariable(argument_index),
                       span);
     })
 }
 
+/// Creates debug information for the given for-loop variable.
+///
+/// This function assumes that there's a datum for each pattern component of the
+/// loop variable in `bcx.fcx.lllocals`.
+/// Adds the created metadata nodes directly to the crate's IR.
+pub fn create_for_loop_var_metadata(bcx: Block, pat: &ast::Pat) {
+    if fn_should_be_ignored(bcx.fcx) {
+        return;
+    }
+
+    let def_map = &bcx.tcx().def_map;
+    let locals = bcx.fcx.lllocals.borrow();
+
+    pat_util::pat_bindings(def_map, pat, |_, node_id, span, var_ident| {
+        let datum = match locals.get(&node_id) {
+            Some(datum) => datum,
+            None => {
+                bcx.sess().span_bug(span,
+                    format!("no entry in lllocals table for {}",
+                            node_id).as_slice());
+            }
+        };
+
+        if unsafe { llvm::LLVMIsAAllocaInst(datum.val) } == ptr::null_mut() {
+            bcx.sess().span_bug(span, "debuginfo::create_for_loop_var_metadata() - \
+                                       Referenced variable location is not an alloca!");
+        }
+
+        let scope_metadata = scope_metadata(bcx.fcx, node_id, span);
+
+        declare_local(bcx,
+                      var_ident.node,
+                      datum.ty,
+                      scope_metadata,
+                      DirectVariable { alloca: datum.val },
+                      LocalVariable,
+                      span);
+    })
+}
+
 pub fn get_cleanup_debug_loc_for_ast_node<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                                     node_id: ast::NodeId,
                                                     node_span: Span,
@@ -1117,13 +1166,13 @@ pub fn get_cleanup_debug_loc_for_ast_node<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 pub fn set_source_location(fcx: &FunctionContext,
                            node_id: ast::NodeId,
                            span: Span) {
-    match fcx.debug_context.repr {
-        DebugInfoDisabled => return,
-        FunctionWithoutDebugInfo => {
+    match fcx.debug_context {
+        FunctionDebugContext::DebugInfoDisabled => return,
+        FunctionDebugContext::FunctionWithoutDebugInfo => {
             set_debug_location(fcx.ccx, UnknownLocation);
             return;
         }
-        DebugInfo(box ref function_debug_context) => {
+        FunctionDebugContext::RegularContext(box ref function_debug_context) => {
             let cx = fcx.ccx;
 
             debug!("set_source_location: {}", cx.sess().codemap().span_to_string(span));
@@ -1160,8 +1209,8 @@ pub fn clear_source_location(fcx: &FunctionContext) {
 /// switches source location emitting on and must therefore be called before the
 /// first real statement/expression of the function is translated.
 pub fn start_emitting_source_locations(fcx: &FunctionContext) {
-    match fcx.debug_context.repr {
-        DebugInfo(box ref data) => {
+    match fcx.debug_context {
+        FunctionDebugContext::RegularContext(box ref data) => {
             data.source_locations_enabled.set(true)
         },
         _ => { /* safe to ignore */ }
@@ -1179,7 +1228,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                                param_substs: &Substs<'tcx>,
                                                llfn: ValueRef) -> FunctionDebugContext {
     if cx.sess().opts.debuginfo == NoDebugInfo {
-        return FunctionDebugContext { repr: DebugInfoDisabled };
+        return FunctionDebugContext::DebugInfoDisabled;
     }
 
     // Clear the debug location so we don't assign them in the function prelude.
@@ -1189,7 +1238,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     if fn_ast_id == ast::DUMMY_NODE_ID {
         // This is a function not linked to any source location, so don't
         // generate debuginfo for it.
-        return FunctionDebugContext { repr: FunctionWithoutDebugInfo };
+        return FunctionDebugContext::FunctionWithoutDebugInfo;
     }
 
     let empty_generics = ast_util::empty_generics();
@@ -1199,7 +1248,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     let (ident, fn_decl, generics, top_level_block, span, has_path) = match fnitem {
         ast_map::NodeItem(ref item) => {
             if contains_nodebug_attribute(item.attrs.as_slice()) {
-                return FunctionDebugContext { repr: FunctionWithoutDebugInfo };
+                return FunctionDebugContext::FunctionWithoutDebugInfo;
             }
 
             match item.node {
@@ -1216,9 +1265,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             match **item {
                 ast::MethodImplItem(ref method) => {
                     if contains_nodebug_attribute(method.attrs.as_slice()) {
-                        return FunctionDebugContext {
-                            repr: FunctionWithoutDebugInfo
-                        };
+                        return FunctionDebugContext::FunctionWithoutDebugInfo;
                     }
 
                     (method.pe_ident(),
@@ -1257,9 +1304,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             match **trait_method {
                 ast::ProvidedMethod(ref method) => {
                     if contains_nodebug_attribute(method.attrs.as_slice()) {
-                        return FunctionDebugContext {
-                            repr: FunctionWithoutDebugInfo
-                        };
+                        return FunctionDebugContext::FunctionWithoutDebugInfo;
                     }
 
                     (method.pe_ident(),
@@ -1280,7 +1325,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         ast_map::NodeForeignItem(..) |
         ast_map::NodeVariant(..) |
         ast_map::NodeStructCtor(..) => {
-            return FunctionDebugContext { repr: FunctionWithoutDebugInfo };
+            return FunctionDebugContext::FunctionWithoutDebugInfo;
         }
         _ => cx.sess().bug(format!("create_function_debug_context: \
                                     unexpected sort of node: {}",
@@ -1289,7 +1334,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
     // This can be the case for functions inlined from another crate
     if span == codemap::DUMMY_SP {
-        return FunctionDebugContext { repr: FunctionWithoutDebugInfo };
+        return FunctionDebugContext::FunctionWithoutDebugInfo;
     }
 
     let loc = span_start(cx, span);
@@ -1356,22 +1401,23 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         })
     });
 
+    let scope_map = create_scope_map(cx,
+                                     fn_decl.inputs.as_slice(),
+                                     &*top_level_block,
+                                     fn_metadata,
+                                     fn_ast_id);
+
     // Initialize fn debug context (including scope map and namespace map)
     let fn_debug_context = box FunctionDebugContextData {
-        scope_map: RefCell::new(NodeMap::new()),
+        scope_map: RefCell::new(scope_map),
         fn_metadata: fn_metadata,
         argument_counter: Cell::new(1),
         source_locations_enabled: Cell::new(false),
     };
 
-    populate_scope_map(cx,
-                       fn_decl.inputs.as_slice(),
-                       &*top_level_block,
-                       fn_metadata,
-                       fn_ast_id,
-                       &mut *fn_debug_context.scope_map.borrow_mut());
 
-    return FunctionDebugContext { repr: DebugInfo(fn_debug_context) };
+
+    return FunctionDebugContext::RegularContext(fn_debug_context);
 
     fn get_function_signature<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                         fn_ast_id: ast::NodeId,
@@ -3134,8 +3180,8 @@ fn DIB(cx: &CrateContext) -> DIBuilderRef {
 }
 
 fn fn_should_be_ignored(fcx: &FunctionContext) -> bool {
-    match fcx.debug_context.repr {
-        DebugInfo(_) => false,
+    match fcx.debug_context {
+        FunctionDebugContext::RegularContext(_) => false,
         _ => true
     }
 }
@@ -3169,12 +3215,14 @@ fn get_namespace_and_span_for_item(cx: &CrateContext, def_id: ast::DefId)
 // what belongs to which scope, creating DIScope DIEs along the way, and
 // introducing *artificial* lexical scope descriptors where necessary. These
 // artificial scopes allow GDB to correctly handle name shadowing.
-fn populate_scope_map(cx: &CrateContext,
-                      args: &[ast::Arg],
-                      fn_entry_block: &ast::Block,
-                      fn_metadata: DISubprogram,
-                      fn_ast_id: ast::NodeId,
-                      scope_map: &mut NodeMap<DIScope>) {
+fn create_scope_map(cx: &CrateContext,
+                    args: &[ast::Arg],
+                    fn_entry_block: &ast::Block,
+                    fn_metadata: DISubprogram,
+                    fn_ast_id: ast::NodeId)
+                 -> NodeMap<DIScope> {
+    let mut scope_map = NodeMap::new();
+
     let def_map = &cx.tcx().def_map;
 
     struct ScopeStackEntry {
@@ -3200,11 +3248,14 @@ fn populate_scope_map(cx: &CrateContext,
     with_new_scope(cx,
                    fn_entry_block.span,
                    &mut scope_stack,
-                   scope_map,
+                   &mut scope_map,
                    |cx, scope_stack, scope_map| {
         walk_block(cx, fn_entry_block, scope_stack, scope_map);
     });
 
+    return scope_map;
+
+
     // local helper functions for walking the AST.
     fn with_new_scope<F>(cx: &CrateContext,
                          scope_span: Span,
@@ -3440,7 +3491,7 @@ fn populate_scope_map(cx: &CrateContext,
             }
 
             ast::PatMac(_) => {
-                cx.sess().span_bug(pat.span, "debuginfo::populate_scope_map() - \
+                cx.sess().span_bug(pat.span, "debuginfo::create_scope_map() - \
                                               Found unexpanded macro.");
             }
         }
@@ -3531,7 +3582,7 @@ fn populate_scope_map(cx: &CrateContext,
             }
 
             ast::ExprIfLet(..) => {
-                cx.sess().span_bug(exp.span, "debuginfo::populate_scope_map() - \
+                cx.sess().span_bug(exp.span, "debuginfo::create_scope_map() - \
                                               Found unexpanded if-let.");
             }
 
@@ -3548,7 +3599,7 @@ fn populate_scope_map(cx: &CrateContext,
             }
 
             ast::ExprWhileLet(..) => {
-                cx.sess().span_bug(exp.span, "debuginfo::populate_scope_map() - \
+                cx.sess().span_bug(exp.span, "debuginfo::create_scope_map() - \
                                               Found unexpanded while-let.");
             }
 
@@ -3573,7 +3624,7 @@ fn populate_scope_map(cx: &CrateContext,
             }
 
             ast::ExprMac(_) => {
-                cx.sess().span_bug(exp.span, "debuginfo::populate_scope_map() - \
+                cx.sess().span_bug(exp.span, "debuginfo::create_scope_map() - \
                                               Found unexpanded macro.");
             }
 
diff --git a/src/test/debuginfo/destructured-for-loop-variable.rs b/src/test/debuginfo/destructured-for-loop-variable.rs
new file mode 100644
index 00000000000..9935bb60364
--- /dev/null
+++ b/src/test/debuginfo/destructured-for-loop-variable.rs
@@ -0,0 +1,219 @@
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-android: FIXME(#10381)
+// min-lldb-version: 310
+
+// compile-flags:-g
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command:run
+
+// DESTRUCTURED STRUCT
+// gdb-command:print x
+// gdb-check:$1 = 400
+// gdb-command:print y
+// gdb-check:$2 = 401.5
+// gdb-command:print z
+// gdb-check:$3 = true
+// gdb-command:continue
+
+// DESTRUCTURED TUPLE
+// gdb-command:print/x _i8
+// gdb-check:$4 = 0x6f
+// gdb-command:print/x _u8
+// gdb-check:$5 = 0x70
+// gdb-command:print _i16
+// gdb-check:$6 = -113
+// gdb-command:print _u16
+// gdb-check:$7 = 114
+// gdb-command:print _i32
+// gdb-check:$8 = -115
+// gdb-command:print _u32
+// gdb-check:$9 = 116
+// gdb-command:print _i64
+// gdb-check:$10 = -117
+// gdb-command:print _u64
+// gdb-check:$11 = 118
+// gdb-command:print _f32
+// gdb-check:$12 = 119.5
+// gdb-command:print _f64
+// gdb-check:$13 = 120.5
+// gdb-command:continue
+
+// MORE COMPLEX CASE
+// gdb-command:print v1
+// gdb-check:$14 = 80000
+// gdb-command:print x1
+// gdb-check:$15 = 8000
+// gdb-command:print *y1
+// gdb-check:$16 = 80001.5
+// gdb-command:print z1
+// gdb-check:$17 = false
+// gdb-command:print *x2
+// gdb-check:$18 = -30000
+// gdb-command:print y2
+// gdb-check:$19 = -300001.5
+// gdb-command:print *z2
+// gdb-check:$20 = true
+// gdb-command:print v2
+// gdb-check:$21 = 854237.5
+// gdb-command:continue
+
+// SIMPLE IDENTIFIER
+// gdb-command:print i
+// gdb-check:$22 = 1234
+// gdb-command:continue
+
+// gdb-command:print simple_struct_ident
+// gdb-check:$23 = {x = 3537, y = 35437.5, z = true}
+// gdb-command:continue
+
+// gdb-command:print simple_tuple_ident
+// gdb-check:$24 = {34903493, 232323}
+// gdb-command:continue
+
+// === LLDB TESTS ==================================================================================
+
+// lldb-command:type format add --format hex char
+// lldb-command:type format add --format hex 'unsigned char'
+
+// lldb-command:run
+
+// DESTRUCTURED STRUCT
+// lldb-command:print x
+// lldb-check:[...]$0 = 400
+// lldb-command:print y
+// lldb-check:[...]$1 = 401.5
+// lldb-command:print z
+// lldb-check:[...]$2 = true
+// lldb-command:continue
+
+// DESTRUCTURED TUPLE
+// lldb-command:print _i8
+// lldb-check:[...]$3 = 0x6f
+// lldb-command:print _u8
+// lldb-check:[...]$4 = 0x70
+// lldb-command:print _i16
+// lldb-check:[...]$5 = -113
+// lldb-command:print _u16
+// lldb-check:[...]$6 = 114
+// lldb-command:print _i32
+// lldb-check:[...]$7 = -115
+// lldb-command:print _u32
+// lldb-check:[...]$8 = 116
+// lldb-command:print _i64
+// lldb-check:[...]$9 = -117
+// lldb-command:print _u64
+// lldb-check:[...]$10 = 118
+// lldb-command:print _f32
+// lldb-check:[...]$11 = 119.5
+// lldb-command:print _f64
+// lldb-check:[...]$12 = 120.5
+// lldb-command:continue
+
+// MORE COMPLEX CASE
+// lldb-command:print v1
+// lldb-check:[...]$13 = 80000
+// lldb-command:print x1
+// lldb-check:[...]$14 = 8000
+// lldb-command:print *y1
+// lldb-check:[...]$15 = 80001.5
+// lldb-command:print z1
+// lldb-check:[...]$16 = false
+// lldb-command:print *x2
+// lldb-check:[...]$17 = -30000
+// lldb-command:print y2
+// lldb-check:[...]$18 = -300001.5
+// lldb-command:print *z2
+// lldb-check:[...]$19 = true
+// lldb-command:print v2
+// lldb-check:[...]$20 = 854237.5
+// lldb-command:continue
+
+// SIMPLE IDENTIFIER
+// lldb-command:print i
+// lldb-check:[...]$21 = 1234
+// lldb-command:continue
+
+// lldb-command:print simple_struct_ident
+// lldb-check:[...]$22 = Struct { x: 3537, y: 35437.5, z: true }
+// lldb-command:continue
+
+// lldb-command:print simple_tuple_ident
+// lldb-check:[...]$23 = (34903493, 232323)
+// lldb-command:continue
+
+struct Struct {
+    x: i16,
+    y: f32,
+    z: bool
+}
+
+fn main() {
+
+    let s = Struct {
+        x: 400,
+        y: 401.5,
+        z: true
+    };
+
+    for &Struct { x, y, z } in [s].iter() {
+        zzz(); // #break
+    }
+
+    let tuple: (i8, u8, i16, u16, i32, u32, i64, u64, f32, f64) =
+        (0x6f, 0x70, -113, 114, -115, 116, -117, 118, 119.5, 120.5);
+
+    for &(_i8, _u8, _i16, _u16, _i32, _u32, _i64, _u64, _f32, _f64) in [tuple].iter() {
+        zzz(); // #break
+    }
+
+    let more_complex: (i32, &Struct, Struct, Box<f64>) =
+        (80000,
+         &Struct {
+            x: 8000,
+            y: 80001.5,
+            z: false
+         },
+         Struct {
+            x: -30000,
+            y: -300001.5,
+            z: true
+         },
+         box 854237.5);
+
+    for &(v1,
+          &Struct { x: x1, y: ref y1, z: z1 },
+          Struct { x: ref x2, y: y2, z: ref z2 },
+          box v2) in [more_complex].iter() {
+        zzz(); // #break
+    }
+
+    for i in range(1234, 1235i) {
+        zzz(); // #break
+    }
+
+    for simple_struct_ident in
+      vec![Struct {
+            x: 3537,
+            y: 35437.5,
+            z: true
+           }].into_iter() {
+      zzz(); // #break
+    }
+
+    for simple_tuple_ident in vec![(34903493u32, 232323i64)].into_iter() {
+      zzz(); // #break
+    }
+}
+
+fn zzz() {()}
diff --git a/src/test/debuginfo/lexical-scope-in-for-loop.rs b/src/test/debuginfo/lexical-scope-in-for-loop.rs
index bcaebb5c153..7636ffdb07d 100644
--- a/src/test/debuginfo/lexical-scope-in-for-loop.rs
+++ b/src/test/debuginfo/lexical-scope-in-for-loop.rs
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 // ignore-android: FIXME(#10381)
-// ignore-test: Not sure what is going on here --pcwalton
 // min-lldb-version: 310
 
 // compile-flags:-g