REPOSITORY
  rL LLVM

http://reviews.llvm.org/D8561

Files:
  lldb/trunk/include/lldb/Expression/ClangASTSource.h
  lldb/trunk/source/Expression/ClangASTSource.cpp
  lldb/trunk/source/Symbol/ClangASTImporter.cpp
  lldb/trunk/test/types/TestRecursiveTypes.py
  lldb/trunk/test/types/recursive_type_1.cpp
  lldb/trunk/test/types/recursive_type_2.cpp
  lldb/trunk/test/types/recursive_type_main.cpp

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
Index: lldb/trunk/include/lldb/Expression/ClangASTSource.h
===================================================================
--- lldb/trunk/include/lldb/Expression/ClangASTSource.h
+++ lldb/trunk/include/lldb/Expression/ClangASTSource.h
@@ -51,6 +51,7 @@
         m_lookups_enabled (false),
         m_target (target),
         m_ast_context (NULL),
+        m_active_lexical_decls (),
         m_active_lookups ()
     {
         m_ast_importer = m_target->GetClangASTImporter();
@@ -404,6 +405,7 @@
     const lldb::TargetSP                m_target;           ///< The target to use in finding variables and types.
     clang::ASTContext                  *m_ast_context;      ///< The AST context requests are coming in for.
     ClangASTImporter                   *m_ast_importer;     ///< The target's AST importer.
+    std::set<const clang::Decl *>       m_active_lexical_decls;
     std::set<const char *>              m_active_lookups;
 };
 
Index: lldb/trunk/source/Expression/ClangASTSource.cpp
===================================================================
--- lldb/trunk/source/Expression/ClangASTSource.cpp
+++ lldb/trunk/source/Expression/ClangASTSource.cpp
@@ -30,6 +30,31 @@
 using namespace clang;
 using namespace lldb_private;
 
+//------------------------------------------------------------------
+// Scoped class that will remove an active lexical decl from the set
+// when it goes out of scope.
+//------------------------------------------------------------------
+namespace {
+    class ScopedLexicalDeclEraser
+    {
+    public:
+        ScopedLexicalDeclEraser(std::set<const clang::Decl *> &decls,
+                                const clang::Decl *decl)
+            : m_active_lexical_decls(decls), m_decl(decl)
+        {
+        }
+
+        ~ScopedLexicalDeclEraser()
+        {
+            m_active_lexical_decls.erase(m_decl);
+        }
+
+    private:
+        std::set<const clang::Decl *> &m_active_lexical_decls;
+        const clang::Decl *m_decl;
+    };
+}
+
 ClangASTSource::~ClangASTSource()
 {
     m_ast_importer->ForgetDestination(m_ast_context);
@@ -191,6 +216,12 @@
         dumper.ToLog(log, "      [CTD] ");
     }
 
+    auto iter = m_active_lexical_decls.find(tag_decl);
+    if (iter != m_active_lexical_decls.end())
+        return;
+    m_active_lexical_decls.insert(tag_decl);
+    ScopedLexicalDeclEraser eraser(m_active_lexical_decls, tag_decl);
+
     if (!m_ast_importer->CompleteTagDecl (tag_decl))
     {
         // We couldn't complete the type.  Maybe there's a definition
@@ -402,6 +433,12 @@
     if (!context_decl)
         return ELR_Failure;
 
+    auto iter = m_active_lexical_decls.find(context_decl);
+    if (iter != m_active_lexical_decls.end())
+        return ELR_Failure;
+    m_active_lexical_decls.insert(context_decl);
+    ScopedLexicalDeclEraser eraser(m_active_lexical_decls, context_decl);
+
     static unsigned int invocation_id = 0;
     unsigned int current_id = invocation_id++;
 
Index: lldb/trunk/source/Symbol/ClangASTImporter.cpp
===================================================================
--- lldb/trunk/source/Symbol/ClangASTImporter.cpp
+++ lldb/trunk/source/Symbol/ClangASTImporter.cpp
@@ -286,7 +286,12 @@
     
     if (const TagType *tag_type = type->getAs<TagType>())
     {
-        return CompleteTagDecl(tag_type->getDecl());
+        TagDecl *tag_decl = tag_type->getDecl();
+
+        if (tag_decl->getDefinition() || tag_decl->isBeingDefined())
+            return true;
+
+        return CompleteTagDecl(tag_decl);
     }
     if (const ObjCObjectType *objc_object_type = type->getAs<ObjCObjectType>())
     {
Index: lldb/trunk/test/types/TestRecursiveTypes.py
===================================================================
--- lldb/trunk/test/types/TestRecursiveTypes.py
+++ lldb/trunk/test/types/TestRecursiveTypes.py
@@ -0,0 +1,68 @@
+"""
+Test that recursive types are handled correctly.
+"""
+
+import lldb
+import lldbutil
+import sys
+import unittest2
+from lldbtest import *
+
+class RecursiveTypesTestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        # disable "There is a running process, kill it and restart?" prompt
+        self.runCmd("settings set auto-confirm true")
+        self.addTearDownHook(lambda: self.runCmd("settings clear auto-confirm"))
+        # Find the line number to break for main.c.
+        self.line = line_number('recursive_type_main.cpp',
+                                '// Test at this line.')
+
+        self.d1 = {'CXX_SOURCES': 'recursive_type_main.cpp recursive_type_1.cpp'}
+        self.d2 = {'CXX_SOURCES': 'recursive_type_main.cpp recursive_type_2.cpp'}
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @dsym_test
+    def test_recursive_dsym_type_1(self):
+        """Test that recursive structs are displayed correctly."""
+        self.buildDsym(dictionary=self.d1)
+        self.print_struct()
+
+    @dwarf_test
+    def test_recursive_dwarf_type_1(self):
+        """Test that recursive structs are displayed correctly."""
+        self.buildDwarf(dictionary=self.d1)
+        self.print_struct()
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @dsym_test
+    def test_recursive_dsym_type_2(self):
+        """Test that recursive structs are displayed correctly."""
+        self.buildDsym(dictionary=self.d2)
+        self.print_struct()
+
+    @dwarf_test
+    def test_recursive_dwarf_type_2(self):
+        """Test that recursive structs are displayed correctly."""
+        self.buildDwarf(dictionary=self.d2)
+        self.print_struct()
+
+    def print_struct(self):
+        self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
+
+        lldbutil.run_break_set_by_file_and_line (self, "recursive_type_main.cpp", self.line, num_expected_locations=-1, loc_exact=True)
+
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        self.expect("print tpi", RUN_SUCCEEDED)
+        self.expect("print *tpi", RUN_SUCCEEDED)
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()
Index: lldb/trunk/test/types/recursive_type_main.cpp
===================================================================
--- lldb/trunk/test/types/recursive_type_main.cpp
+++ lldb/trunk/test/types/recursive_type_main.cpp
@@ -0,0 +1,8 @@
+typedef struct t *tp;
+extern struct t t;
+
+int main() {
+    tp tpi = &t;
+    // Test at this line.
+    return 0;
+}
Index: lldb/trunk/test/types/recursive_type_1.cpp
===================================================================
--- lldb/trunk/test/types/recursive_type_1.cpp
+++ lldb/trunk/test/types/recursive_type_1.cpp
@@ -0,0 +1,12 @@
+typedef struct t *tp;
+typedef tp (*get_tp)();
+
+struct s {
+    get_tp get_tp_p;
+};
+
+struct t {
+    struct s *s;
+};
+
+struct t t;
Index: lldb/trunk/test/types/recursive_type_2.cpp
===================================================================
--- lldb/trunk/test/types/recursive_type_2.cpp
+++ lldb/trunk/test/types/recursive_type_2.cpp
@@ -0,0 +1,10 @@
+typedef struct t *tp;
+typedef tp (*get_tp)();
+
+struct t {
+    struct {
+      get_tp get_tp_p;
+    };
+};
+
+struct t t;
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits

Reply via email to