Mark implicit members coming from a PCH as used.

Implicitly generated members from a CXXRecordDecls coming from a PCH should not be
unloaded. CodeGen 'records' that it once emitted the implicit members and if they
get unloaded it would be out of sync. The key difference is the information about
all the implicitly generated members (trivial ctors/dtors, etc) comes from an
ASTMutationListener and they are not part of the transaction. We still do not
record it as a part of the transaction, we just mark them as used so that they
don't get unloaded from the llvm::Module.

Once the list of llvm.used decls is emitted we need to clear it, otherwise we
end up emitting one and the same thing over and over.

Fixes ROOT-6722
Tests should be coming shortly.
This commit is contained in:
Vassil Vassilev 2014-09-29 15:32:10 +02:00 committed by sftnight
parent f8b513b63a
commit 08a9274c02
4 changed files with 52 additions and 4 deletions

View File

@ -726,6 +726,7 @@ namespace cling {
stateCollector = new DeclCollector();
// Set up the ASTConsumers
CI->setASTConsumer(stateCollector);
CI->getASTContext().setASTMutationListener(stateCollector);
// Set up Sema
CodeCompleteConsumer* CCC = 0;

View File

@ -31,9 +31,25 @@ namespace cling {
return D->isFromASTFile();
}
bool DeclCollector::comesFromASTReader(const Decl* D) const {
// The operation is const but clang::DeclGroupRef doesn't allow us to
// express it.
return comesFromASTReader(DeclGroupRef(const_cast<Decl*>(D)));
}
// pin the vtable here.
DeclCollector::~DeclCollector() { }
void DeclCollector::AddedCXXImplicitMember(const CXXRecordDecl *RD,
const Decl *D) {
assert(D->isImplicit());
// We need to mark the decls coming from the modules
if (comesFromASTReader(RD) || comesFromASTReader(D)) {
Decl* implicitD = const_cast<Decl*>(D);
implicitD->addAttr(UsedAttr::CreateImplicit(implicitD->getASTContext()));
}
}
bool DeclCollector::HandleTopLevelDecl(DeclGroupRef DGR) {
Transaction::DelayCallInfo DCI(DGR, Transaction::kCCIHandleTopLevelDecl);
m_CurTransaction->append(DCI);

View File

@ -11,6 +11,7 @@
#define CLING_DECL_COLLECTOR_H
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/Lex/PPCallbacks.h"
namespace clang {
@ -32,7 +33,9 @@ namespace cling {
/// cling::DeclCollector is responsible for appending all the declarations
/// seen by clang.
///
class DeclCollector: public clang::PPCallbacks, public clang::ASTConsumer {
class DeclCollector: public clang::PPCallbacks,
public clang::ASTMutationListener,
public clang::ASTConsumer {
private:
Transaction* m_CurTransaction;
@ -40,11 +43,23 @@ namespace cling {
/// file.
///
bool comesFromASTReader(clang::DeclGroupRef DGR) const;
bool comesFromASTReader(const clang::Decl* D) const;
public:
DeclCollector() : m_CurTransaction(0){}
virtual ~DeclCollector();
/// \name PPCallbacks overrides
/// Macro support
virtual void MacroDefined(const clang::Token &MacroNameTok,
const clang::MacroDirective *MD);
/// \}
/// \name ASTMutationListeners overrides
virtual void AddedCXXImplicitMember(const clang::CXXRecordDecl *RD,
const clang::Decl *D);
/// \}
/// \{
/// \name ASTConsumer overrides
@ -71,9 +86,6 @@ namespace cling {
/// \}
/// Macro support
virtual void MacroDefined (const clang::Token &MacroNameTok,
const clang::MacroDirective *MD);
// dyn_cast/isa support
static bool classof(const clang::ASTConsumer*) { return true; }
};

View File

@ -64,6 +64,7 @@ namespace clang {
Changed |= RemoveUnusedGlobalValue(*GV);
// Collect all uses of globals by GV
CollectAllUsesOfGlobals(GV);
FindUsedValues(*GV->getParent());
// The first pass is to drop initializers of global vars which are dead.
for (Globals::iterator I = VisitedGlobals.begin(),
@ -108,6 +109,24 @@ namespace clang {
}
private:
/// Find values that are marked as llvm.used.
void FindUsedValues(const llvm::Module& m) {
for (const llvm::GlobalVariable& GV : m.globals()) {
if (!GV.getName().startswith("llvm.used"))
continue;
const llvm::ConstantArray* Inits
= cast<llvm::ConstantArray>(GV.getInitializer());
for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i) {
llvm::Value *Operand
= Inits->getOperand(i)->stripPointerCastsNoFollowAliases();
VisitedGlobals.erase(cast<llvm::GlobalValue>(Operand));
}
}
}
/// CollectAllUsesOfGlobals - collects recursively all referenced globals by
/// GV.
void CollectAllUsesOfGlobals(llvm::GlobalValue *G) {