diff --git a/lib/Interpreter/ExternalInterpreterSource.cpp b/lib/Interpreter/ExternalInterpreterSource.cpp index 115ea73f9b..934f6cd5c1 100644 --- a/lib/Interpreter/ExternalInterpreterSource.cpp +++ b/lib/Interpreter/ExternalInterpreterSource.cpp @@ -14,6 +14,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/ASTImporter.h" +#include "clang/AST/DeclContextInternals.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Sema.h" @@ -78,7 +79,7 @@ namespace cling { m_ChildInterpreter->getCI()->getASTContext().getTranslationUnitDecl(); // Also keep in the map of Decl Contexts the Translation Unit Decl Context - m_ImportedDeclContexts[childTUDeclContext] = parentTUDeclContext; + m_ImportedDeclContexts.emplace(childTUDeclContext, parentTUDeclContext); FileManager &childFM = m_ChildInterpreter->getCI()->getFileManager(); FileManager &parentFM = m_ParentInterpreter->getCI()->getFileManager(); @@ -95,7 +96,7 @@ namespace cling { void ExternalInterpreterSource::ImportDecl(Decl *declToImport, DeclarationName &childDeclName, - DeclarationName &parentDeclName, + const DeclarationName &parentDeclName, const DeclContext *childCurrentDeclContext) { // Don't do the import if we have a Function Template or using decls. They @@ -104,6 +105,7 @@ namespace cling { // supports their import. if ((declToImport->isFunctionOrFunctionTemplate() && declToImport->isTemplateDecl()) || dyn_cast(declToImport) + || dyn_cast(declToImport) || dyn_cast(declToImport)) { #ifndef NDEBUG utils::DiagnosticsStore DS( @@ -125,14 +127,14 @@ namespace cling { } // Put the name of the Decl imported with the // DeclarationName coming from the parent, in my map. - m_ImportedDecls[childDeclName] = parentDeclName; + m_ImportedDecls.emplace(childDeclName, parentDeclName); } } void ExternalInterpreterSource::ImportDeclContext( DeclContext *declContextToImport, DeclarationName &childDeclName, - DeclarationName &parentDeclName, + const DeclarationName &parentDeclName, const DeclContext *childCurrentDeclContext) { if (DeclContext *importedDeclContext = @@ -148,32 +150,31 @@ namespace cling { // Put the name of the DeclContext imported with the // DeclarationName coming from the parent, in my map. - m_ImportedDecls[childDeclName] = parentDeclName; + m_ImportedDecls.emplace(childDeclName, parentDeclName); // And also put the declaration context I found from the parent Interpreter // in the map of the child Interpreter to have it for the future. - m_ImportedDeclContexts[importedDeclContext] = declContextToImport; + m_ImportedDeclContexts.emplace(importedDeclContext, declContextToImport); } } bool ExternalInterpreterSource::Import(DeclContext::lookup_result lookup_result, const DeclContext *childCurrentDeclContext, DeclarationName &childDeclName, - DeclarationName &parentDeclName) { + const DeclarationName &parentDeclName) { - for (DeclContext::lookup_iterator I = lookup_result.begin(), - E = lookup_result.end(); I != E; ++I) { + for (NamedDecl* ND : lookup_result) { // Check if this Name we are looking for is // a DeclContext (for example a Namespace, function etc.). - if (DeclContext *declContextToImport = llvm::dyn_cast(*I)) { + if (DeclContext *declContextToImport = llvm::dyn_cast(ND)) { ImportDeclContext(declContextToImport, childDeclName, parentDeclName, childCurrentDeclContext); } - ImportDecl(*I, childDeclName, parentDeclName, childCurrentDeclContext); + ImportDecl(ND, childDeclName, parentDeclName, childCurrentDeclContext); } return true; } @@ -190,45 +191,109 @@ namespace cling { assert(childCurrentDeclContext->hasExternalVisibleStorage() && "DeclContext has no visible decls in storage"); + // Search in the map of the stored Decl Contexts for this + // Decl Context. + auto IDeclContext = m_ImportedDeclContexts.find(childCurrentDeclContext); + // If childCurrentDeclContext was found before and is already in the map, + // then do the lookup using the stored pointer. + if (IDeclContext == m_ImportedDeclContexts.end()) + return false; + + DeclContext *parentDC = IDeclContext->second; + //Check if we have already found this declaration Name before DeclarationName parentDeclName; - std::map::iterator IDecl = - m_ImportedDecls.find(childDeclName); + auto IDecl = m_ImportedDecls.find(childDeclName); if (IDecl != m_ImportedDecls.end()) { parentDeclName = IDecl->second; } else { // Get the identifier info from the parent interpreter // for this Name. - std::string name = childDeclName.getAsString(); + const std::string name = childDeclName.getAsString(); IdentifierTable &parentIdentifierTable = m_ParentInterpreter->getCI()->getASTContext().Idents; IdentifierInfo &parentIdentifierInfo = parentIdentifierTable.get(name); parentDeclName = DeclarationName(&parentIdentifierInfo); - } - - // Search in the map of the stored Decl Contexts for this - // Decl Context. - std::map::iterator - IDeclContext = m_ImportedDeclContexts.find(childCurrentDeclContext); - // If childCurrentDeclContext was found before and is already in the map, - // then do the lookup using the stored pointer. - if (IDeclContext == m_ImportedDeclContexts.end()) return false; - DeclContext *parentDeclContext = IDeclContext->second; + // Make sure then lookup name is right, this is an issue looking to import + // a constructor, where lookup_result can hold the injected class name. + // FIXME: Pre-filter childDeclName.getNameKind() and just drop import + // of any unsupported types (i.e. CXXUsingDirective) + const DeclarationName::NameKind ChildKind = childDeclName.getNameKind(); + if (parentDeclName.getNameKind() != ChildKind) { + (void)parentDC->lookup(parentDeclName); + const auto* DM = parentDC->getPrimaryContext()->getLookupPtr(); + assert(DM && "No lookup map"); + for (auto&& Entry : *DM) { + const DeclarationName& DN = Entry.first; + if (DN.getNameKind() == ChildKind) { + if (DN.getAsString() == name) { + parentDeclName = DN; + break; + } + } + } + } + } - DeclContext::lookup_result lookup_result = - parentDeclContext->lookup(parentDeclName); + DeclContext::lookup_result lookup_result = parentDC->lookup(parentDeclName); // Check if we found this Name in the parent interpreter - if (!lookup_result.empty()) { - if (Import(lookup_result, - childCurrentDeclContext, childDeclName, parentDeclName)) - return true; + if (lookup_result.empty()) + return false; + + if (!Import(lookup_result, childCurrentDeclContext, childDeclName, + parentDeclName)) + return false; + + // FIXME: The failure of this to work out of the box seems like a deeper + // issue (in ASTImporter::ImportContext or + // CXXRecordDecl::getVisibleConversionFunctions for example). + + // Constructing or importing a variable of type CXXRecordDecl. + // Import the all constructors, conversion routines, and the destructor. + + const CXXRecordDecl* CXD = dyn_cast(childCurrentDeclContext); + if (!CXD && isa(*lookup_result.begin())) { + assert(lookup_result.size() == 1 && "More than one VarDecl?!"); + CXD = cast(*lookup_result.begin()) + ->getType() + ->getAsCXXRecordDecl(); + if (CXD) + parentDC = cast(const_cast(CXD)); } - return false; + if (!CXD) + return true; + + ASTContext& AST = m_ChildInterpreter->getCI()->getASTContext(); + const auto CanonQT = CXD->getCanonicalDecl() + ->getTypeForDecl() + ->getCanonicalTypeUnqualified(); + const auto* DM = parentDC->getPrimaryContext()->getLookupPtr(); + assert(DM && "No lookup map"); + for (auto&& Entry : *DM) { + const DeclarationName& ParentDN = Entry.first; + const auto ParentKind = ParentDN.getNameKind(); + if (ParentKind < DeclarationName::CXXConstructorName || + ParentKind > DeclarationName::CXXConversionFunctionName) + continue; + + if (m_ImportedDecls.find(childDeclName) == m_ImportedDecls.end()) + continue; + + DeclarationName ChildDN = + AST.DeclarationNames.getCXXSpecialName(ParentDN.getNameKind(), + CanonQT); + // FIXME: DeclContext::Import checks if the decl is a DeclContext. + // Is that neccessary? + DeclContext::lookup_result LR = parentDC->lookup(ParentDN); + if (!LR.empty() && + !Import(LR, childCurrentDeclContext, ChildDN, ParentDN)) + return false; + } + return true; } ///\brief Make available to child all decls in parent's decl context @@ -242,8 +307,7 @@ namespace cling { // Search in the map of the stored Decl Contexts for this // Decl Context. - std::map::iterator - IDeclContext = m_ImportedDeclContexts.find(childDeclContext); + auto IDeclContext = m_ImportedDeclContexts.find(childDeclContext); // If childCurrentDeclContext was found before and is already in the map, // then do the lookup using the stored pointer. if (IDeclContext == m_ImportedDeclContexts.end()) return ; @@ -254,12 +318,8 @@ namespace cling { // stored in Sema. StringRef filter = m_ChildInterpreter->getCI()->getPreprocessor().getCodeCompletionFilter(); - for (DeclContext::decl_iterator IDeclContext = - parentDeclContext->decls_begin(), - EDeclContext = - parentDeclContext->decls_end(); - IDeclContext != EDeclContext; ++IDeclContext) { - if (NamedDecl* parentDecl = llvm::dyn_cast(*IDeclContext)) { + for (Decl* D : parentDeclContext->decls()) { + if (NamedDecl* parentDecl = llvm::dyn_cast(D)) { DeclarationName childDeclName = parentDecl->getDeclName(); if (auto II = childDeclName.getAsIdentifierInfo()) { StringRef name = II->getName(); diff --git a/lib/Interpreter/ExternalInterpreterSource.h b/lib/Interpreter/ExternalInterpreterSource.h index 259b2e8d12..51abf94082 100644 --- a/lib/Interpreter/ExternalInterpreterSource.h +++ b/lib/Interpreter/ExternalInterpreterSource.h @@ -71,16 +71,16 @@ namespace cling { bool Import(clang::DeclContext::lookup_result lookupResult, const clang::DeclContext *childCurrentDeclContext, clang::DeclarationName &childDeclName, - clang::DeclarationName &parentDeclName); + const clang::DeclarationName &parentDeclName); void ImportDeclContext(clang::DeclContext *declContextToImport, clang::DeclarationName &childDeclName, - clang::DeclarationName &parentDeclName, + const clang::DeclarationName &parentDeclName, const clang::DeclContext *childCurrentDeclContext); void ImportDecl(clang::Decl *declToImport, clang::DeclarationName &childDeclName, - clang::DeclarationName &parentDeclName, + const clang::DeclarationName &parentDeclName, const clang::DeclContext *childCurrentDeclContext); void addToImportedDecls(clang::DeclarationName child, diff --git a/test/MultipleInterpreters/MultipleInterpreters.C b/test/MultipleInterpreters/MultipleInterpreters.C index 56b4c5958d..7d26195db2 100644 --- a/test/MultipleInterpreters/MultipleInterpreters.C +++ b/test/MultipleInterpreters/MultipleInterpreters.C @@ -6,18 +6,17 @@ // LICENSE.TXT for details. //------------------------------------------------------------------------------ -// RUN: cat %s | %cling 2>&1 | FileCheck %s +// RUN: cat %s | %cling -Xclang -verify 2>&1 | FileCheck %s // Test to check the functionality of the multiple interpreters. // Create a "child" interpreter and use gCling as its "parent". #include "cling/Interpreter/Interpreter.h" -#include "cling/MetaProcessor/MetaProcessor.h" -// #include "cling/Utils/Output.h" - //Declare something in the parent interpreter int foo(){ return 42; } +struct InParent { operator int() const { return 84; } }; +InParent IP; // OR //gCling->declare("void foo(){ cling::outs() << \"foo(void)\\n\"; }"); @@ -31,7 +30,27 @@ const char* argV[1] = {"cling"}; { cling::Interpreter ChildInterp(*gCling, 1, argV); ChildInterp.declare("void foo(int i){ printf(\"foo(int) = %d\\n\", i); }\n"); - ChildInterp.echo("foo()"); //CHECK: (int) 42 - ChildInterp.echo("foo(1)"); //CHECK: foo(int) = 1 + + ChildInterp.echo("foo()"); + // CHECK: (int) 42 + + ChildInterp.echo("foo(1)"); + // CHECK-NEXT: foo(int) = 1 + + ChildInterp.echo("InParent FC"); + // CHECK-NEXT: (InParent &) @0x{{.*}} + + ChildInterp.echo("static_cast(IP)"); + // CHECK-NEXT: (int) 84 +} + +{ + cling::Interpreter ChildInterp(*gCling, 1, argV); + + ChildInterp.echo("static_cast(IP)"); + // CHECK: (int) 84 } + +// expected-no-diagnostics + .q