friss updated this revision to Diff 138733.
friss added a comment.

I experimented quite a bit with different approches to fix this bug
without always completing the types right after importing them from
the external AST.

This is the most principled approach I came up with. I applied the
new helper in only one place (the only one we have seen failing),
but we could potentially find more uses for it in the future.


https://reviews.llvm.org/D43592

Files:
  packages/Python/lldbsuite/test/lang/cpp/gmodules/TestWithModuleDebugging.py
  packages/Python/lldbsuite/test/lang/cpp/gmodules/main.cpp
  packages/Python/lldbsuite/test/lang/cpp/gmodules/pch.h
  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
@@ -179,12 +179,6 @@
   lldb_private::CompilerType type =
       GetClangASTImporter().CopyType(m_ast, dwo_type);
 
-  // printf ("copied_qual_type: ast = %p, clang_type = %p, name =
-  // '%s'\n", m_ast, copied_qual_type.getAsOpaquePtr(),
-  // external_type->GetName().GetCString());
-  if (!type)
-    return TypeSP();
-
   SymbolFileDWARF *dwarf = die.GetDWARF();
   TypeSP type_sp(new Type(
       die.GetID(), dwarf, dwo_type_sp->GetName(), dwo_type_sp->GetByteSize(),
@@ -205,6 +199,33 @@
   return type_sp;
 }
 
+static void CompleteExternalTagDeclType(ClangASTImporter &ast_importer,
+                                        clang::DeclContext *decl_ctx,
+                                        DWARFDIE die,
+                                        const char *type_name_cstr) {
+  auto *tag_decl_ctx = clang::dyn_cast<clang::TagDecl>(decl_ctx);
+  if (!tag_decl_ctx)
+    return;
+
+  // If this type was not imported from an external AST, there's
+  // nothing to do.
+  CompilerType type = ClangASTContext::GetTypeForDecl(tag_decl_ctx);
+  if (!type || !ast_importer.CanImport(type))
+    return;
+
+  auto qual_type = ClangUtil::GetQualType(type);
+  if (!ast_importer.RequireCompleteType(qual_type)) {
+    die.GetDWARF()->GetObjectFile()->GetModule()->ReportError(
+        "Unable to complete the Decl context for DIE '%s' at offset "
+        "0x%8.8x.\nPlease file a bug report.",
+        type_name_cstr ?: "", die.GetOffset());
+    // We need to make the type look complete otherwise, we
+    // might crash in Clang when adding children.
+    if (ClangASTContext::StartTagDeclarationDefinition(type))
+      ClangASTContext::CompleteTagDeclarationDefinition(type);
+  }
+}
+
 TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc,
                                                const DWARFDIE &die, Log *log,
                                                bool *type_is_new_ptr) {
@@ -795,6 +816,16 @@
         if (!clang_type) {
           clang::DeclContext *decl_ctx =
               GetClangDeclContextContainingDIE(die, nullptr);
+
+          // If your decl context is a record that was imported from
+          // another AST context (in the gmodules case), we need to
+          // make sure the type backing the Decl is complete before
+          // adding children to it. This is not an issue in the
+          // non-gmodules case because the debug info will always contain
+          // a full definition of parent types in that case.
+          CompleteExternalTagDeclType(GetClangASTImporter(), decl_ctx, die,
+                                      type_name_cstr);
+
           if (accessibility == eAccessNone && decl_ctx) {
             // Check the decl context that contains this class/struct/union.
             // If it is a class we must give it an accessibility.
Index: packages/Python/lldbsuite/test/lang/cpp/gmodules/pch.h
===================================================================
--- packages/Python/lldbsuite/test/lang/cpp/gmodules/pch.h
+++ packages/Python/lldbsuite/test/lang/cpp/gmodules/pch.h
@@ -10,3 +10,8 @@
 };
 
 typedef GenericContainer<int> IntContainer;
+
+struct Foo {
+  class Bar;
+  Bar *bar;
+};
Index: packages/Python/lldbsuite/test/lang/cpp/gmodules/main.cpp
===================================================================
--- packages/Python/lldbsuite/test/lang/cpp/gmodules/main.cpp
+++ packages/Python/lldbsuite/test/lang/cpp/gmodules/main.cpp
@@ -1,5 +1,8 @@
+class Foo::Bar { int i = 123; };
+
 int main(int argc, const char * argv[])
 {
     IntContainer test(42);
+    Foo::Bar bar;
     return 0; // break here
 }
Index: packages/Python/lldbsuite/test/lang/cpp/gmodules/TestWithModuleDebugging.py
===================================================================
--- packages/Python/lldbsuite/test/lang/cpp/gmodules/TestWithModuleDebugging.py
+++ packages/Python/lldbsuite/test/lang/cpp/gmodules/TestWithModuleDebugging.py
@@ -69,3 +69,26 @@
             42,
             memberValue.GetValueAsSigned(),
             "Member value incorrect")
+
+        testValue = frame.EvaluateExpression("bar")
+        self.assertTrue(
+            testValue.GetError().Success(),
+            "Test expression value invalid: %s" %
+            (testValue.GetError().GetCString()))
+        self.assertTrue(
+            testValue.GetTypeName() == "Foo::Bar",
+            "Test expression type incorrect")
+
+        memberValue = testValue.GetChildMemberWithName("i")
+        self.assertTrue(
+            memberValue.GetError().Success(),
+            "Member value missing or invalid: %s" %
+            (testValue.GetError().GetCString()))
+        self.assertTrue(
+            memberValue.GetTypeName() == "int",
+            "Member type incorrect")
+        self.assertEqual(
+            123,
+            memberValue.GetValueAsSigned(),
+            "Member value incorrect")
+
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to