labath updated this revision to Diff 270097.
labath added a comment.
add more comments and logging
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D81561/new/
https://reviews.llvm.org/D81561
Files:
lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h
lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h
lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp
lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
lldb/test/API/functionalities/limit-debug-info/Makefile
lldb/test/API/functionalities/limit-debug-info/TestLimitDebugInfo.py
lldb/test/API/functionalities/limit-debug-info/foo.cpp
lldb/test/API/functionalities/limit-debug-info/main.cpp
lldb/test/API/functionalities/limit-debug-info/one.cpp
lldb/test/API/functionalities/limit-debug-info/onetwo.h
lldb/test/API/functionalities/limit-debug-info/two.cpp
Index: lldb/test/API/functionalities/limit-debug-info/two.cpp
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/limit-debug-info/two.cpp
@@ -0,0 +1,3 @@
+#include "onetwo.h"
+
+Two::~Two() = default;
Index: lldb/test/API/functionalities/limit-debug-info/onetwo.h
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/limit-debug-info/onetwo.h
@@ -0,0 +1,11 @@
+struct One {
+ int one = 142;
+ constexpr One() = default;
+ virtual ~One();
+};
+
+struct Two : One {
+ int two = 242;
+ constexpr Two() = default;
+ ~Two() override;
+};
Index: lldb/test/API/functionalities/limit-debug-info/one.cpp
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/limit-debug-info/one.cpp
@@ -0,0 +1,3 @@
+#include "onetwo.h"
+
+One::~One() = default;
Index: lldb/test/API/functionalities/limit-debug-info/main.cpp
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/limit-debug-info/main.cpp
@@ -0,0 +1,13 @@
+#include "onetwo.h"
+
+struct InheritsFromOne : One {
+ constexpr InheritsFromOne() = default;
+ int member = 47;
+} inherits_from_one;
+
+struct InheritsFromTwo : Two {
+ constexpr InheritsFromTwo() = default;
+ int member = 47;
+} inherits_from_two;
+
+int main() { return 0; }
Index: lldb/test/API/functionalities/limit-debug-info/foo.cpp
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/limit-debug-info/foo.cpp
@@ -0,0 +1,6 @@
+struct A {
+ int a = 47;
+ virtual ~A();
+};
+
+A::~A() = default;
Index: lldb/test/API/functionalities/limit-debug-info/TestLimitDebugInfo.py
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/limit-debug-info/TestLimitDebugInfo.py
@@ -0,0 +1,85 @@
+"""
+Test completing types using information from other shared libraries.
+"""
+
+import os
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class LimitDebugInfoTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ def _check_type(self, target, name):
+ exe = target.FindModule(lldb.SBFileSpec("a.out"))
+ the_type = exe.FindFirstType(name)
+ self.assertTrue(the_type)
+ self.trace("the_type: %s"%the_type)
+ field_names = map(lambda f: f.GetName(), the_type.get_fields_array())
+ self.assertEquals(list(field_names), ["member"])
+
+ def _check_debug_info_is_limited(self, target):
+ # Without other shared libraries we should only see the member declared
+ # in the derived class. This serves as a sanity check that we are truly
+ # building with limited debug info.
+ self._check_type(target, "InheritsFromOne")
+ self._check_type(target, "InheritsFromTwo")
+
+ def test_one_and_two_debug(self):
+ self.build()
+ target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
+
+ self._check_debug_info_is_limited(target)
+
+ self.registerSharedLibrariesWithTarget(target, ["one", "two"])
+
+ # But when other shared libraries are loaded, we should be able to see
+ # all members.
+ self.expect_expr("inherits_from_one.member", result_value="47")
+ self.expect_expr("inherits_from_one.one", result_value="142")
+
+ self.expect_expr("inherits_from_two.member", result_value="47")
+ self.expect_expr("inherits_from_two.one", result_value="142")
+ self.expect_expr("inherits_from_two.two", result_value="242")
+
+ def test_two_debug(self):
+ self.build(dictionary=dict(STRIP_ONE="1"))
+ target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
+
+ self._check_debug_info_is_limited(target)
+
+ self.registerSharedLibrariesWithTarget(target, ["one", "two"])
+
+ # This time, we should only see the members from the second library.
+ self.expect_expr("inherits_from_one.member", result_value="47")
+ self.expect("expr inherits_from_one.one", error=True,
+ substrs=["no member named 'one' in 'InheritsFromOne'"])
+
+ self.expect_expr("inherits_from_two.member", result_value="47")
+ self.expect("expr inherits_from_two.one", error=True,
+ substrs=["no member named 'one' in 'InheritsFromTwo'"])
+ self.expect_expr("inherits_from_two.two", result_value="242")
+
+ def test_one_debug(self):
+ self.build(dictionary=dict(STRIP_TWO="1"))
+ target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
+
+ self._check_debug_info_is_limited(target)
+
+ self.registerSharedLibrariesWithTarget(target, ["one", "two"])
+
+ # In this case we should only see the members from the second library.
+ # Note that we cannot see inherits_from_two.one because without debug
+ # info for "Two", we cannot determine that it in fact inherits from
+ # "One".
+ self.expect_expr("inherits_from_one.member", result_value="47")
+ self.expect_expr("inherits_from_one.one", result_value="142")
+
+ self.expect_expr("inherits_from_two.member", result_value="47")
+ self.expect("expr inherits_from_two.one", error=True,
+ substrs=["no member named 'one' in 'InheritsFromTwo'"])
+ self.expect("expr inherits_from_two.two", error=True,
+ substrs=["no member named 'two' in 'InheritsFromTwo'"])
Index: lldb/test/API/functionalities/limit-debug-info/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/limit-debug-info/Makefile
@@ -0,0 +1,27 @@
+CFLAGS_EXTRAS := -flimit-debug-info
+LD_EXTRAS := -L. -lone -ltwo
+CXX_SOURCES := main.cpp
+
+ONE_CXXFLAGS := -flimit-debug-info
+ifdef STRIP_ONE
+ ONE_CXXFLAGS += -g0
+endif
+
+TWO_CXXFLAGS := -flimit-debug-info
+ifdef STRIP_TWO
+ TWO_CXXFLAGS += -g0
+endif
+
+include Makefile.rules
+
+a.out: libone libtwo
+
+libone:
+ $(MAKE) -f $(MAKEFILE_RULES) \
+ DYLIB_ONLY=YES DYLIB_CXX_SOURCES=one.cpp DYLIB_NAME=one \
+ CFLAGS_EXTRAS="$(ONE_CXXFLAGS)"
+
+libtwo: libone
+ $(MAKE) -f $(MAKEFILE_RULES) \
+ DYLIB_ONLY=YES DYLIB_CXX_SOURCES=two.cpp DYLIB_NAME=two \
+ CFLAGS_EXTRAS="$(TWO_CXXFLAGS)" LD_EXTRAS="-L. -lone"
Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -2061,26 +2061,19 @@
CompilerType base_class_type =
m_ast.GetType(type_source_info->getType());
if (!base_class_type.GetCompleteType()) {
- auto module = dwarf->GetObjectFile()->GetModule();
- module->ReportError(":: Class '%s' has a base class '%s' which "
- "does not have a complete definition.",
- die.GetName(),
- base_class_type.GetTypeName().GetCString());
- if (die.GetCU()->GetProducer() == eProducerClang)
- module->ReportError(":: Try compiling the source file with "
- "-fstandalone-debug.");
-
- // We have no choice other than to pretend that the base class
- // is complete. If we don't do this, clang will crash when we
- // call setBases() inside of
- // "clang_type.TransferBaseClasses()" below. Since we
- // provide layout assistance, all ivars in this class and other
- // classes will be fine, this is the best we can do short of
- // crashing.
+ // We mark the class as complete to allow the TransferBaseClasses
+ // call to succeed. But we make a note of the fact that this class
+ // is not _really_ complete so we can later search for a definition
+ // in a different module.
if (TypeSystemClang::StartTagDeclarationDefinition(
base_class_type)) {
TypeSystemClang::CompleteTagDeclarationDefinition(
base_class_type);
+ const auto *td = TypeSystemClang::GetQualType(
+ base_class_type.GetOpaqueQualType())
+ .getTypePtr()
+ ->getAsTagDecl();
+ m_ast.GetMetadata(td)->SetIsForcefullyCompleted();
}
}
}
Index: lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp
+++ lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp
@@ -7,6 +7,8 @@
//===----------------------------------------------------------------------===//
#include "Plugins/ExpressionParser/Clang/CxxModuleHandler.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Utility/Log.h"
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h
@@ -213,7 +213,16 @@
/// Clang AST contexts like to own their AST sources, so this is a state-
/// free proxy object.
class ClangASTSourceProxy : public clang::ExternalASTSource {
+ /// LLVM RTTI support.
+ static char ID;
+
public:
+ /// LLVM RTTI support.
+ bool isA(const void *ClassID) const override { return ClassID == &ID; }
+ static bool classof(const clang::ExternalASTSource *s) {
+ return s->isA(&ID);
+ }
+
ClangASTSourceProxy(ClangASTSource &original) : m_original(original) {}
bool FindExternalVisibleDeclsByName(const clang::DeclContext *DC,
@@ -251,6 +260,8 @@
return m_original.StartTranslationUnit(Consumer);
}
+ ClangASTSource &GetOriginalSource() { return m_original; }
+
private:
ClangASTSource &m_original;
};
@@ -356,6 +367,8 @@
/// ExternalASTSource.
TypeSystemClang *GetTypeSystem() const { return m_clang_ast_context; }
+ clang::TagDecl *FindCompleteType(const clang::TagDecl *decl);
+
protected:
bool FindObjCMethodDeclsWithOrigin(
NameSearchContext &context,
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
@@ -50,6 +50,8 @@
};
}
+char ClangASTSource::ClangASTSourceProxy::ID;
+
ClangASTSource::ClangASTSource(
const lldb::TargetSP &target,
const std::shared_ptr<ClangASTImporter> &importer)
@@ -185,127 +187,125 @@
return (name_decls.size() != 0);
}
-void ClangASTSource::CompleteType(TagDecl *tag_decl) {
+TagDecl *ClangASTSource::FindCompleteType(const TagDecl *decl) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
- if (log) {
- LLDB_LOG(log,
- " CompleteTagDecl on (ASTContext*){0} Completing "
- "(TagDecl*){1} named {2}",
- m_clang_ast_context->getDisplayName(), tag_decl,
- tag_decl->getName());
-
- LLDB_LOG(log, " CTD Before:\n{0}", ClangUtil::DumpDecl(tag_decl));
- }
-
- 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 (const NamespaceDecl *namespace_context =
+ dyn_cast<NamespaceDecl>(decl->getDeclContext())) {
+ ClangASTImporter::NamespaceMapSP namespace_map =
+ m_ast_importer_sp->GetNamespaceMap(namespace_context);
- if (!m_ast_importer_sp->CompleteTagDecl(tag_decl)) {
- // We couldn't complete the type. Maybe there's a definition somewhere
- // else that can be completed.
+ LLDB_LOGV(log, " CTD Inspecting namespace map{0} ({1} entries)",
+ namespace_map.get(), namespace_map->size());
- LLDB_LOG(log, " CTD Type could not be completed in the module in "
- "which it was first found.");
+ if (!namespace_map)
+ return nullptr;
- bool found = false;
+ for (const ClangASTImporter::NamespaceMapItem &item : *namespace_map) {
+ LLDB_LOG(log, " CTD Searching namespace {0} in module {1}",
+ item.second.GetName(), item.first->GetFileSpec().GetFilename());
- DeclContext *decl_ctx = tag_decl->getDeclContext();
+ TypeList types;
- if (const NamespaceDecl *namespace_context =
- dyn_cast<NamespaceDecl>(decl_ctx)) {
- ClangASTImporter::NamespaceMapSP namespace_map =
- m_ast_importer_sp->GetNamespaceMap(namespace_context);
+ ConstString name(decl->getName());
- LLDB_LOGV(log, " CTD Inspecting namespace map{0} ({1} entries)",
- namespace_map.get(), namespace_map->size());
+ item.first->FindTypesInNamespace(name, item.second, UINT32_MAX, types);
- if (!namespace_map)
- return;
+ for (uint32_t ti = 0, te = types.GetSize(); ti != te; ++ti) {
+ lldb::TypeSP type = types.GetTypeAtIndex(ti);
- for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(),
- e = namespace_map->end();
- i != e && !found; ++i) {
- LLDB_LOG(log, " CTD Searching namespace {0} in module {1}",
- i->second.GetName(), i->first->GetFileSpec().GetFilename());
+ if (!type)
+ continue;
- TypeList types;
+ CompilerType clang_type(type->GetFullCompilerType());
- ConstString name(tag_decl->getName().str().c_str());
+ if (!ClangUtil::IsClangType(clang_type))
+ continue;
- i->first->FindTypesInNamespace(name, i->second, UINT32_MAX, types);
+ const TagType *tag_type =
+ ClangUtil::GetQualType(clang_type)->getAs<TagType>();
- for (uint32_t ti = 0, te = types.GetSize(); ti != te && !found; ++ti) {
- lldb::TypeSP type = types.GetTypeAtIndex(ti);
+ if (!tag_type)
+ continue;
- if (!type)
- continue;
+ TagDecl *candidate_tag_decl =
+ const_cast<TagDecl *>(tag_type->getDecl());
- CompilerType clang_type(type->GetFullCompilerType());
+ if (TypeSystemClang::GetCompleteDecl(
+ &candidate_tag_decl->getASTContext(), candidate_tag_decl))
+ return candidate_tag_decl;
+ }
+ }
+ } else {
+ TypeList types;
- if (!ClangUtil::IsClangType(clang_type))
- continue;
+ ConstString name(decl->getName());
- const TagType *tag_type =
- ClangUtil::GetQualType(clang_type)->getAs<TagType>();
+ const ModuleList &module_list = m_target->GetImages();
- if (!tag_type)
- continue;
+ bool exact_match = false;
+ llvm::DenseSet<SymbolFile *> searched_symbol_files;
+ module_list.FindTypes(nullptr, name, exact_match, UINT32_MAX,
+ searched_symbol_files, types);
- TagDecl *candidate_tag_decl =
- const_cast<TagDecl *>(tag_type->getDecl());
+ for (uint32_t ti = 0, te = types.GetSize(); ti != te; ++ti) {
+ lldb::TypeSP type = types.GetTypeAtIndex(ti);
- if (m_ast_importer_sp->CompleteTagDeclWithOrigin(tag_decl,
- candidate_tag_decl))
- found = true;
- }
- }
- } else {
- TypeList types;
+ if (!type)
+ continue;
- ConstString name(tag_decl->getName().str().c_str());
+ CompilerType clang_type(type->GetFullCompilerType());
- const ModuleList &module_list = m_target->GetImages();
+ if (!ClangUtil::IsClangType(clang_type))
+ continue;
- bool exact_match = false;
- llvm::DenseSet<SymbolFile *> searched_symbol_files;
- module_list.FindTypes(nullptr, name, exact_match, UINT32_MAX,
- searched_symbol_files, types);
+ const TagType *tag_type =
+ ClangUtil::GetQualType(clang_type)->getAs<TagType>();
- for (uint32_t ti = 0, te = types.GetSize(); ti != te && !found; ++ti) {
- lldb::TypeSP type = types.GetTypeAtIndex(ti);
+ if (!tag_type)
+ continue;
- if (!type)
- continue;
+ TagDecl *candidate_tag_decl = const_cast<TagDecl *>(tag_type->getDecl());
- CompilerType clang_type(type->GetFullCompilerType());
+ // We have found a type by basename and we need to make sure the decl
+ // contexts are the same before we can try to complete this type with
+ // another
+ if (!TypeSystemClang::DeclsAreEquivalent(const_cast<TagDecl *>(decl),
+ candidate_tag_decl))
+ continue;
- if (!ClangUtil::IsClangType(clang_type))
- continue;
+ if (TypeSystemClang::GetCompleteDecl(&candidate_tag_decl->getASTContext(),
+ candidate_tag_decl))
+ return candidate_tag_decl;
+ }
+ }
+ return nullptr;
+}
- const TagType *tag_type =
- ClangUtil::GetQualType(clang_type)->getAs<TagType>();
+void ClangASTSource::CompleteType(TagDecl *tag_decl) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
- if (!tag_type)
- continue;
+ if (log) {
+ LLDB_LOG(log,
+ " CompleteTagDecl on (ASTContext*){0} Completing "
+ "(TagDecl*){1} named {2}",
+ m_clang_ast_context->getDisplayName(), tag_decl,
+ tag_decl->getName());
- TagDecl *candidate_tag_decl =
- const_cast<TagDecl *>(tag_type->getDecl());
+ LLDB_LOG(log, " CTD Before:\n{0}", ClangUtil::DumpDecl(tag_decl));
+ }
- // We have found a type by basename and we need to make sure the decl
- // contexts are the same before we can try to complete this type with
- // another
- if (!TypeSystemClang::DeclsAreEquivalent(tag_decl, candidate_tag_decl))
- continue;
+ 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_sp->CompleteTagDeclWithOrigin(tag_decl,
- candidate_tag_decl))
- found = true;
- }
- }
+ if (!m_ast_importer_sp->CompleteTagDecl(tag_decl)) {
+ // We couldn't complete the type. Maybe there's a definition somewhere
+ // else that can be completed.
+ if (TagDecl *alternate = FindCompleteType(tag_decl))
+ m_ast_importer_sp->CompleteTagDeclWithOrigin(tag_decl, alternate);
}
LLDB_LOG(log, " [CTD] After:\n{0}", ClangUtil::DumpDecl(tag_decl));
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h
@@ -19,7 +19,8 @@
public:
ClangASTMetadata()
: m_user_id(0), m_union_is_user_id(false), m_union_is_isa_ptr(false),
- m_has_object_ptr(false), m_is_self(false), m_is_dynamic_cxx(true) {}
+ m_has_object_ptr(false), m_is_self(false), m_is_dynamic_cxx(true),
+ m_is_forcefully_completed(false) {}
bool GetIsDynamicCXXType() const { return m_is_dynamic_cxx; }
@@ -83,6 +84,15 @@
bool HasObjectPtr() const { return m_has_object_ptr; }
+ /// A type is "forcefully completed" if it was declared complete to satisfy an
+ /// AST invariant (e.g. base classes must be complete types), but in fact we
+ /// were not able to find a actual definition for it.
+ bool IsForcefullyCompleted() const { return m_is_forcefully_completed; }
+
+ void SetIsForcefullyCompleted(bool value = true) {
+ m_is_forcefully_completed = true;
+ }
+
void Dump(Stream *s);
private:
@@ -92,7 +102,7 @@
};
bool m_union_is_user_id : 1, m_union_is_isa_ptr : 1, m_has_object_ptr : 1,
- m_is_self : 1, m_is_dynamic_cxx : 1;
+ m_is_self : 1, m_is_dynamic_cxx : 1, m_is_forcefully_completed : 1;
};
} // namespace lldb_private
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
@@ -18,6 +18,7 @@
#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTSource.h"
#include "Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h"
#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
@@ -876,6 +877,39 @@
}
}
+ // If we have a forcefully completed type, try to find an actual definition
+ // for it in other modules.
+ const ClangASTMetadata *md = m_master.GetDeclMetadata(From);
+ auto *td = dyn_cast<TagDecl>(From);
+ if (td && md && md->IsForcefullyCompleted()) {
+ Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
+ LLDB_LOG(log,
+ "[ClangASTImporter] Searching for a complete definition of {0} in "
+ "other modules",
+ td->getName());
+
+ if (auto *proxy = llvm::dyn_cast<ClangASTSource::ClangASTSourceProxy>(
+ getToContext().getExternalSource())) {
+ if (TagDecl *complete = proxy->GetOriginalSource().FindCompleteType(td)) {
+ LLDB_LOG(log, "[ClangASTImporter] Complete definition found in {0}",
+ TypeSystemClang::GetASTContext(&complete->getASTContext())
+ ->getDisplayName());
+ ImporterDelegateSP delegate_sp =
+ m_master.GetDelegate(&getToContext(), &complete->getASTContext());
+
+ Expected<Decl *> imported = delegate_sp->ImportImpl(complete);
+ if (imported) {
+ RegisterImportedDecl(From, *imported);
+ m_decls_to_ignore.insert(*imported);
+ m_master.CompleteTagDeclWithOrigin(cast<TagDecl>(*imported),
+ complete);
+ }
+ return imported;
+ } else
+ LLDB_LOG(log, "[ClangASTImporter] Complete definition not found");
+ }
+ }
+
return ASTImporter::ImportImpl(From);
}
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits