Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions build/unix/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ module ROOT_Foundation_C {
export *
}

module ROOT_FwdNamespaces {
module "AutoGeneratedForwardDeclaredNamespacesForGMI" { header "AutoGeneratedForwardDeclaredNamespacesForGMI.h" export *}
export *
}

// This module contains header files from module Core which are used as
// configuration for ROOT. They contain a lot of macro definitions which are
// supposed to be textually expanded in each TU.
Expand Down
87 changes: 79 additions & 8 deletions core/metacling/src/TCling.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ clang/LLVM technology.
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Process.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/ObjectFile.h"
Expand Down Expand Up @@ -1084,6 +1085,8 @@ static bool HasASTFileOnDisk(clang::Module *M, const clang::Preprocessor &PP, st
}

static bool HaveFullGlobalModuleIndex = false;
static const std::string GeneratedFwdNamespaces = (TROOT::GetIncludeDir() + "AutoGeneratedForwardDeclaredNamespacesForGMI.h").Data();

static GlobalModuleIndex *loadGlobalModuleIndex(cling::Interpreter &interp)
{
CompilerInstance &CI = *interp.getCI();
Expand Down Expand Up @@ -1124,6 +1127,8 @@ static GlobalModuleIndex *loadGlobalModuleIndex(cling::Interpreter &interp)
TraverseDecl(TU);
}
bool VisitNamedDecl(NamedDecl *ND) {
if (ND->isInStdNamespace())
return true;
if (!ND->isFromASTFile())
return true;
if (!ND->getIdentifier())
Expand All @@ -1135,17 +1140,22 @@ static GlobalModuleIndex *loadGlobalModuleIndex(cling::Interpreter &interp)
if (TagDecl *TD = llvm::dyn_cast<TagDecl>(ND)) {
if (TD->isCompleteDefinition())
Register(TD);
} else if (NamespaceDecl *NSD = llvm::dyn_cast<NamespaceDecl>(ND)) {
Register(NSD, /*AddSingleEntry=*/ false);
}
else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(ND))
} else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(ND))
Register(TND);
else if (TypeAliasDecl *TAD = dyn_cast<TypeAliasDecl>(ND))
Register(TAD);
else if (isa<FunctionDecl>(ND) && !isa<CXXMethodDecl>(ND))
Register(ND);
// FIXME: Add the rest...
return true; // continue decending
}

private:
clang::GlobalModuleIndex::UserDefinedInterestingIDs &DefinitionIDs;
void Register(const NamedDecl* ND, bool AddSingleEntry = true) {
llvm::StringMap<llvm::SmallVector<const Decl *, 8>> Canonicals;

void Register(const NamedDecl *ND)
{
assert(ND->isFromASTFile());
// FIXME: All decls should have an owning module once rootcling
// updates its generated decls from within the LookupHelper & co.
Expand All @@ -1163,17 +1173,74 @@ static GlobalModuleIndex *loadGlobalModuleIndex(cling::Interpreter &interp)
Module *OwningModule = ND->getOwningModule()->getTopLevelModule();
assert(OwningModule);
assert(!ND->getName().empty() && "Empty name");
if (AddSingleEntry && DefinitionIDs.count(ND->getName()))
return;
if (Canonicals.count(ND->getName())) {
if (llvm::is_contained(Canonicals[ND->getName()], ND->getCanonicalDecl()))
return;
}

// FIXME: The FileEntry in not stable to serialize.
// FIXME: We might end up with many times with the same module.
// FIXME: We might end up two modules containing a definition.
// FIXME: What do we do if no definition is found.
DefinitionIDs[ND->getName()].push_back(OwningModule->getASTFile());
Canonicals[ND->getName()].push_back(ND->getCanonicalDecl());
}
};
DefinitionFinder defFinder(IDs, CI.getASTContext().getTranslationUnitDecl());

struct NamespaceDeclarer : public RecursiveASTVisitor<NamespaceDeclarer> {
std::string Fwds;
std::unordered_set<const NamespaceDecl *> Namespaces;

NamespaceDeclarer(clang::TranslationUnitDecl *TU) { TraverseDecl(TU); }
std::string PrintNamespaceOpen(NamespaceDecl *NSD)
{
std::string result;
if (NSD->isInline())
result += "inline ";
result += "namespace " + NSD->getNameAsString() + "{";
return result;
}
bool VisitNamespaceDecl(NamespaceDecl *NSD)
{
if (NSD->isAnonymousNamespace() || NSD->isInline() || NSD->isInStdNamespace())
return true;
if (Namespaces.count(NSD->getCanonicalDecl()))
return true;

std::vector<NamespaceDecl *> Parents;
// NS1::NS2::NS3-> namespace NS1 { namespace NS2 {namespace NS3{}}}
for (DeclContext *DC = NSD; DC && !DC->isTranslationUnit(); DC = DC->getParent()) {
if (auto D = dyn_cast<NamespaceDecl>(DC)) {
if (D->isAnonymousNamespace() || D->isInline() || D->isInStdNamespace())
continue;
Namespaces.insert(D);
Parents.push_back(D);
}
}
std::reverse(Parents.begin(), Parents.end());

for (auto *D : Parents)
Fwds += PrintNamespaceOpen(D);
Fwds += std::string(Parents.size(), '}');
Fwds += "\n";

Namespaces.insert(NSD->getCanonicalDecl());
for (Decl *D : NSD->decls()) {
if (!isa<NamespaceDecl>(D))
continue;
TraverseDecl(D);
}
return true;
}
};

if (!llvm::sys::fs::exists(GeneratedFwdNamespaces)) {
NamespaceDeclarer NSDeclarer(CI.getASTContext().getTranslationUnitDecl());

llvm::sys::writeFileWithEncoding(GeneratedFwdNamespaces, NSDeclarer.Fwds);
}

llvm::cantFail(GlobalModuleIndex::writeIndex(CI.getFileManager(),
CI.getPCHContainerReader(),
ModuleIndexPath,
Expand All @@ -1196,6 +1263,8 @@ static void RegisterCxxModules(cling::Interpreter &clingInterp)
cling::Interpreter::PushTransactionRAII deserRAII(&clingInterp);

// Setup core C++ modules if we have any to setup.
if (llvm::sys::fs::exists(GeneratedFwdNamespaces))
LoadModule("ROOT_FwdNamespaces", clingInterp);

// Load libc and stl first.
// Load vcruntime module for windows
Expand Down Expand Up @@ -1233,7 +1302,9 @@ static void RegisterCxxModules(cling::Interpreter &clingInterp)
// These modules should not be preloaded but they fix issues.
// FIXME: Hist is not a core module but is very entangled to MathCore and
// causes issues.
std::vector<std::string> FIXMEModules = {"Hist"};
// ROOTDataFrame is not a core module as well, but without it Clang reports
// some ODR related issues.
std::vector<std::string> FIXMEModules = {"Hist", "ROOTDataFrame"};
clang::CompilerInstance &CI = *clingInterp.getCI();
clang::Preprocessor &PP = CI.getPreprocessor();
ModuleMap &MMap = PP.getHeaderSearchInfo().getModuleMap();
Expand Down