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:
parent
f8b513b63a
commit
08a9274c02
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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; }
|
||||
};
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user