Move codegenning of deserialized declarations in the IncrementalParser.
We had two different codepath for codegeneration. The first one was for declarations that came from text and the second one for declarations that came from 'ExternalSource' such as PCH. In the latter case we had to do some extra equilibristics to emulate a PCM and ignore generating code for decls with static storage, because it will clash with the loading of the library that already contains them. The advantage of the new implementation is that instead of communicating the deserialized decls to ROOT via some fishy deserialization listeners we can use the cling::Transaction as we use it for decls that came from code.
This commit is contained in:
parent
2e97001848
commit
59ced3f193
@ -30,98 +30,27 @@ namespace cling {
|
||||
return D->isFromASTFile();
|
||||
}
|
||||
|
||||
bool DeclCollector::shouldIgnoreDeclFromASTReader(const Decl* D) const {
|
||||
// Functions that are inlined must be sent to CodeGen - they will not have a
|
||||
// symbol in the library.
|
||||
if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D)) {
|
||||
if (D->isFromASTFile())
|
||||
return !FD->hasBody();
|
||||
else
|
||||
return !FD->isInlined();
|
||||
}
|
||||
|
||||
// Don't codegen statics coming in from a module; they are already part of
|
||||
// the library.
|
||||
if (const VarDecl* VD = dyn_cast<VarDecl>(D))
|
||||
if (VD->hasGlobalStorage())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// pin the vtable here.
|
||||
DeclCollector::~DeclCollector() {
|
||||
}
|
||||
|
||||
bool DeclCollector::HandleTopLevelDecl(DeclGroupRef DGR) {
|
||||
// if that decl comes from an AST File, i.e. PCH/PCM, no transaction needed
|
||||
// pipe it directly to codegen.
|
||||
if (comesFromASTReader(DGR)) {
|
||||
if (m_CodeGen) {
|
||||
for (DeclGroupRef::iterator I = DGR.begin(), E = DGR.end();
|
||||
I != E; ++I) {
|
||||
if (NamespaceDecl* ND = dyn_cast<NamespaceDecl>(*I)) {
|
||||
for (NamespaceDecl::decl_iterator IN = ND->decls_begin(),
|
||||
EN = ND->decls_end(); IN != EN; ++IN)
|
||||
// Recurse over decls inside the namespace, like
|
||||
// CodeGenModule::EmitNamespace() does.
|
||||
HandleTopLevelDecl(DeclGroupRef(*IN));
|
||||
} else {
|
||||
if (!shouldIgnoreDeclFromASTReader(*I)) {
|
||||
m_CodeGen->HandleTopLevelDecl(DeclGroupRef(*I));
|
||||
}
|
||||
// FIXME: once modules are there this is not needed anymore.
|
||||
// it is used to simulate modules and the ASTDeserializationListener
|
||||
// for sources that are included to describe the library that was
|
||||
// built from the sources (ACLiC).
|
||||
if (!(*I)->isFromASTFile() && m_Interp->getASTDeserializationListener())
|
||||
m_Interp->getASTDeserializationListener()->DeclRead(0, *I);
|
||||
}
|
||||
}
|
||||
}
|
||||
//return true;
|
||||
}
|
||||
DeclCollector::~DeclCollector() { }
|
||||
|
||||
bool DeclCollector::HandleTopLevelDecl(DeclGroupRef DGR) {
|
||||
Transaction::DelayCallInfo DCI(DGR, Transaction::kCCIHandleTopLevelDecl);
|
||||
m_CurTransaction->append(DCI);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeclCollector::HandleInterestingDecl(DeclGroupRef DGR) {
|
||||
// if that decl comes from an AST File, i.e. PCH/PCM, no transaction needed
|
||||
// pipe it directly to codegen.
|
||||
if (comesFromASTReader(DGR)) {
|
||||
HandleTopLevelDecl(DGR);
|
||||
//return;
|
||||
}
|
||||
|
||||
Transaction::DelayCallInfo DCI(DGR, Transaction::kCCIHandleInterestingDecl);
|
||||
m_CurTransaction->append(DCI);
|
||||
}
|
||||
|
||||
void DeclCollector::HandleTagDeclDefinition(TagDecl* TD) {
|
||||
// if that decl comes from an AST File, i.e. PCH/PCM, no transaction needed
|
||||
// pipe it directly to codegen.
|
||||
if (comesFromASTReader(DeclGroupRef(TD))) {
|
||||
if (m_CodeGen)
|
||||
m_CodeGen->HandleTagDeclDefinition(TD);
|
||||
//return;
|
||||
}
|
||||
|
||||
Transaction::DelayCallInfo DCI(DeclGroupRef(TD),
|
||||
Transaction::kCCIHandleTagDeclDefinition);
|
||||
m_CurTransaction->append(DCI);
|
||||
}
|
||||
|
||||
void DeclCollector::HandleVTable(CXXRecordDecl* RD, bool DefinitionRequired) {
|
||||
// if that decl comes from an AST File, i.e. PCH/PCM, no transaction needed
|
||||
// pipe it directly to codegen.
|
||||
if (comesFromASTReader(DeclGroupRef(RD))) {
|
||||
// FIXME: when is the vtable part of the library?
|
||||
if (m_CodeGen)
|
||||
m_CodeGen->HandleVTable(RD, DefinitionRequired);
|
||||
//return;
|
||||
}
|
||||
|
||||
Transaction::DelayCallInfo DCI(DeclGroupRef(RD),
|
||||
Transaction::kCCIHandleVTable);
|
||||
m_CurTransaction->append(DCI);
|
||||
@ -142,27 +71,11 @@ namespace cling {
|
||||
}
|
||||
|
||||
void DeclCollector::HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) {
|
||||
// if that decl comes from an AST File, i.e. PCH/PCM, no transaction needed
|
||||
// pipe it directly to codegen.
|
||||
if (comesFromASTReader(DeclGroupRef(D))) {
|
||||
if (m_CodeGen)
|
||||
m_CodeGen->HandleCXXImplicitFunctionInstantiation(D);
|
||||
//return;
|
||||
}
|
||||
|
||||
Transaction::DelayCallInfo DCI(DeclGroupRef(D),
|
||||
Transaction::kCCIHandleCXXImplicitFunctionInstantiation);
|
||||
m_CurTransaction->append(DCI);
|
||||
}
|
||||
void DeclCollector::HandleCXXStaticMemberVarInstantiation(VarDecl *D) {
|
||||
// if that decl comes from an AST File, i.e. PCH/PCM, no transaction needed
|
||||
// pipe it directly to codegen.
|
||||
if (comesFromASTReader(DeclGroupRef(D))) {
|
||||
if (m_CodeGen && !shouldIgnoreDeclFromASTReader(D))
|
||||
m_CodeGen->HandleCXXStaticMemberVarInstantiation(D);
|
||||
//return;
|
||||
}
|
||||
|
||||
Transaction::DelayCallInfo DCI(DeclGroupRef(D),
|
||||
Transaction::kCCIHandleCXXStaticMemberVarInstantiation);
|
||||
m_CurTransaction->append(DCI);
|
||||
|
@ -31,36 +31,15 @@ namespace cling {
|
||||
private:
|
||||
Transaction* m_CurTransaction;
|
||||
|
||||
///\brief This is the fast path for the declarations which do not need
|
||||
/// special handling. Eg. deserialized declarations.
|
||||
clang::CodeGenerator* m_CodeGen; // we do not own.
|
||||
|
||||
///\brief Interpreter feeding into the DeclCollector. Only used for
|
||||
/// a temporary workaround until modules work.
|
||||
/// FIXME: remove once modules work.
|
||||
cling::Interpreter* m_Interp; // we do not own.
|
||||
|
||||
///\brief Test whether the first decl of the DeclGroupRef comes from an AST
|
||||
/// file.
|
||||
///
|
||||
bool comesFromASTReader(clang::DeclGroupRef DGR) const;
|
||||
/// \brief Return true if this decl (which comes from an AST file) should
|
||||
// not be sent to CodeGen. The module is assumed to describe the contents of
|
||||
// a library; symbols inside the library must thus not be reemitted /
|
||||
// duplicated by CodeGen.
|
||||
bool shouldIgnoreDeclFromASTReader(const clang::Decl* D) const;
|
||||
|
||||
public:
|
||||
DeclCollector() :
|
||||
m_CurTransaction(0), m_CodeGen(0), m_Interp(0) {}
|
||||
DeclCollector() : m_CurTransaction(0){}
|
||||
virtual ~DeclCollector();
|
||||
|
||||
// FIXME: Gross hack, which should disappear when we move some of the
|
||||
// initialization happening in the IncrementalParser to the CIFactory.
|
||||
void setCodeGen(clang::CodeGenerator* codeGen) { m_CodeGen = codeGen; }
|
||||
|
||||
// FIXME: Gross hack, which should disappear when m_Interp can go.
|
||||
void setInterpreter(cling::Interpreter* Interp) { m_Interp = Interp; }
|
||||
|
||||
/// \{
|
||||
/// \name ASTConsumer overrides
|
||||
|
||||
|
@ -56,7 +56,6 @@ namespace cling {
|
||||
|
||||
m_Consumer = dyn_cast<DeclCollector>(&CI->getASTConsumer());
|
||||
assert(m_Consumer && "Expected ChainedConsumer!");
|
||||
m_Consumer->setInterpreter(interp);
|
||||
|
||||
m_CI.reset(CI);
|
||||
|
||||
@ -66,7 +65,6 @@ namespace cling {
|
||||
CI->getTargetOpts(),
|
||||
*m_Interpreter->getLLVMContext()
|
||||
));
|
||||
m_Consumer->setCodeGen(m_CodeGen.get());
|
||||
}
|
||||
|
||||
initializeVirtualFile();
|
||||
@ -352,19 +350,43 @@ namespace cling {
|
||||
llvm_unreachable("We shouldn't have decl without call info.");
|
||||
}
|
||||
|
||||
// Treat the deserialized decls differently.
|
||||
const CompilationOptions& CO(T->getCompilationOpts());
|
||||
for (Transaction::iterator I = T->deserialized_decls_begin(),
|
||||
E = T->deserialized_decls_end(); I != E; ++I) {
|
||||
// Skip unless we find at least one used decl.
|
||||
bool skip = true;
|
||||
for (DeclGroupRef::const_iterator J = I->m_DGR.begin(),
|
||||
JE = I->m_DGR.end(); J != JE; ++J) {
|
||||
if ((*J)->hasAttr<UsedAttr>())
|
||||
skip = false;
|
||||
|
||||
if (I->m_Call == Transaction::kCCIHandleTopLevelDecl) {
|
||||
// FIXME: This flag means that we should skip the namespace codegen,
|
||||
// because we did it already. This works around issue with the static
|
||||
// initialization when having a PCH and loading a library. We don't want
|
||||
// to generate code for the static that will come through the library.
|
||||
//
|
||||
// This will be fixed with the clang::Modules. Make sure we remember.
|
||||
assert(!getCI()->getLangOpts().Modules && "Please revisit!");
|
||||
bool shouldContinue = false;
|
||||
for (DeclGroupRef::iterator DI = I->m_DGR.begin(), DE = I->m_DGR.end();
|
||||
DI != DE; ++DI)
|
||||
if (NamespaceDecl* ND = dyn_cast<NamespaceDecl>(*DI)) {
|
||||
shouldContinue = true;
|
||||
for (NamespaceDecl::decl_iterator IN = ND->decls_begin(),
|
||||
EN = ND->decls_end(); IN != EN; ++IN) {
|
||||
// Recurse over decls inside the namespace, like
|
||||
// CodeGenModule::EmitNamespace() does.
|
||||
DeclGroupRef INDGR = DeclGroupRef(*IN);
|
||||
if (!shouldIgnore(INDGR))
|
||||
getCodeGenerator()->HandleTopLevelDecl(INDGR);
|
||||
}
|
||||
}
|
||||
if (shouldContinue)
|
||||
continue;
|
||||
}
|
||||
if (skip)
|
||||
|
||||
if (shouldIgnore(I->m_DGR))
|
||||
continue;
|
||||
if (I->m_Call == Transaction::kCCIHandleTopLevelDecl)
|
||||
|
||||
if (I->m_Call == Transaction::kCCIHandleTopLevelDecl) {
|
||||
getCodeGenerator()->HandleTopLevelDecl(I->m_DGR);
|
||||
}
|
||||
else if (I->m_Call == Transaction::kCCIHandleInterestingDecl) {
|
||||
// Usually through BackendConsumer which doesn't implement
|
||||
// HandleInterestingDecl() and thus calls
|
||||
@ -611,4 +633,25 @@ namespace cling {
|
||||
}
|
||||
}
|
||||
|
||||
bool IncrementalParser::shouldIgnore(DeclGroupRef DGR) const {
|
||||
// Take the first/only decl in the group. The second must have the same
|
||||
// properties as the first Decl in the group.
|
||||
const Decl* D = *DGR.begin();
|
||||
// Functions that are inlined must be sent to CodeGen - they will not have a
|
||||
// symbol in the library.
|
||||
if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D)) {
|
||||
if (D->isFromASTFile())
|
||||
return !FD->hasBody();
|
||||
else
|
||||
return !FD->isInlined();
|
||||
}
|
||||
|
||||
// Don't codegen statics coming in from a module; they are already part of
|
||||
// the library.
|
||||
if (const VarDecl* VD = dyn_cast<VarDecl>(D))
|
||||
if (VD->hasGlobalStorage())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace cling
|
||||
|
@ -24,11 +24,11 @@ namespace llvm {
|
||||
namespace clang {
|
||||
class CodeGenerator;
|
||||
class CompilerInstance;
|
||||
class DeclGroupRef;
|
||||
class FileID;
|
||||
class Parser;
|
||||
}
|
||||
|
||||
|
||||
namespace cling {
|
||||
class CompilationOptions;
|
||||
class CIFactory;
|
||||
@ -229,6 +229,13 @@ namespace cling {
|
||||
///\param[in] input - The incremental input that needs to be parsed.
|
||||
///
|
||||
EParseResult ParseInternal(llvm::StringRef input);
|
||||
|
||||
///\brief Return true if this decl (which comes from an AST file) should
|
||||
/// not be sent to CodeGen. The module is assumed to describe the contents
|
||||
/// of a library; symbols inside the library must thus not be reemitted /
|
||||
/// duplicated by CodeGen.
|
||||
///
|
||||
bool shouldIgnore(clang::DeclGroupRef DGR) const;
|
||||
};
|
||||
} // end namespace cling
|
||||
#endif // CLING_INCREMENTAL_PARSER_H
|
||||
|
Loading…
Reference in New Issue
Block a user