Fixed the way ClangASTImporter deports types from

ASTContexts that will not stay around.  Before, we
did this in a very half-hearted way.  Now we maintain
work queues of all Decls that need to be completed
before the source ASTContext can go away; we then
expunge their origins completely.

<rdar://problem/13511875>

llvm-svn: 178410
This commit is contained in:
Sean Callanan 2013-03-30 02:31:21 +00:00
parent 7b0c94e207
commit e55bc8a9c1
2 changed files with 122 additions and 52 deletions

View File

@ -11,6 +11,7 @@
#define liblldb_ClangASTImporter_h_
#include <map>
#include <set>
#include "lldb/lldb-types.h"
@ -250,17 +251,38 @@ private:
*source_ctx,
master.m_file_manager,
true /*minimal*/),
m_decls_to_deport(NULL),
m_decls_already_deported(NULL),
m_master(master),
m_source_ctx(source_ctx)
{
}
// A call to "InitDeportWorkQueues" puts the minion into deport mode.
// In deport mode, every copied Decl that could require completion is
// recorded and placed into the decls_to_deport set.
//
// A call to "ExecuteDeportWorkQueues" completes all the Decls that
// are in decls_to_deport, adding any Decls it sees along the way that
// it hasn't already deported. It proceeds until decls_to_deport is
// empty.
//
// These calls must be paired. Leaving a minion in deport mode or
// trying to start deport minion with a new pair of queues will result
// in an assertion failure.
void InitDeportWorkQueues (std::set<clang::NamedDecl *> *decls_to_deport,
std::set<clang::NamedDecl *> *decls_already_deported);
void ExecuteDeportWorkQueues ();
void ImportDefinitionTo (clang::Decl *to, clang::Decl *from);
clang::Decl *Imported (clang::Decl *from, clang::Decl *to);
ClangASTImporter &m_master;
clang::ASTContext *m_source_ctx;
std::set<clang::NamedDecl *> *m_decls_to_deport;
std::set<clang::NamedDecl *> *m_decls_already_deported;
ClangASTImporter &m_master;
clang::ASTContext *m_source_ctx;
};
typedef STD_SHARED_PTR(Minion) MinionSP;

View File

@ -113,37 +113,27 @@ lldb::clang_type_t
ClangASTImporter::DeportType (clang::ASTContext *dst_ctx,
clang::ASTContext *src_ctx,
lldb::clang_type_t type)
{
{
MinionSP minion_sp (GetMinion (dst_ctx, src_ctx));
if (!minion_sp)
return NULL;
std::set<NamedDecl *> decls_to_deport;
std::set<NamedDecl *> decls_already_deported;
minion_sp->InitDeportWorkQueues(&decls_to_deport,
&decls_already_deported);
lldb::clang_type_t result = CopyType(dst_ctx, src_ctx, type);
minion_sp->ExecuteDeportWorkQueues();
if (!result)
return NULL;
QualType qual_type = QualType::getFromOpaquePtr(type);
if (const TagType *tag_type = qual_type->getAs<TagType>())
{
TagDecl *tag_decl = tag_type->getDecl();
const TagType *result_tag_type = QualType::getFromOpaquePtr(result)->getAs<TagType>();
TagDecl *result_tag_decl = result_tag_type->getDecl();
if (tag_decl)
{
MinionSP minion_sp (GetMinion (dst_ctx, src_ctx));
minion_sp->ImportDefinitionTo(result_tag_decl, tag_decl);
ASTContextMetadataSP to_context_md = GetContextMetadata(dst_ctx);
OriginMap::iterator oi = to_context_md->m_origins.find(result_tag_decl);
if (oi != to_context_md->m_origins.end() &&
oi->second.ctx == src_ctx)
to_context_md->m_origins.erase(oi);
}
}
return result;
}
clang::Decl *
@ -160,31 +150,23 @@ ClangASTImporter::DeportDecl (clang::ASTContext *dst_ctx,
src_ctx,
dst_ctx);
MinionSP minion_sp (GetMinion (dst_ctx, src_ctx));
if (!minion_sp)
return NULL;
std::set<NamedDecl *> decls_to_deport;
std::set<NamedDecl *> decls_already_deported;
minion_sp->InitDeportWorkQueues(&decls_to_deport,
&decls_already_deported);
clang::Decl *result = CopyDecl(dst_ctx, src_ctx, decl);
minion_sp->ExecuteDeportWorkQueues();
if (!result)
return NULL;
ClangASTContext::GetCompleteDecl (src_ctx, decl);
MinionSP minion_sp (GetMinion (dst_ctx, src_ctx));
if (minion_sp && isa<TagDecl>(decl))
minion_sp->ImportDefinitionTo(result, decl);
ASTContextMetadataSP to_context_md = GetContextMetadata(dst_ctx);
OriginMap::iterator oi = to_context_md->m_origins.find(result);
if (oi != to_context_md->m_origins.end() &&
oi->second.ctx == src_ctx)
to_context_md->m_origins.erase(oi);
if (TagDecl *result_tag_decl = dyn_cast<TagDecl>(result))
{
result_tag_decl->setHasExternalLexicalStorage(false);
result_tag_decl->setHasExternalVisibleStorage(false);
}
if (log)
log->Printf(" [ClangASTImporter] DeportDecl deported (%sDecl*)%p to (%sDecl*)%p",
@ -468,6 +450,63 @@ ClangASTImporter::MapCompleter::~MapCompleter ()
return;
}
void
ClangASTImporter::Minion::InitDeportWorkQueues (std::set<clang::NamedDecl *> *decls_to_deport,
std::set<clang::NamedDecl *> *decls_already_deported)
{
assert(!m_decls_to_deport); // TODO make debug only
assert(!m_decls_already_deported);
m_decls_to_deport = decls_to_deport;
m_decls_already_deported = decls_already_deported;
}
void
ClangASTImporter::Minion::ExecuteDeportWorkQueues ()
{
assert(m_decls_to_deport); // TODO make debug only
assert(m_decls_already_deported);
ASTContextMetadataSP to_context_md = m_master.GetContextMetadata(&getToContext());
while (!m_decls_to_deport->empty())
{
NamedDecl *decl = *m_decls_to_deport->begin();
m_decls_already_deported->insert(decl);
m_decls_to_deport->erase(decl);
DeclOrigin &origin = to_context_md->m_origins[decl];
assert (origin.ctx == m_source_ctx); // otherwise we should never have added this
// because it doesn't need to be deported
Decl *original_decl = to_context_md->m_origins[decl].decl;
ClangASTContext::GetCompleteDecl (m_source_ctx, original_decl);
if (TagDecl *tag_decl = dyn_cast<TagDecl>(decl))
{
if (TagDecl *original_tag_decl = dyn_cast<TagDecl>(original_decl))
if (original_tag_decl->isCompleteDefinition())
ImportDefinitionTo(tag_decl, original_tag_decl);
tag_decl->setHasExternalLexicalStorage(false);
tag_decl->setHasExternalVisibleStorage(false);
}
else if (ObjCInterfaceDecl *interface_decl = dyn_cast<ObjCInterfaceDecl>(decl))
{
interface_decl->setHasExternalLexicalStorage(false);
interface_decl->setHasExternalVisibleStorage(false);
}
to_context_md->m_origins.erase(decl);
}
m_decls_to_deport = NULL;
m_decls_already_deported = NULL;
}
void
ClangASTImporter::Minion::ImportDefinitionTo (clang::Decl *to, clang::Decl *from)
{
@ -594,6 +633,17 @@ clang::Decl
}
else
{
if (m_decls_to_deport && m_decls_already_deported)
{
if (isa<TagDecl>(to) || isa<ObjCInterfaceDecl>(to))
{
NamedDecl *to_named_decl = dyn_cast<NamedDecl>(to);
if (!m_decls_already_deported->count(to_named_decl))
m_decls_to_deport->insert(to_named_decl);
}
}
to_context_md->m_origins[to] = DeclOrigin(m_source_ctx, from);
if (log)
@ -630,15 +680,13 @@ clang::Decl
to_tag_decl->setHasExternalLexicalStorage();
to_tag_decl->setMustBuildLookupTable();
if (log)
log->Printf(" [ClangASTImporter] To is a TagDecl - attributes %s%s [%s->%s]",
(to_tag_decl->hasExternalLexicalStorage() ? " Lexical" : ""),
(to_tag_decl->hasExternalVisibleStorage() ? " Visible" : ""),
(from_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"),
(to_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"));
to_tag_decl = NULL;
}
if (isa<NamespaceDecl>(from))
@ -656,7 +704,7 @@ clang::Decl
to_interface_decl->setHasExternalLexicalStorage();
to_interface_decl->setHasExternalVisibleStorage();
/*to_interface_decl->setExternallyCompleted();*/
if (log)