Prepone callback initialization in cling.

We should setup our callbacks for ExternalASTSource/ExternalSemaSource
before we parse *any* code to prevent that any part of the code
stores a reference to a non-cling external sources. If this happens,
then the clang data structures such redecl chain could go out of
sync if they reference different sources and produce errors like failing
to merge declarations correctly or creating invalid redecl chains.

To fix this, we move this initalization before the initalization of
the incremental parser which is the first part that can generate
any AST nodes. We only do this for the modules case because in
the non-modules case the clang PCH overwrites our callback
in the ExternalASTSource and therefore would destroy our external
source.
This commit is contained in:
Raphael Isemann 2017-11-01 10:17:56 +01:00 committed by sftnight
parent d411ed7885
commit 016eaa7620

View File

@ -182,6 +182,20 @@ namespace cling {
return Opts.ShowVersion || Opts.Help;
}
static void setupCallbacks(Interpreter& Interp,
const Interpreter* parentInterp) {
// We need InterpreterCallbacks only if it is a parent Interpreter.
if (parentInterp) return;
// Disable suggestions for ROOT
bool showSuggestions =
!llvm::StringRef(ClingStringify(CLING_VERSION)).startswith("ROOT");
std::unique_ptr<InterpreterCallbacks> AutoLoadCB(
new AutoloadCallback(&Interp, showSuggestions));
Interp.setCallbacks(std::move(AutoLoadCB));
}
Interpreter::Interpreter(int argc, const char* const *argv,
const char* llvmdir /*= 0*/, bool noRuntime,
const Interpreter* parentInterp) :
@ -226,6 +240,17 @@ namespace cling {
DiagnosticConsumer& DClient = getCI()->getDiagnosticClient();
DClient.BeginSourceFile(getCI()->getLangOpts(), &PP);
bool usingCxxModules = getSema().getLangOpts().Modules;
// When using C++ modules, we setup the callbacks now that we have them
// ready before we parse code for the first time. Without C++ modules
// we can't setup the calls now because the clang PCH currently just
// overwrites it in the Initialize method and we have no simple way to
// initialize them earlier. We handle the non-modules case below.
if (usingCxxModules) {
setupCallbacks(*this, parentInterp);
}
llvm::SmallVector<IncrementalParser::ParseResultTransaction, 2>
IncrParserTransactions;
if (!m_IncrParser->Initialize(IncrParserTransactions, parentInterp)) {
@ -237,6 +262,13 @@ namespace cling {
return;
}
// When not using C++ modules, we now have a PCH and we can safely setup
// our callbacks without fearing that they get ovewritten by clang code.
// The modules setup is handled above.
if (!usingCxxModules) {
setupCallbacks(*this, parentInterp);
}
llvm::SmallVector<llvm::StringRef, 6> Syms;
Initialize(noRuntime || m_Opts.NoRuntime, isInSyntaxOnlyMode(), Syms);
@ -269,16 +301,6 @@ namespace cling {
}
}
// Disable suggestions for ROOT
bool showSuggestions = !llvm::StringRef(ClingStringify(CLING_VERSION)).startswith("ROOT");
// We need InterpreterCallbacks only if it is a parent Interpreter.
if (!parentInterp) {
std::unique_ptr<InterpreterCallbacks>
AutoLoadCB(new AutoloadCallback(this, showSuggestions));
setCallbacks(std::move(AutoLoadCB));
}
m_IncrParser->SetTransformers(parentInterp);
if (!m_LLVMContext) {