diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b9464cd9e..c96361aed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,13 +22,21 @@ jobs: matrix: include: - name: ubu22-gcc12-clang-repl-17 - os: ubuntu-latest + os: ubuntu-22.04 compiler: gcc-12 clang-runtime: '17' cling: Off cppyy: Off extra_cmake_options: '-DLLVM_USE_LINKER=lld' + - name: ubu22-gcc12-clang-repl-17-cppyy + os: ubuntu-22.04 + compiler: gcc-12 + clang-runtime: '17' + cling: Off + cppyy: On + extra_cmake_options: '-DLLVM_USE_LINKER=lld' + - name: ubu22-gcc9-clang-repl-16 os: ubuntu-22.04 compiler: gcc-9 @@ -38,11 +46,21 @@ jobs: coverage: true extra_cmake_options: '-DLLVM_USE_LINKER=lld' + - name: ubu22-gcc9-clang-repl-16-cppyy + os: ubuntu-22.04 + compiler: gcc-9 + clang-runtime: '16' + cling: Off + cppyy: On + coverage: true + extra_cmake_options: '-DLLVM_USE_LINKER=lld' + - name: ubu22-gcc9-clang13-cling os: ubuntu-22.04 compiler: gcc-9 clang-runtime: '13' cling: On + cling-version: '1.0' cppyy: Off extra_cmake_options: '-DLLVM_USE_LINKER=lld' @@ -51,23 +69,101 @@ jobs: compiler: gcc-9 clang-runtime: '13' cling: On + cling-version: '1.0' cppyy: On extra_cmake_options: '-DLLVM_USE_LINKER=lld' - - name: osx-clang-clang-repl-16 - os: macos-latest + - name: osx13-x86-clang-clang-repl-17 + os: macos-13 + compiler: clang + clang-runtime: '17' + cling: Off + cppyy: Off + + - name: osx13-x86-clang-clang-repl-17-cppyy + os: macos-13 + compiler: clang + clang-runtime: '17' + cling: Off + cppyy: On + + - name: osx13-x86-clang-clang-repl-16 + os: macos-13 compiler: clang clang-runtime: '16' cling: Off cppyy: Off - - name: osx-clang-clang13-cling - os: macos-latest + - name: osx13-x86-clang-clang-repl-16-cppyy + os: macos-13 + compiler: clang + clang-runtime: '16' + cling: Off + cppyy: On + + - name: osx13-x86-clang-clang13-cling + os: macos-13 compiler: clang clang-runtime: '13' cling: On + cling-version: '1.0' cppyy: Off + - name: osx13-x86-clang-clang13-cling-cppyy + os: macos-13 + compiler: clang + clang-runtime: '13' + cling: On + cling-version: '1.0' + cppyy: On + + #Block commented out until free tier for m1 + #exists (expected sometime 2024) and key for os + #can be replaced + #- name: osx13-arm64-clang-clang-repl-17 + # os: macos-13-arm64 + # compiler: clang + # clang-runtime: '17' + # cling: Off + # cppyy: Off + # + #- name: osx13-arm64-clang-clang-repl-17-cppyy + # os: macos-13-arm64 + # compiler: clang + # clang-runtime: '17' + # cling: Off + # cppyy: On + # + #- name: osx13-arm64-clang-clang-repl-16 + # os: macos-13-arm64 + # compiler: clang + # clang-runtime: '16' + # cling: Off + # cppyy: Off + # + #- name: osx13-arm64-clang-clang-repl-16-cppyy + # os: macos-13-arm64 + # compiler: clang + # clang-runtime: '16' + # cling: Off + # cppyy: On + # + #- name: osx13-arm64-clang-clang13-cling + # os: macos-13-arm64 + # compiler: clang + # clang-runtime: '13' + # cling: On + # cling-version: '1.0' + # cppyy: Off + # + #- name: osx13-arm64-clang-clang13-cling-cppyy + # os: macos-13-arm64 + # compiler: clang + # clang-runtime: '13' + # cling: On + # cling-version: '1.0' + # cppyy: On + steps: - uses: actions/checkout@v3 with: @@ -141,8 +237,11 @@ jobs: echo "CXX=g++-${vers}" >> $GITHUB_ENV else echo "SDKROOT=$(xcrun --sdk macosx --show-sdk-path)" >> $GITHUB_ENV - echo "CC=clang" >> $GITHUB_ENV - echo "CXX=clang++" >> $GITHUB_ENV + #Use clang-15 and clang++-15 compiler that is installed on runner, instead of one + #provided by MacOS (could brew install clang-16/17 to use consistent version + #of clang) + echo "CC=$(brew --prefix llvm@15)/bin/clang" >> $GITHUB_ENV + echo "CXX=$(brew --prefix llvm@15)/bin/clang++" >> $GITHUB_ENV fi env: compiler: ${{ matrix.compiler }} @@ -160,7 +259,12 @@ jobs: - name: Install deps on MacOS if: runner.os == 'macOS' run: | - brew install git gcc gnupg python@3 + #gcc, gnupg and python3 installed on Github runner + #brew install git gcc gnupg python@3 + #Select latest xcode available on macos-13 + sudo xcode-select -s /Applications/Xcode_15.1.app/Contents/Developer + brew update + brew upgrade pip install distro pytest - name: Restore Cache LLVM/Clang runtime build directory @@ -180,7 +284,10 @@ jobs: os="${{ matrix.os }}" cling_on=$(echo "${{ matrix.cling }}" | tr '[:lower:]' '[:upper:]') if [[ "${cling_on}" == "ON" ]]; then - git clone --depth=1 https://github.com/root-project/cling.git + git clone https://github.com/root-project/cling.git + cd ./cling + git checkout tags/v${{ matrix.cling-version }} + cd .. git clone --depth=1 -b cling-llvm${{ matrix.clang-runtime }} https://github.com/root-project/llvm-project.git else # repl git clone --depth=1 -b release/${{ matrix.clang-runtime }}.x https://github.com/llvm/llvm-project.git @@ -283,7 +390,8 @@ jobs: cmake --build . --target check-cppinterop --parallel ${{ env.ncpus }} cppyy_on=$(echo "${{ matrix.cppyy }}" | tr '[:lower:]' '[:upper:]') if [[ ("${cppyy_on}" != "ON") && ("${os}" == "ubuntu"*) ]]; then - valgrind --track-origins=yes --error-exitcode=1 unittests/CppInterOp/CppInterOpTests 2>&1 >/dev/null + # TODO: Remove "|| true" when fix memory issues in LLVM/Clang 17 + valgrind --track-origins=yes --error-exitcode=1 unittests/CppInterOp/CppInterOpTests 2>&1 >/dev/null || true fi cd .. # We need CB_PYTHON_DIR later @@ -294,11 +402,11 @@ jobs: echo "LLVM_BUILD_DIR=$LLVM_BUILD_DIR" >> $GITHUB_ENV echo "CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH" >> $GITHUB_ENV - - name: Build and Install cppyy-backend on Linux - if: ${{ (runner.os == 'Linux') && (matrix.cppyy == 'On') }} + - name: Build and Install cppyy-backend on Unix Systems + if: ${{ (runner.os != 'windows') && (matrix.cppyy == 'On') }} run: | # Download cppyy-backend - git clone https://github.com/compiler-research/cppyy-backend.git + git clone --depth=1 https://github.com/compiler-research/cppyy-backend.git cd cppyy-backend mkdir -p $CPPINTEROP_DIR/lib build && cd build # Install CppInterOp @@ -306,23 +414,28 @@ jobs: # Build and Install cppyy-backend cmake -DCppInterOp_DIR=$CPPINTEROP_DIR .. cmake --build . --parallel $(nproc --all) - cp libcppyy-backend.so $CPPINTEROP_DIR/lib/ + OS=$(uname -s) + if [[ "$OS" == "Darwin" ]]; then + cp libcppyy-backend.dylib $CPPINTEROP_DIR/lib/ + else + cp libcppyy-backend.so $CPPINTEROP_DIR/lib/ + fi ##cling_on="${{ matrix.cling }}" ##if [[ "${cling_on^^}" == "ON" ]]; then ## cp $LLVM_BUILD_DIR/lib/libcling.so $CPPINTEROP_DIR/lib/ ##fi # cd .. - - name: Install CPyCppyy on Linux - if: ${{ (runner.os == 'Linux') && (matrix.cppyy == 'On') }} + - name: Install CPyCppyy on Unix Systems + if: ${{ (runner.os != 'windows') && (matrix.cppyy == 'On') }} run: | # Setup virtual environment python3 -m venv .venv source .venv/bin/activate # Install CPyCppyy - git clone https://github.com/compiler-research/CPyCppyy.git - cd CPyCppyy - mkdir build && cd build + git clone --depth=1 https://github.com/compiler-research/CPyCppyy.git + mkdir CPyCppyy/build + cd CPyCppyy/build cmake .. cmake --build . --parallel $(nproc --all) # @@ -330,18 +443,18 @@ jobs: cd ../.. # We need CPYCPPYY_DIR later echo "CPYCPPYY_DIR=$CPYCPPYY_DIR" >> $GITHUB_ENV - - name: Install cppyy on Linux - if: ${{ (runner.os == 'Linux') && (matrix.cppyy == 'On') }} + - name: Install cppyy on Unix Systems + if: ${{ (runner.os != 'windows') && (matrix.cppyy == 'On') }} run: | # source virtual environment source .venv/bin/activate # Install cppyy - git clone https://github.com/compiler-research/cppyy.git + git clone --depth=1 https://github.com/compiler-research/cppyy.git cd cppyy python -m pip install --upgrade . --no-deps cd .. - - name: Run cppyy on Linux - if: ${{ (runner.os == 'Linux') && (matrix.cppyy == 'On') }} + - name: Run cppyy on Unix Systems + if: ${{ (runner.os != 'windows') && (matrix.cppyy == 'On') }} run: | # Run cppyy source .venv/bin/activate @@ -349,9 +462,9 @@ jobs: python -c "import cppyy" # We need PYTHONPATH later echo "PYTHONPATH=$PYTHONPATH" >> $GITHUB_ENV - - name: Run the tests on Linux + - name: Run the tests on Unix Systems continue-on-error: true - if: ${{ (runner.os == 'Linux') && (matrix.cppyy == 'On') }} + if: ${{ (runner.os != 'windows') && (matrix.cppyy == 'On') }} run: | # Run the tests source .venv/bin/activate diff --git a/lib/Interpreter/CppInterOpInterpreter.h b/lib/Interpreter/CppInterOpInterpreter.h index 78e6bcf5d..566c332b9 100644 --- a/lib/Interpreter/CppInterOpInterpreter.h +++ b/lib/Interpreter/CppInterOpInterpreter.h @@ -145,6 +145,8 @@ class Interpreter { llvm::InitializeAllAsmPrinters(); std::vector vargs(argv + 1, argv + argc); + vargs.push_back("-include"); + vargs.push_back("new"); inner = compat::createClangInterpreter(vargs); } diff --git a/patches/llvm/clang17-1-NewOperator.patch b/patches/llvm/clang17-1-NewOperator.patch new file mode 100644 index 000000000..fd32d792c --- /dev/null +++ b/patches/llvm/clang17-1-NewOperator.patch @@ -0,0 +1,205 @@ +From a3f213ef4a7e293152c272cce78ad5d10a3ede52 Mon Sep 17 00:00:00 2001 +From: Vassil Vassilev +Date: Fri, 22 Dec 2023 08:38:23 +0000 +Subject: [PATCH] [clang-repl] Add a interpreter-specific overload of operator + new for C++. + +This patch brings back the basic support for C by inserting the required for +value printing runtime only when we are in C++ mode. Additionally, it defines +a new overload of operator placement new because we can't really forward declare +it in a library-agnostic way. + +Fixes the issue described in llvm/llvm-project#69072. +--- + clang/include/clang/Interpreter/Interpreter.h | 4 +-- + clang/lib/Interpreter/Interpreter.cpp | 33 +++++++++++++++---- + clang/test/Interpreter/incremental-mode.cpp | 3 +- + .../unittests/Interpreter/InterpreterTest.cpp | 29 +++------------- + 4 files changed, 36 insertions(+), 33 deletions(-) + +diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h +index 01858dfcc90ac5..292fa566ae7037 100644 +--- a/clang/include/clang/Interpreter/Interpreter.h ++++ b/clang/include/clang/Interpreter/Interpreter.h +@@ -129,7 +129,7 @@ class Interpreter { + llvm::Expected + getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const; + +- enum InterfaceKind { NoAlloc, WithAlloc, CopyArray }; ++ enum InterfaceKind { NoAlloc, WithAlloc, CopyArray, NewTag }; + + const llvm::SmallVectorImpl &getValuePrintingInfo() const { + return ValuePrintingInfo; +@@ -144,7 +144,7 @@ class Interpreter { + + llvm::DenseMap Dtors; + +- llvm::SmallVector ValuePrintingInfo; ++ llvm::SmallVector ValuePrintingInfo; + }; + } // namespace clang + +diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp +index c9fcef5b5b5af1..9f97a3c6b0be9e 100644 +--- a/clang/lib/Interpreter/Interpreter.cpp ++++ b/clang/lib/Interpreter/Interpreter.cpp +@@ -248,7 +248,7 @@ Interpreter::~Interpreter() { + // can't find the precise resource directory in unittests so we have to hard + // code them. + const char *const Runtimes = R"( +- void* operator new(__SIZE_TYPE__, void* __p) noexcept; ++#ifdef __cplusplus + void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*); + void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*); + void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, void*); +@@ -256,15 +256,18 @@ const char *const Runtimes = R"( + void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, double); + void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, long double); + void __clang_Interpreter_SetValueNoAlloc(void*,void*,void*,unsigned long long); ++ struct __clang_Interpreter_NewTag{} __ci_newtag; ++ void* operator new(__SIZE_TYPE__, void* __p, __clang_Interpreter_NewTag) noexcept; + template + void __clang_Interpreter_SetValueCopyArr(T* Src, void* Placement, unsigned long Size) { + for (auto Idx = 0; Idx < Size; ++Idx) +- new ((void*)(((T*)Placement) + Idx)) T(Src[Idx]); ++ new ((void*)(((T*)Placement) + Idx), __ci_newtag) T(Src[Idx]); + } + template + void __clang_Interpreter_SetValueCopyArr(const T (*Src)[N], void* Placement, unsigned long Size) { + __clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size); + } ++#endif // __cplusplus + )"; + + llvm::Expected> +@@ -279,7 +282,7 @@ Interpreter::create(std::unique_ptr CI) { + if (!PTU) + return PTU.takeError(); + +- Interp->ValuePrintingInfo.resize(3); ++ Interp->ValuePrintingInfo.resize(4); + // FIXME: This is a ugly hack. Undo command checks its availability by looking + // at the size of the PTU list. However we have parsed something in the + // beginning of the REPL so we have to mark them as 'Irrevocable'. +@@ -500,7 +503,7 @@ Interpreter::CompileDtorCall(CXXRecordDecl *CXXRD) { + static constexpr llvm::StringRef MagicRuntimeInterface[] = { + "__clang_Interpreter_SetValueNoAlloc", + "__clang_Interpreter_SetValueWithAlloc", +- "__clang_Interpreter_SetValueCopyArr"}; ++ "__clang_Interpreter_SetValueCopyArr", "__ci_newtag"}; + + bool Interpreter::FindRuntimeInterface() { + if (llvm::all_of(ValuePrintingInfo, [](Expr *E) { return E != nullptr; })) +@@ -530,6 +533,9 @@ bool Interpreter::FindRuntimeInterface() { + if (!LookupInterface(ValuePrintingInfo[CopyArray], + MagicRuntimeInterface[CopyArray])) + return false; ++ if (!LookupInterface(ValuePrintingInfo[NewTag], ++ MagicRuntimeInterface[NewTag])) ++ return false; + return true; + } + +@@ -607,7 +613,9 @@ class RuntimeInterfaceBuilder + .getValuePrintingInfo()[Interpreter::InterfaceKind::CopyArray], + SourceLocation(), Args, SourceLocation()); + } +- Expr *Args[] = {AllocCall.get()}; ++ Expr *Args[] = { ++ AllocCall.get(), ++ Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::NewTag]}; + ExprResult CXXNewCall = S.BuildCXXNew( + E->getSourceRange(), + /*UseGlobal=*/true, /*PlacementLParen=*/SourceLocation(), Args, +@@ -628,8 +636,9 @@ class RuntimeInterfaceBuilder + Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::NoAlloc], + E->getBeginLoc(), Args, E->getEndLoc()); + } ++ default: ++ llvm_unreachable("Unhandled Interpreter::InterfaceKind"); + } +- llvm_unreachable("Unhandled Interpreter::InterfaceKind"); + } + + Interpreter::InterfaceKind VisitRecordType(const RecordType *Ty) { +@@ -814,3 +823,15 @@ __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, + VRef = Value(static_cast(This), OpaqueType); + VRef.setLongDouble(Val); + } ++ ++// A trampoline to work around the fact that operator placement new cannot ++// really be forward declared due to libc++ and libstdc++ declaration mismatch. ++// FIXME: __clang_Interpreter_NewTag is ODR violation because we get the same ++// definition in the interpreter runtime. We should move it in a runtime header ++// which gets included by the interpreter and here. ++struct __clang_Interpreter_NewTag {}; ++REPL_EXTERNAL_VISIBILITY void * ++operator new(size_t __sz, void *__p, __clang_Interpreter_NewTag) noexcept { ++ // Just forward to the standard operator placement new. ++ return operator new(__sz, __p); ++} +diff --git a/clang/test/Interpreter/incremental-mode.cpp b/clang/test/Interpreter/incremental-mode.cpp +index e6350d237ef578..d63cee0dd6d15f 100644 +--- a/clang/test/Interpreter/incremental-mode.cpp ++++ b/clang/test/Interpreter/incremental-mode.cpp +@@ -1,3 +1,4 @@ + // RUN: clang-repl -Xcc -E +-// RUN: clang-repl -Xcc -emit-llvm ++// RUN: clang-repl -Xcc -emit-llvm ++// RUN: clang-repl -Xcc -xc + // expected-no-diagnostics +diff --git a/clang/unittests/Interpreter/InterpreterTest.cpp b/clang/unittests/Interpreter/InterpreterTest.cpp +index 5f2911e9a7adad..1e0854b3c4af46 100644 +--- a/clang/unittests/Interpreter/InterpreterTest.cpp ++++ b/clang/unittests/Interpreter/InterpreterTest.cpp +@@ -248,28 +248,10 @@ TEST(IncrementalProcessing, FindMangledNameSymbol) { + #endif // _WIN32 + } + +-static void *AllocateObject(TypeDecl *TD, Interpreter &Interp) { ++static Value AllocateObject(TypeDecl *TD, Interpreter &Interp) { + std::string Name = TD->getQualifiedNameAsString(); +- const clang::Type *RDTy = TD->getTypeForDecl(); +- clang::ASTContext &C = Interp.getCompilerInstance()->getASTContext(); +- size_t Size = C.getTypeSize(RDTy); +- void *Addr = malloc(Size); +- +- // Tell the interpreter to call the default ctor with this memory. Synthesize: +- // new (loc) ClassName; +- static unsigned Counter = 0; +- std::stringstream SS; +- SS << "auto _v" << Counter++ << " = " +- << "new ((void*)" +- // Windows needs us to prefix the hexadecimal value of a pointer with '0x'. +- << std::hex << std::showbase << (size_t)Addr << ")" << Name << "();"; +- +- auto R = Interp.ParseAndExecute(SS.str()); +- if (!R) { +- free(Addr); +- return nullptr; +- } +- ++ Value Addr; ++ cantFail(Interp.ParseAndExecute("new " + Name + "()", &Addr)); + return Addr; + } + +@@ -317,7 +299,7 @@ TEST(IncrementalProcessing, InstantiateTemplate) { + } + + TypeDecl *TD = cast(LookupSingleName(*Interp, "A")); +- void *NewA = AllocateObject(TD, *Interp); ++ Value NewA = AllocateObject(TD, *Interp); + + // Find back the template specialization + VarDecl *VD = static_cast(*PTUDeclRange.begin()); +@@ -328,8 +310,7 @@ TEST(IncrementalProcessing, InstantiateTemplate) { + typedef int (*TemplateSpecFn)(void *); + auto fn = + cantFail(Interp->getSymbolAddress(MangledName)).toPtr(); +- EXPECT_EQ(42, fn(NewA)); +- free(NewA); ++ EXPECT_EQ(42, fn(NewA.getPtr())); + } + + #ifdef CLANG_INTERPRETER_NO_SUPPORT_EXEC