diff --git a/.clang-format b/.clang-format index 78e73e07..23d6f8ef 100644 --- a/.clang-format +++ b/.clang-format @@ -14,4 +14,4 @@ IncludeCategories: - Regex: '^"llvm/' Priority: 40 - Regex: '^<' - Priority: 50 \ No newline at end of file + Priority: 50 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55a023e9..fbaf1684 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,6 @@ jobs: clang-runtime: '18' cling: Off cppyy: On - coverage: true - name: ubu24-x86-gcc13-clang-repl-17 os: ubuntu-24.04 compiler: gcc-13 @@ -56,7 +55,6 @@ jobs: cling: On cling-version: '1.0' cppyy: On - coverage: true - name: win2022-msvc-clang-repl-19 os: windows-2022 compiler: msvc @@ -494,7 +492,6 @@ jobs: clang-runtime: '18' cling: Off cppyy: On - coverage: true - name: ubu24-x86-gcc13-clang-repl-17-cppyy os: ubuntu-24.04 compiler: gcc-13 diff --git a/.gitignore b/.gitignore index 1d41d910..faed8be0 100644 --- a/.gitignore +++ b/.gitignore @@ -16,10 +16,6 @@ *.dylib *.dll -# Fortran module files -*.mod -*.smod - # Compiled Static libraries *.lai *.la @@ -36,4 +32,4 @@ build install # CLion files -.idea \ No newline at end of file +.idea diff --git a/CMakeLists.txt b/CMakeLists.txt index 2298a5dd..2bacd081 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,13 +45,6 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR ) option(USE_CLING "Use Cling as backend" OFF) option(USE_REPL "Use clang-repl as backend" OFF) - if (USE_CLING) - add_definitions(-DUSE_CLING) - endif() - if (USE_REPL) - add_definitions(-DUSE_REPL) - endif() - if (USE_CLING AND USE_REPL) message(FATAL_ERROR "We can only use Cling (USE_CLING=On) or Repl (USE_REPL=On), but not both of them.") endif() @@ -226,53 +219,60 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR ) # Fix bug in some AddLLVM.cmake implementation (-rpath "" problem) set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX}) - include(AddLLVM) - include(HandleLLVMOptions) - - set(CMAKE_INCLUDE_CURRENT_DIR ON) + set( CPPINTEROP_BUILT_STANDALONE 1 ) +endif() - # In rare cases we might want to have clang installed in a different place - # than llvm and the header files should be found first (even though the - # LLVM_INCLUDE_DIRS) contain clang headers, too. - if (USE_CLING) - include_directories(SYSTEM ${CLING_INCLUDE_DIRS}) - endif(USE_CLING) - include_directories(SYSTEM ${CLANG_INCLUDE_DIRS}) - include_directories(SYSTEM ${LLVM_INCLUDE_DIRS}) - separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS}) - add_definitions(${LLVM_DEFINITIONS_LIST}) +include(AddLLVM) +include(HandleLLVMOptions) - if (USE_CLING) - message(STATUS "CLING_INCLUDE_DIRS: ${CLING_INCLUDE_DIRS}") - endif(USE_CLING) - message(STATUS "CLANG_INCLUDE_DIRS: ${CLANG_INCLUDE_DIRS}") - message(STATUS "LLVM_INCLUDE_DIRS: ${LLVM_INCLUDE_DIRS}") - message(STATUS "LLVM_DEFINITIONS_LIST: ${LLVM_DEFINITIONS_LIST}") - - # If the llvm sources are present add them with higher priority. - if (LLVM_BUILD_MAIN_SRC_DIR) - # LLVM_INCLUDE_DIRS contains the include paths to both LLVM's source and - # build directories. Since we cannot just include ClangConfig.cmake (see - # fixme above) we have to do a little more work to get the right include - # paths for clang. - # - # FIXME: We only support in-tree builds of clang, that is clang being built - # in llvm_src/tools/clang. - include_directories(SYSTEM ${LLVM_BUILD_MAIN_SRC_DIR}/tools/clang/include/) - - if (NOT LLVM_BUILD_BINARY_DIR) - message(FATAL "LLVM_BUILD_* values should be available for the build tree") - endif() +set(CMAKE_INCLUDE_CURRENT_DIR ON) - include_directories(SYSTEM ${LLVM_BUILD_BINARY_DIR}/tools/clang/include/) +# In rare cases we might want to have clang installed in a different place +# than llvm and the header files should be found first (even though the +# LLVM_INCLUDE_DIRS) contain clang headers, too. +if (USE_CLING) + add_definitions(-DUSE_CLING) + include_directories(SYSTEM ${CLING_INCLUDE_DIRS}) + else() + if (NOT USE_REPL) + message(FATAL_ERROR "We need either USE_CLING or USE_REPL") + endif() + add_definitions(-DUSE_REPL) + +endif(USE_CLING) +include_directories(SYSTEM ${CLANG_INCLUDE_DIRS}) +include_directories(SYSTEM ${LLVM_INCLUDE_DIRS}) +separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS}) +add_definitions(${LLVM_DEFINITIONS_LIST}) + +if (USE_CLING) + message(STATUS "CLING_INCLUDE_DIRS: ${CLING_INCLUDE_DIRS}") +endif(USE_CLING) +message(STATUS "CLANG_INCLUDE_DIRS: ${CLANG_INCLUDE_DIRS}") +message(STATUS "LLVM_INCLUDE_DIRS: ${LLVM_INCLUDE_DIRS}") +message(STATUS "LLVM_DEFINITIONS_LIST: ${LLVM_DEFINITIONS_LIST}") + +# If the llvm sources are present add them with higher priority. +if (LLVM_BUILD_MAIN_SRC_DIR) + # LLVM_INCLUDE_DIRS contains the include paths to both LLVM's source and + # build directories. Since we cannot just include ClangConfig.cmake (see + # fixme above) we have to do a little more work to get the right include + # paths for clang. + # + # FIXME: We only support in-tree builds of clang, that is clang being built + # in llvm_src/tools/clang. + include_directories(SYSTEM ${LLVM_BUILD_MAIN_SRC_DIR}/tools/clang/include/) + + if (NOT LLVM_BUILD_BINARY_DIR) + message(FATAL "LLVM_BUILD_* values should be available for the build tree") endif() - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib/) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/) - - set( CPPINTEROP_BUILT_STANDALONE 1 ) + include_directories(SYSTEM ${LLVM_BUILD_BINARY_DIR}/tools/clang/include/) endif() +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib/) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/) + ## Code Coverage Configuration add_library(coverage_config INTERFACE) option(CODE_COVERAGE "Enable coverage reporting" OFF) diff --git a/include/clang/Interpreter/CppInterOp.h b/include/clang/Interpreter/CppInterOp.h index 2cbb66c6..9e818cd6 100644 --- a/include/clang/Interpreter/CppInterOp.h +++ b/include/clang/Interpreter/CppInterOp.h @@ -77,7 +77,8 @@ namespace Cpp { /// function, constructor or destructor. class JitCall { public: - friend CPPINTEROP_API JitCall MakeFunctionCallable(TCppConstFunction_t); + friend CPPINTEROP_API JitCall + MakeFunctionCallable(TInterp_t I, TCppConstFunction_t func); enum Kind : char { kUnknown = 0, kGenericCall, @@ -262,16 +263,16 @@ namespace Cpp { /// This is similar to GetName() function, but besides /// the name, it also gets the template arguments. - CPPINTEROP_API std::string GetCompleteName(TCppType_t klass); + CPPINTEROP_API std::string GetCompleteName(TCppScope_t klass); /// Gets the "qualified" name (including the namespace) of any /// named decl (a class, namespace, variable, or a function). - CPPINTEROP_API std::string GetQualifiedName(TCppType_t klass); + CPPINTEROP_API std::string GetQualifiedName(TCppScope_t klass); /// This is similar to GetQualifiedName() function, but besides /// the "qualified" name (including the namespace), it also /// gets the template arguments. - CPPINTEROP_API std::string GetQualifiedCompleteName(TCppType_t klass); + CPPINTEROP_API std::string GetQualifiedCompleteName(TCppScope_t klass); /// Gets the list of namespaces utilized in the supplied scope. CPPINTEROP_API std::vector GetUsingNamespaces(TCppScope_t scope); @@ -307,13 +308,13 @@ namespace Cpp { /// Gets the number of Base Classes for the Derived Class that /// is passed as a parameter. - CPPINTEROP_API TCppIndex_t GetNumBases(TCppType_t klass); + CPPINTEROP_API TCppIndex_t GetNumBases(TCppScope_t klass); /// Gets a specific Base Class using its index. Typically GetNumBases() /// is used to get the number of Base Classes, and then that number /// can be used to iterate through the index value to get each specific /// base class. - CPPINTEROP_API TCppScope_t GetBaseClass(TCppType_t klass, TCppIndex_t ibase); + CPPINTEROP_API TCppScope_t GetBaseClass(TCppScope_t klass, TCppIndex_t ibase); /// Checks if the supplied Derived Class is a sub-class of the /// provided Base Class. @@ -496,6 +497,9 @@ namespace Cpp { /// uniform interface to call it from compiled code. CPPINTEROP_API JitCall MakeFunctionCallable(TCppConstFunction_t func); + CPPINTEROP_API JitCall MakeFunctionCallable(TInterp_t I, + TCppConstFunction_t func); + /// Checks if a function declared is of const type or not. CPPINTEROP_API bool IsConstMethod(TCppFunction_t method); diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index 434952e9..b757cd23 100644 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -857,7 +857,7 @@ namespace Cpp { TCppIndex_t GetFunctionRequiredArgs(TCppConstFunction_t func) { - auto *D = (const clang::Decl *) func; + const auto* D = static_cast(func); if (auto* FD = llvm::dyn_cast_or_null(D)) return FD->getMinRequiredArguments(); @@ -923,7 +923,8 @@ namespace Cpp { } bool IsFunctionDeleted(TCppConstFunction_t function) { - auto *FD = cast((const clang::Decl*)function); + const auto* FD = + cast(static_cast(function)); return FD->isDeleted(); } @@ -1054,7 +1055,8 @@ namespace Cpp { bool IsMethod(TCppConstFunction_t method) { - return dyn_cast_or_null((const clang::Decl*)method); + return dyn_cast_or_null( + static_cast(method)); } bool IsPublicMethod(TCppFunction_t method) @@ -1073,18 +1075,18 @@ namespace Cpp { bool IsConstructor(TCppConstFunction_t method) { - auto *D = (const Decl *) method; + const auto* D = static_cast(method); return llvm::isa_and_nonnull(D); } bool IsDestructor(TCppConstFunction_t method) { - auto *D = (const Decl *) method; + const auto* D = static_cast(method); return llvm::isa_and_nonnull(D); } bool IsStaticMethod(TCppConstFunction_t method) { - const auto* D = (const Decl*)method; + const auto* D = static_cast(method); if (auto *CXXMD = llvm::dyn_cast_or_null(D)) { return CXXMD->isStatic(); } @@ -1207,13 +1209,11 @@ namespace Cpp { return 0; } - intptr_t GetVariableOffset(TCppScope_t var) - { - if (!var) + intptr_t GetVariableOffset(compat::Interpreter& I, Decl* D) { + if (!D) return 0; - auto *D = (Decl *) var; - auto &C = getASTContext(); + auto& C = I.getSema().getASTContext(); if (auto* FD = llvm::dyn_cast(D)) { const clang::RecordDecl* RD = FD->getParent(); @@ -1242,7 +1242,7 @@ namespace Cpp { compat::maybeMangleDeclName(GD, mangledName); void* address = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol( mangledName.c_str()); - auto &I = getInterp(); + if (!address) address = I.getAddressOfGlobal(GD); if (!address) { @@ -1292,6 +1292,11 @@ namespace Cpp { return 0; } + intptr_t GetVariableOffset(TCppScope_t var) { + auto* D = static_cast(var); + return GetVariableOffset(getInterp(), D); + } + // Check if the Access Specifier of the variable matches the provided value. bool CheckVariableAccess(TCppScope_t var, AccessSpecifier AS) { @@ -2574,26 +2579,32 @@ namespace Cpp { } // namespace // End of JitCall Helper Functions - CPPINTEROP_API JitCall MakeFunctionCallable(TCppConstFunction_t func) { - auto* D = (const clang::Decl*)func; - if (!D) - return {}; + CPPINTEROP_API JitCall MakeFunctionCallable(TInterp_t I, + TCppConstFunction_t func) { + const auto* D = static_cast(func); + if (!D) + return {}; - auto& I = getInterp(); - // FIXME: Unify with make_wrapper. - if (auto *Dtor = dyn_cast(D)) { - if (auto Wrapper = make_dtor_wrapper(I, Dtor->getParent())) - return {JitCall::kDestructorCall, Wrapper, Dtor}; + auto* interp = static_cast(I); + + // FIXME: Unify with make_wrapper. + if (const auto* Dtor = dyn_cast(D)) { + if (auto Wrapper = make_dtor_wrapper(*interp, Dtor->getParent())) + return {JitCall::kDestructorCall, Wrapper, Dtor}; + // FIXME: else error we failed to compile the wrapper. + return {}; + } + + if (auto Wrapper = make_wrapper(*interp, cast(D))) { + return {JitCall::kGenericCall, Wrapper, cast(D)}; + } // FIXME: else error we failed to compile the wrapper. return {}; } - if (auto Wrapper = make_wrapper(I, cast(D))) { - return {JitCall::kGenericCall, Wrapper, cast(D)}; + CPPINTEROP_API JitCall MakeFunctionCallable(TCppConstFunction_t func) { + return MakeFunctionCallable(&getInterp(), func); } - // FIXME: else error we failed to compile the wrapper. - return {}; - } namespace { static std::string MakeResourcesPath() { @@ -2842,7 +2853,8 @@ namespace Cpp { return DLM->searchLibrariesForSymbol(mangled_name, search_system); } - bool InsertOrReplaceJitSymbol(const char* linker_mangled_name, + bool InsertOrReplaceJitSymbol(compat::Interpreter& I, + const char* linker_mangled_name, uint64_t address) { // FIXME: This approach is problematic since we could replace a symbol // whose address was already taken by clients. @@ -2869,7 +2881,6 @@ namespace Cpp { using namespace llvm; using namespace llvm::orc; - auto& I = getInterp(); auto Symbol = compat::getSymbolAddress(I, linker_mangled_name); llvm::orc::LLJIT& Jit = *compat::getExecutionEngine(I); llvm::orc::ExecutionSession& ES = Jit.getExecutionSession(); @@ -2930,6 +2941,11 @@ namespace Cpp { return false; } + bool InsertOrReplaceJitSymbol(const char* linker_mangled_name, + uint64_t address) { + return InsertOrReplaceJitSymbol(getInterp(), linker_mangled_name, address); + } + std::string ObjToString(const char *type, void *obj) { return getInterp().toString(type, obj); } @@ -2979,9 +2995,8 @@ namespace Cpp { // return C.getElaboratedType(ETK_None, NS, TT); } - static Decl* InstantiateTemplate(TemplateDecl* TemplateD, - ArrayRef TemplateArgs, - Sema& S) { + Decl* InstantiateTemplate(TemplateDecl* TemplateD, + ArrayRef TemplateArgs, Sema& S) { // Create a list of template arguments. TemplateArgumentListInfo TLI{}; for (auto TA : TemplateArgs) @@ -2991,10 +3006,11 @@ namespace Cpp { return InstantiateTemplate(TemplateD, TLI, S); } - TCppScope_t InstantiateTemplate(TCppScope_t tmpl, + TCppScope_t InstantiateTemplate(compat::Interpreter& I, TCppScope_t tmpl, const TemplateArgInfo* template_args, size_t template_args_size) { - ASTContext &C = getASTContext(); + auto& S = I.getSema(); + auto& C = S.getASTContext(); llvm::SmallVector TemplateArgs; TemplateArgs.reserve(template_args_size); @@ -3015,9 +3031,16 @@ namespace Cpp { // We will create a new decl, push a transaction. #ifdef USE_CLING - cling::Interpreter::PushTransactionRAII RAII(&getInterp()); + cling::Interpreter::PushTransactionRAII RAII(&I); #endif - return InstantiateTemplate(TmplD, TemplateArgs, getSema()); + return InstantiateTemplate(TmplD, TemplateArgs, S); + } + + TCppScope_t InstantiateTemplate(TCppScope_t tmpl, + const TemplateArgInfo* template_args, + size_t template_args_size) { + return InstantiateTemplate(getInterp(), tmpl, template_args, + template_args_size); } void GetClassTemplateInstantiationArgs(TCppScope_t templ_instance, @@ -3241,15 +3264,15 @@ namespace Cpp { } // FIXME: Add optional arguments to the operator new. - TCppObject_t Construct(TCppScope_t scope, - void* arena/*=nullptr*/) { + TCppObject_t Construct(compat::Interpreter& interp, TCppScope_t scope, + void* arena /*=nullptr*/) { auto* Class = (Decl*) scope; // FIXME: Diagnose. if (!HasDefaultConstructor(Class)) return nullptr; auto* const Ctor = GetDefaultConstructor(Class); - if (JitCall JC = MakeFunctionCallable(Ctor)) { + if (JitCall JC = MakeFunctionCallable(&interp, Ctor)) { if (arena) { JC.Invoke(&arena, {}, (void*)~0); // Tell Invoke to use placement new. return arena; @@ -3262,15 +3285,24 @@ namespace Cpp { return nullptr; } - void Destruct(TCppObject_t This, TCppScope_t scope, bool withFree /*=true*/) { - Decl* Class = (Decl*)scope; - if (auto wrapper = make_dtor_wrapper(getInterp(), Class)) { + TCppObject_t Construct(TCppScope_t scope, void* arena /*=nullptr*/) { + return Construct(getInterp(), scope, arena); + } + + void Destruct(compat::Interpreter& interp, TCppObject_t This, Decl* Class, + bool withFree) { + if (auto wrapper = make_dtor_wrapper(interp, Class)) { (*wrapper)(This, /*nary=*/0, withFree); return; } // FIXME: Diagnose. } + void Destruct(TCppObject_t This, TCppScope_t scope, bool withFree /*=true*/) { + auto* Class = static_cast(scope); + Destruct(getInterp(), This, Class, withFree); + } + class StreamCaptureInfo { std::unique_ptr m_TempFile; int m_FD = -1;