tberghammer created this revision.
tberghammer added a reviewer: clayborg.
tberghammer added a subscriber: lldb-commits.

Fix expression evaluation inside lambda functions for gcc

gcc emits the artificial struct created for lambda expressions inside a
lexical block what is not understood by clang (it emits them at the
compile unit level). This CL changes the dwarf parsing code to move
types defined inside a lexical block to the first parent what is not a
lexical block to avoid this clang limitation. This will make the
experience between clang and gcc consistent as clang moves these types
out of the lexical blocks before emitting the debug info.


https://reviews.llvm.org/D27394

Files:
  packages/Python/lldbsuite/test/expression_command/lambda/Makefile
  packages/Python/lldbsuite/test/expression_command/lambda/TestLambda.py
  packages/Python/lldbsuite/test/expression_command/lambda/main.cpp
  source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp

Index: source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -3777,7 +3777,37 @@
     const DWARFDIE &die, DWARFDIE *decl_ctx_die_copy) {
   SymbolFileDWARF *dwarf = die.GetDWARF();
 
+  bool is_type = false;
+  switch (die.Tag()) {
+    case DW_TAG_base_type:
+    case DW_TAG_class_type:
+    case DW_TAG_const_type:
+    case DW_TAG_pointer_type:
+    case DW_TAG_reference_type:
+    case DW_TAG_restrict_type:
+    case DW_TAG_rvalue_reference_type:
+    case DW_TAG_structure_type:
+    case DW_TAG_typedef:
+    case DW_TAG_union_type:
+    case DW_TAG_unspecified_type:
+    case DW_TAG_volatile_type:
+      is_type = true;
+      break;
+    default:
+      break;
+  }
+
   DWARFDIE decl_ctx_die = dwarf->GetDeclContextDIEContainingDIE(die);
+  if (is_type) {
+    // The clang AST importer can't handle types declared inside a BlockDecl.
+    // Move these declarartions into the parent context of the block. This will
+    // make the behavior from gcc (what emits type information inside lexical
+    // blocks) consistent with the way clang emits debug info for types defined
+    // inside a function (class, namespace or compile unit level).
+    while (decl_ctx_die.Tag() == DW_TAG_lexical_block) {
+      decl_ctx_die = dwarf->GetDeclContextDIEContainingDIE(decl_ctx_die);
+    }
+  }
 
   if (decl_ctx_die_copy)
     *decl_ctx_die_copy = decl_ctx_die;
Index: packages/Python/lldbsuite/test/expression_command/lambda/main.cpp
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/expression_command/lambda/main.cpp
@@ -0,0 +1,6 @@
+int main() {
+  auto l = [](int a, int b) {
+    return a + b; // Break here 1
+  };
+  return l(123, 456); // Break here 2
+}
Index: packages/Python/lldbsuite/test/expression_command/lambda/TestLambda.py
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/expression_command/lambda/TestLambda.py
@@ -0,0 +1,73 @@
+from __future__ import print_function
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class LambdaTestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+
+        self.main_source = "main.cpp"
+        self.main_source_spec = lldb.SBFileSpec(self.main_source)
+        self.exe = os.path.join(os.getcwd(), "a.out")
+
+    def test_expression_inside_lambda(self):
+        self.build()
+
+        target = self.dbg.CreateTarget(self.exe)
+        self.assertTrue(target)
+
+        breakpoint = target.BreakpointCreateBySourceRegex(
+            '// Break here 1', self.main_source_spec)
+        self.assertTrue(breakpoint)
+
+        # Launch the process, and do not stop at the entry point.
+        process = target.LaunchSimple(
+            None, None, self.get_process_working_directory())
+        self.assertTrue(process)
+
+        threads = lldbutil.get_threads_stopped_at_breakpoint(
+            process, breakpoint)
+        self.assertEqual(len(threads), 1)
+
+        frame = threads[0].GetFrameAtIndex(0)
+
+        value = frame.EvaluateExpression("a + b")
+        self.assertTrue(value.IsValid())
+        self.assertTrue(value.GetError().Success())
+        self.assertEqual(value.GetValueAsSigned(0), 579)
+
+    @expectedFailureAll(compiler="gcc")
+    def test_expression_call_lambda(self):
+        self.build()
+
+        target = self.dbg.CreateTarget(self.exe)
+        self.assertTrue(target)
+
+        breakpoint = target.BreakpointCreateBySourceRegex(
+            '// Break here 2', self.main_source_spec)
+        self.assertTrue(breakpoint)
+
+        # Launch the process, and do not stop at the entry point.
+        process = target.LaunchSimple(
+            None, None, self.get_process_working_directory())
+        self.assertTrue(process)
+
+        threads = lldbutil.get_threads_stopped_at_breakpoint(
+            process, breakpoint)
+        self.assertEqual(len(threads), 1)
+
+        frame = threads[0].GetFrameAtIndex(0)
+
+        value = frame.EvaluateExpression("l(321, 654)")
+        self.assertTrue(value.IsValid())
+        self.assertTrue(value.GetError().Success())
+        self.assertEqual(value.GetValueAsSigned(0), 975)
+
Index: packages/Python/lldbsuite/test/expression_command/lambda/Makefile
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/expression_command/lambda/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to