From 91dd1957ada40203edcfe18d7e236a4511f4af7e Mon Sep 17 00:00:00 2001 From: Javier Lopez-Gomez Date: Tue, 29 Aug 2023 16:43:05 +0200 Subject: [PATCH 1/8] [cling] DeclUnloader: remove StaticVarCollector StaticVarCollector recursively visited descendants of a `FunctionDecl` node to collect static local variables. However, these always appear in the enclosing DeclContext. (cherry picked from commit bd28a5b793947c1b777edb376c35062da409281b) --- .../cling/lib/Interpreter/DeclUnloader.cpp | 31 +++++-------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/interpreter/cling/lib/Interpreter/DeclUnloader.cpp b/interpreter/cling/lib/Interpreter/DeclUnloader.cpp index 25c01b1ef3c0b..6f7fe4746aba1 100644 --- a/interpreter/cling/lib/Interpreter/DeclUnloader.cpp +++ b/interpreter/cling/lib/Interpreter/DeclUnloader.cpp @@ -327,24 +327,6 @@ namespace { } } - typedef llvm::SmallVector Vars; - class StaticVarCollector : public RecursiveASTVisitor { - Vars& m_V; - - public: - StaticVarCollector(FunctionDecl* FD, Vars& V) : m_V(V) { - TraverseStmt(FD->getBody()); - } - bool VisitDeclStmt(DeclStmt* DS) { - for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end(); - I != E; ++I) - if (VarDecl* VD = dyn_cast(*I)) - if (VD->isStaticLocal()) - m_V.push_back(VD); - return true; - } - }; - // Template instantiation of templated function first creates a canonical // declaration and after the actual template specialization. For example: // template T TemplatedF(T t); @@ -677,15 +659,18 @@ namespace cling { // which we will remove soon. (Eg. mangleDeclName iterates the redecls) GlobalDecl GD(FD); MaybeRemoveDeclFromModule(GD); + // Handle static locals. void func() { static int var; } is represented in // the llvm::Module is a global named @func.var - Vars V; - StaticVarCollector c(FD, V); - for (Vars::iterator I = V.begin(), E = V.end(); I != E; ++I) { - GlobalDecl GD(*I); - MaybeRemoveDeclFromModule(GD); + for (auto D : FunctionDecl::castToDeclContext(FD)->noload_decls()) { + if (auto VD = dyn_cast(D)) + if (VD->isStaticLocal()) { + GlobalDecl GD(VD); + MaybeRemoveDeclFromModule(GD); + } } } + // VisitRedeclarable() will mess around with this! bool wasCanonical = FD->isCanonicalDecl(); // FunctionDecl : DeclaratiorDecl, DeclContext, Redeclarable From d1689c06fa189d7ad2718a54608b44342eb85ed3 Mon Sep 17 00:00:00 2001 From: Javier Lopez-Gomez Date: Tue, 29 Aug 2023 16:43:05 +0200 Subject: [PATCH 2/8] [cling] DeclUnloader: do not delete instantiated member functions The body of member functions of a templated class only gets instantiated when the function is used. These `CXXMethodDecl` should not be deleted from the AST; instead return them to the 'instantiation pending' state. (cherry picked from commit afba1d737aeafd554ac4763fcc2d542de961be2a) --- .../cling/lib/Interpreter/DeclUnloader.cpp | 30 +++++++++++++++++++ .../cling/test/CodeUnloading/Classes.C | 20 ++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/interpreter/cling/lib/Interpreter/DeclUnloader.cpp b/interpreter/cling/lib/Interpreter/DeclUnloader.cpp index 6f7fe4746aba1..21cdd678de2ac 100644 --- a/interpreter/cling/lib/Interpreter/DeclUnloader.cpp +++ b/interpreter/cling/lib/Interpreter/DeclUnloader.cpp @@ -678,6 +678,36 @@ namespace cling { // DeclContext and when trying to remove them we need the full redecl chain // still in place. bool Successful = VisitDeclContext(FD); + // The body of member functions of a templated class only gets instantiated + // when the function is used, i.e. + // `-ClassTemplateDecl + // |-TemplateTypeParmDecl referenced typename depth 0 index 0 T + // |-CXXRecordDecl struct Foo definition + // | |-DefinitionData + // | `-CXXMethodDecl f 'T (T)' + // | |-ParmVarDecl 0x55e5787cac70 referenced x 'T' + // | `-CompoundStmt + // | `-ReturnStmt + // | `-DeclRefExpr 'T' lvalue ParmVar 0x55e5787cac70 'x' 'T' + // `-ClassTemplateSpecializationDecl struct Foo definition + // |-DefinitionData + // |-TemplateArgument type 'int' + // | `-BuiltinType 'int' + // |-CXXMethodDecl f 'int (int)' <<<< Instantiation pending + // | `-ParmVarDecl x 'int':'int' + // |-CXXConstructorDecl implicit used constexpr Foo 'void () noexcept' + // inline default trivial + // + // Such functions should not be deleted from the AST, but returned to the + // 'pending instantiation' state. + if (auto MSI = FD->getMemberSpecializationInfo()) { + MSI->setPointOfInstantiation(SourceLocation()); + MSI->setTemplateSpecializationKind( + TemplateSpecializationKind::TSK_ImplicitInstantiation); + FD->setBody(nullptr); + FD->setInstantiationIsPending(true); + return Successful; + } Successful &= VisitRedeclarable(FD, FD->getDeclContext()); Successful &= VisitDeclaratorDecl(FD); diff --git a/interpreter/cling/test/CodeUnloading/Classes.C b/interpreter/cling/test/CodeUnloading/Classes.C index 76afb20f37602..fc30502658b92 100644 --- a/interpreter/cling/test/CodeUnloading/Classes.C +++ b/interpreter/cling/test/CodeUnloading/Classes.C @@ -8,6 +8,9 @@ // RUN: cat %s | %cling 2>&1 | FileCheck %s +#include +#include + extern "C" int printf(const char* fmt, ...); .storeState "preUnload" class MyClass{ @@ -22,5 +25,20 @@ public: .compareState "preUnload" //CHECK-NOT: Differences float MyClass = 1.1 -//CHECK: (float) 1.1 +//CHECK: (float) 1.10000f + +template +struct MyStruct { T f(T x) { return x; } }; +MyStruct obj; +obj.f(42.0) +//CHECK: (float) 42.0000f +.undo +obj.f(42.0) +//CHECK: (float) 42.0000f + +auto p = std::make_unique("string"); +(unsigned long)p.size() // expected-error{{no member named 'size' in 'std::unique_ptr>'; did you mean to use '->' instead of '.'?}} +(unsigned long)p->size() +//CHECK: (unsigned long) 6 + .q From 8e1dde2b92ad6dfb79105be168a188086a4b78e4 Mon Sep 17 00:00:00 2001 From: Jonas Hahnfeld Date: Fri, 24 Nov 2023 14:39:34 +0100 Subject: [PATCH 3/8] [cling] DeclUnloader: Remove extra check isInstantiatedInPCH This effectively reverts commit 74472caaa9 ("[cling] Fixes issue in DeclUnloader: do not unload templates intantiated in the PCH"), it's not needed anymore, all tests pass and the snippet in the summary of https://github.com/root-project/root/pull/4447 works, but it filters too many declarations from the unloader. (cherry picked from commit 1c3ea0a068bc22eacf0dee087d8e3e2801b8018d) --- .../cling/lib/Interpreter/DeclUnloader.cpp | 15 --------------- interpreter/cling/lib/Interpreter/DeclUnloader.h | 4 +--- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/interpreter/cling/lib/Interpreter/DeclUnloader.cpp b/interpreter/cling/lib/Interpreter/DeclUnloader.cpp index 21cdd678de2ac..85874db9a5f42 100644 --- a/interpreter/cling/lib/Interpreter/DeclUnloader.cpp +++ b/interpreter/cling/lib/Interpreter/DeclUnloader.cpp @@ -473,21 +473,6 @@ namespace { namespace cling { using namespace clang; - ///\brief Return whether `D' is a template that was first instantiated non- - /// locally, i.e. in a PCH/module. If `D' is not an instantiation, return - /// false. - bool DeclUnloader::isInstantiatedInPCH(const Decl* D) { - SourceManager& SM = D->getASTContext().getSourceManager(); - if (const auto FD = dyn_cast(D)) - return FD->isTemplateInstantiation() && - !SM.isLocalSourceLocation(FD->getPointOfInstantiation()); - else if (const auto CTSD = dyn_cast(D)) - return !SM.isLocalSourceLocation(CTSD->getPointOfInstantiation()); - else if (const auto VTSD = dyn_cast(D)) - return !SM.isLocalSourceLocation(VTSD->getPointOfInstantiation()); - return false; - } - void DeclUnloader::resetDefinitionData(TagDecl* decl) { auto canon = dyn_cast(decl->getCanonicalDecl()); assert(canon && "Only CXXRecordDecl have DefinitionData"); diff --git a/interpreter/cling/lib/Interpreter/DeclUnloader.h b/interpreter/cling/lib/Interpreter/DeclUnloader.h index 500fa7f6d1e4e..b5829155a96d6 100644 --- a/interpreter/cling/lib/Interpreter/DeclUnloader.h +++ b/interpreter/cling/lib/Interpreter/DeclUnloader.h @@ -60,7 +60,7 @@ namespace cling { ///\returns true on success. /// bool UnloadDecl(clang::Decl* D) { - if (D->isFromASTFile() || isInstantiatedInPCH(D)) + if (D->isFromASTFile()) return true; return Visit(D); } @@ -270,8 +270,6 @@ namespace cling { /// void CollectFilesToUncache(clang::SourceLocation Loc); - bool isInstantiatedInPCH(const clang::Decl *D); - template bool VisitRedeclarable(clang::Redeclarable* R, clang::DeclContext* DC); }; From 02e9b5153aa56d2a370c784ac895cfcc8e8fa04a Mon Sep 17 00:00:00 2001 From: Vassil Vassilev Date: Fri, 21 Jul 2023 11:58:46 +0000 Subject: [PATCH 4/8] [cling] Handle llvm::Errors correctly. This fixes several tests on osx. (cherry picked from commit 10510eddef1591956aba86e878beda36967403e5) --- .../cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp | 6 +++++- interpreter/cling/lib/Interpreter/IncrementalJIT.cpp | 6 ++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp b/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp index 3e7fbd6dc7aab..0df740088617e 100644 --- a/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp +++ b/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp @@ -1141,9 +1141,13 @@ namespace cling { auto ObjF = llvm::object::ObjectFile::createObjectFile(FileName); if (!ObjF) { + std::string Message; + handleAllErrors(ObjF.takeError(), [&](llvm::ErrorInfoBase &EIB) { + Message += EIB.message() + "; "; + }); if (DEBUG > 1) cling::errs() << "[DyLD] Failed to read object file " - << FileName << "\n"; + << FileName << ". Message: '" << Message << "\n"; return true; } diff --git a/interpreter/cling/lib/Interpreter/IncrementalJIT.cpp b/interpreter/cling/lib/Interpreter/IncrementalJIT.cpp index 09ad059a547a8..fd9930c406304 100644 --- a/interpreter/cling/lib/Interpreter/IncrementalJIT.cpp +++ b/interpreter/cling/lib/Interpreter/IncrementalJIT.cpp @@ -425,8 +425,10 @@ class DelegateGenerator : public DefinitionGenerator { const SymbolLookupSet& LookupSet) override { SymbolMap Symbols; for (auto& KV : LookupSet) { - if (auto Addr = lookup(*KV.first)) - Symbols[KV.first] = Addr.get(); + auto Addr = lookup(*KV.first); + if (auto Err = Addr.takeError()) + return Err; + Symbols[KV.first] = Addr.get(); } if (Symbols.empty()) return Error::success(); From 9272103c4b2b8d126bb00da02ab65e85848b3ced Mon Sep 17 00:00:00 2001 From: Vassil Vassilev Date: Fri, 21 Jul 2023 11:59:08 +0000 Subject: [PATCH 5/8] [cling] Correctly infer the SDKROOT. This fixes the -lSystem issues we saw on recent osx platforms. (cherry picked from commit 51c26e882d8e1704e2c8936df50a455dcb8730e8) --- interpreter/cling/test/lit.cfg | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interpreter/cling/test/lit.cfg b/interpreter/cling/test/lit.cfg index d1b480bc27a0a..a1ba0d92b199a 100644 --- a/interpreter/cling/test/lit.cfg +++ b/interpreter/cling/test/lit.cfg @@ -68,7 +68,6 @@ llvm_config.with_system_environment( config.substitutions.append(('%PATH%', config.environment['PATH'])) - # We want to invoke the system clang. Or not? config.substitutions = [x for x in config.substitutions if x[0] != ' clang '] @@ -109,6 +108,8 @@ config.substitutions.append(('%shlibext', config.shlibext)) if platform.system() not in ['Windows'] or lit_config.getBashPath() != '': config.available_features.add('shell') +lit.util.usePlatformSdkOnDarwin(config, lit_config) + # ROOT adds features that "heal" some of cling's tests; need to detect # vanilla vs cling-as-part-of-ROOT. The latter has no `lib/UserInterface/textinput/`: if os.path.isdir(os.path.join(config.cling_src_root, 'lib', 'UserInterface', 'textinput')): From 75079c858cce770b06ff3fcd45ce65568c4a6dd7 Mon Sep 17 00:00:00 2001 From: Axel Naumann Date: Tue, 5 Dec 2023 15:10:46 +0100 Subject: [PATCH 6/8] [cling] test/Driver/CommandHistory.C: `env -u` also works on macOS. (cherry picked from commit 7a0481bc0a7f6260e207f7de3c5114a9f703b3aa) --- interpreter/cling/test/Driver/CommandHistory.C | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interpreter/cling/test/Driver/CommandHistory.C b/interpreter/cling/test/Driver/CommandHistory.C index aefda3ce02a41..e00071d64ecbc 100644 --- a/interpreter/cling/test/Driver/CommandHistory.C +++ b/interpreter/cling/test/Driver/CommandHistory.C @@ -8,7 +8,7 @@ // clang-format off // RUN: %rm /tmp/__testing_cling_history -// RUN: cat %s | env --unset=CLING_NOHISTORY CLING_HISTSIZE=8 CLING_HISTFILE="/tmp/__testing_cling_history" %cling - 2>&1 +// RUN: cat %s | env -u CLING_NOHISTORY CLING_HISTSIZE=8 CLING_HISTFILE="/tmp/__testing_cling_history" %cling - 2>&1 // RUN: diff /tmp/__testing_cling_history "%S/Inputs/cling_history" // UNSUPPORTED: system-windows From 7dd6a2de80a153391ae80aefa4417f5b7420d5f0 Mon Sep 17 00:00:00 2001 From: Jonas Hahnfeld Date: Tue, 5 Dec 2023 14:28:02 +0100 Subject: [PATCH 7/8] [cling] Provide fallback for LLVM_INCLUDE_DIRS In standalone builds, it could otherwise happen that the variable is not set during the first CMake invocation and tests fail because they are unable to locate the LLVM headers. (cherry picked from commit e84a7964b4b10f9fd3c751af9e8562cabcf1fb97) --- interpreter/cling/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interpreter/cling/CMakeLists.txt b/interpreter/cling/CMakeLists.txt index 75a4a84ec6006..34e0c65cb000b 100644 --- a/interpreter/cling/CMakeLists.txt +++ b/interpreter/cling/CMakeLists.txt @@ -190,6 +190,9 @@ else() set (CLANG_INCLUDE_DIRS "${CLANG_INCLUDE_DIRS}" "${LLVM_BINARY_DIR}/tools/clang/include") endif() + if (NOT LLVM_INCLUDE_DIRS) + set (LLVM_INCLUDE_DIRS "${LLVM_MAIN_SRC_DIR}/include" "${LLVM_BINARY_DIR}/include") + endif() endif() if( NOT "NVPTX" IN_LIST LLVM_TARGETS_TO_BUILD) From 8333b22e1839509cdfb472b57f5f42edac54896d Mon Sep 17 00:00:00 2001 From: Axel Naumann Date: Fri, 8 Dec 2023 11:30:11 +0100 Subject: [PATCH 8/8] Revert "[Cling] Simplify std::tuple/pair value printer" This reverts commit bfbb58e6f74c38b883ce6e6e096b6c6e44028869. (backported as c49d7924555eea22ce8f7c0fa70870e144b17845) cling needs to be able to interpret C++11, even if built with C++17. (cherry picked from commit 06cdb2ae613624847ab6edd146f57b6447e046a7) --- .../cling/Interpreter/RuntimePrintValue.h | 74 +++++++++++++++---- 1 file changed, 59 insertions(+), 15 deletions(-) diff --git a/interpreter/cling/include/cling/Interpreter/RuntimePrintValue.h b/interpreter/cling/include/cling/Interpreter/RuntimePrintValue.h index 2231c46751ba8..0924b94024879 100644 --- a/interpreter/cling/include/cling/Interpreter/RuntimePrintValue.h +++ b/interpreter/cling/include/cling/Interpreter/RuntimePrintValue.h @@ -245,23 +245,67 @@ namespace cling { return str + " }"; } - // Tuples and pairs - template