From 86a9f464efea4ed5e219c46a8c834afdc94dd66e Mon Sep 17 00:00:00 2001 From: mcbarton <150042563+mcbarton@users.noreply.github.com> Date: Tue, 28 May 2024 21:02:54 +0100 Subject: [PATCH 01/22] Remove unneeded installation of dependencies for Ubuntu wasm jobs --- .github/workflows/ci.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 682b79021..42d64665f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1195,15 +1195,6 @@ jobs: echo "ncpus=$(nproc --all)" >> $GITHUB_ENV fi - - name: Install deps on Linux - if: runner.os == 'Linux' - run: | - # Install deps - sudo apt-get update - sudo apt-get install git g++ debhelper devscripts gnupg python3 valgrind - sudo apt-get autoremove - sudo apt-get clean - - name: install mamba uses: mamba-org/setup-micromamba@main with: From 7782ee273391d465057c1c3c58d2ccb512b2b98d Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Wed, 29 May 2024 22:59:47 +0900 Subject: [PATCH 02/22] Add cross-platform support for cygwin --- include/clang/Interpreter/CppInterOp.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/include/clang/Interpreter/CppInterOp.h b/include/clang/Interpreter/CppInterOp.h index 16451eb47..6d7da7e25 100644 --- a/include/clang/Interpreter/CppInterOp.h +++ b/include/clang/Interpreter/CppInterOp.h @@ -16,10 +16,14 @@ #include // The cross-platform CPPINTEROP_API macro definition -#ifdef _WIN32 -#define CPPINTEROP_API __declspec(dllexport) +#if defined _WIN32 || defined __CYGWIN__ + #define CPPINTEROP_API __declspec(dllexport) #else -#define CPPINTEROP_API __attribute__((visibility("default"))) + #ifdef __GNUC__ + #define CPPINTEROP_API __attribute__((__visibility__("default"))) + #else + #define CPPINTEROP_API + #endif #endif namespace Cpp { From ecbffafe0016022e40b7dea6e7197ee062dde38f Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Wed, 29 May 2024 23:07:02 +0900 Subject: [PATCH 03/22] Export `LookupLibrary` and fix a typo --- include/clang/Interpreter/CppInterOp.h | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/include/clang/Interpreter/CppInterOp.h b/include/clang/Interpreter/CppInterOp.h index 6d7da7e25..12e16eecb 100644 --- a/include/clang/Interpreter/CppInterOp.h +++ b/include/clang/Interpreter/CppInterOp.h @@ -17,13 +17,13 @@ // The cross-platform CPPINTEROP_API macro definition #if defined _WIN32 || defined __CYGWIN__ - #define CPPINTEROP_API __declspec(dllexport) +#define CPPINTEROP_API __declspec(dllexport) #else - #ifdef __GNUC__ - #define CPPINTEROP_API __attribute__((__visibility__("default"))) - #else - #define CPPINTEROP_API - #endif +#ifdef __GNUC__ +#define CPPINTEROP_API __attribute__((__visibility__("default"))) +#else +#define CPPINTEROP_API +#endif #endif namespace Cpp { @@ -276,8 +276,7 @@ namespace Cpp { /// 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 CPPINTEROP_API TCppScope_t GetBaseClass(TCppType_t klass, - TCppIndex_t ibase); + CPPINTEROP_API TCppScope_t GetBaseClass(TCppType_t klass, TCppIndex_t ibase); /// Checks if the supplied Derived Class is a sub-class of the /// provided Base Class. @@ -522,7 +521,7 @@ namespace Cpp { /// Looks up the library if access is enabled. ///\returns the path to the library. - std::string LookupLibrary(const char* lib_name); + CPPINTEROP_API std::string LookupLibrary(const char* lib_name); /// Finds \c lib_stem considering the list of search paths and loads it by /// calling dlopen. From 6a5f5649d2549337456391f672749213118a5b50 Mon Sep 17 00:00:00 2001 From: mcbarton <150042563+mcbarton@users.noreply.github.com> Date: Sun, 2 Jun 2024 17:58:53 +0100 Subject: [PATCH 04/22] Fix clang tidy workflow --- .github/workflows/clang-tidy-review.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/clang-tidy-review.yml b/.github/workflows/clang-tidy-review.yml index ecbe34e19..0d85bc021 100644 --- a/.github/workflows/clang-tidy-review.yml +++ b/.github/workflows/clang-tidy-review.yml @@ -23,9 +23,9 @@ jobs: python-version: "3.11" - name: Install LLVM and Clang - uses: KyleMayes/install-llvm-action@v2.0.2 + uses: KyleMayes/install-llvm-action@v2.0.3 with: - version: "16.0.0" + version: "17.0.6" - name: install lit run: pip install lit @@ -37,8 +37,11 @@ jobs: build_dir: build apt_packages: cmake,libxml2,libxml2-dev,libtinfo-dev,zlib1g-dev,libzstd-dev split_workflow: true + config_file: .clang-tidy cmake_command: > cmake . -B build -DCMAKE_BUILD_TYPE="Release" + -DCMAKE_C_COMPILER="$GITHUB_WORKSPACE/llvm/bin/clang" + -DCMAKE_CXX_COMPILER="$GITHUB_WORKSPACE/llvm/bin/clang++" -DUSE_CLING=OFF -DUSE_REPL=ON -DLLVM_DIR="$GITHUB_WORKSPACE/llvm" From e0fa91e23b2d0f41f1e62cb8c11b9c36f00b7367 Mon Sep 17 00:00:00 2001 From: mcbarton <150042563+mcbarton@users.noreply.github.com> Date: Mon, 10 Jun 2024 16:54:28 +0100 Subject: [PATCH 05/22] Fix wasm jobs in ci due to changes in xeus-cpp requirements --- environment-wasm.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/environment-wasm.yml b/environment-wasm.yml index a6aacbd4c..1455b4af2 100644 --- a/environment-wasm.yml +++ b/environment-wasm.yml @@ -4,8 +4,7 @@ channels: dependencies: - zlib - nlohmann_json - - xeus-lite <2.0 - - xeus >=3.0.5,<4.0 - - xtl >=0.7,<0.8 + - xeus-lite + - xeus - cpp-argparse - pugixml From cff06c73182ccb1214775c1dd35aaacf8d692cc6 Mon Sep 17 00:00:00 2001 From: Aaron Jomy <75925957+maximusron@users.noreply.github.com> Date: Tue, 16 Jul 2024 11:43:08 +0200 Subject: [PATCH 06/22] Update template function selection to use min required args (#309) --- lib/Interpreter/CppInterOp.cpp | 10 +++- .../CppInterOp/FunctionReflectionTest.cpp | 54 +++++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index 6eed01289..a1b3b97da 100644 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -993,11 +993,17 @@ namespace Cpp { // actual types. We make this match solely based on count const FunctionDecl* func = TFD->getTemplatedDecl(); - if (func->getNumParams() != arg_types.size()) + +#ifdef USE_CLING + if (func->getNumParams() > arg_types.size()) continue; +#else // CLANG_REPL + if (func->getMinRequiredArguments() > arg_types.size()) + continue; +#endif // FIXME : first score based on the type similarity before forcing - // instantiation try instantiating + // instantiation. TCppFunction_t instantiated = InstantiateTemplate(candidate, arg_types.data(), arg_types.size()); if (instantiated) diff --git a/unittests/CppInterOp/FunctionReflectionTest.cpp b/unittests/CppInterOp/FunctionReflectionTest.cpp index afa5a584d..5b76e1001 100644 --- a/unittests/CppInterOp/FunctionReflectionTest.cpp +++ b/unittests/CppInterOp/FunctionReflectionTest.cpp @@ -589,6 +589,60 @@ TEST(FunctionReflectionTest, InstantiateTemplateMethod) { EXPECT_TRUE(TA1.getAsType()->isIntegerType()); } +TEST(FunctionReflectionTest, BestTemplateFunctionMatch) { + std::vector Decls; + std::string code = R"( + class MyTemplatedMethodClass { + public: + template long get_size(A&); + template long get_size(); + template long get_size(A a, B b); + }; + + template + long MyTemplatedMethodClass::get_size(A&) { + return sizeof(A); + } + + template + long MyTemplatedMethodClass::get_size() { + return sizeof(A) + 1; + } + + template + long MyTemplatedMethodClass::get_size(A a, B b) { + return sizeof(A) + sizeof(B); + } + )"; + + GetAllTopLevelDecls(code, Decls); + std::vector candidates; + + for (auto decl : Decls) + if (Cpp::IsTemplatedFunction(decl)) candidates.push_back((Cpp::TCppFunction_t)decl); + + ASTContext& C = Interp->getCI()->getASTContext(); + + std::vector args0; + std::vector args1 = {C.IntTy.getAsOpaquePtr()}; + std::vector args2 = {C.CharTy.getAsOpaquePtr(), C.FloatTy.getAsOpaquePtr()}; + + std::vector explicit_args0; + std::vector explicit_args1 = {C.IntTy.getAsOpaquePtr()}; + + + Cpp::TCppFunction_t func1 = Cpp::BestTemplateFunctionMatch(candidates, explicit_args0, args1); + Cpp::TCppFunction_t func2 = Cpp::BestTemplateFunctionMatch(candidates, explicit_args1, args0); + Cpp::TCppFunction_t func3 = Cpp::BestTemplateFunctionMatch(candidates, explicit_args0, args2); + + EXPECT_EQ(Cpp::GetFunctionSignature(func1), + "template<> long MyTemplatedMethodClass::get_size(int &)"); + EXPECT_EQ(Cpp::GetFunctionSignature(func2), + "template<> long MyTemplatedMethodClass::get_size()"); + EXPECT_EQ(Cpp::GetFunctionSignature(func3), + "template<> long MyTemplatedMethodClass::get_size(char a, float b)"); +} + TEST(FunctionReflectionTest, IsPublicMethod) { std::vector Decls, SubDecls; std::string code = R"( From 34186d650cc10ce4d613a25fb22826ce1c3c0207 Mon Sep 17 00:00:00 2001 From: mcbarton <150042563+mcbarton@users.noreply.github.com> Date: Thu, 1 Aug 2024 10:08:49 +0100 Subject: [PATCH 07/22] Make CppInterOp work with llvm 19 (#312) --- .github/workflows/ci.yml | 70 +++++++++++++++++++- CMakeLists.txt | 8 +-- lib/Interpreter/Compatibility.h | 32 +++++++++ lib/Interpreter/CppInterOp.cpp | 62 ++++++++++------- lib/Interpreter/CppInterOpInterpreter.h | 5 +- lib/Interpreter/DynamicLibraryManager.h | 2 +- lib/Interpreter/Paths.cpp | 4 +- unittests/CppInterOp/ScopeReflectionTest.cpp | 4 ++ 8 files changed, 153 insertions(+), 34 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 42d64665f..08f4ebf5c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,6 +21,13 @@ jobs: fail-fast: false matrix: include: + - name: ubu22-x86-gcc12-clang-repl-19 + os: ubuntu-22.04 + compiler: gcc-12 + clang-runtime: '19' + cling: Off + cppyy: On + coverage: true - name: ubu22-x86-gcc12-clang-repl-18 os: ubuntu-22.04 compiler: gcc-12 @@ -50,6 +57,12 @@ jobs: cling-version: '1.0' cppyy: On coverage: true + - name: win2022-msvc-clang-repl-19 + os: windows-2022 + compiler: msvc + clang-runtime: '19' + cling: Off + cppyy: Off - name: win2022-msvc-clang-repl-18 os: windows-2022 compiler: msvc @@ -75,6 +88,12 @@ jobs: cling: On cling-version: '1.0' cppyy: Off + - name: osx14-arm-clang-clang-repl-19 + os: macos-14 + compiler: clang + clang-runtime: '19' + cling: Off + cppyy: On - name: osx14-arm-clang-clang-repl-18 os: macos-14 compiler: clang @@ -100,6 +119,12 @@ jobs: cling: On cling-version: '1.0' cppyy: On + - name: osx13-x86-clang-clang-repl-19 + os: macos-13 + compiler: clang + clang-runtime: '19' + cling: Off + cppyy: On - name: osx13-x86-clang-clang-repl-18 os: macos-13 compiler: clang @@ -350,7 +375,7 @@ jobs: else # Apply patches llvm_vers=$(echo "${{ matrix.clang-runtime }}" | tr '[:lower:]' '[:upper:]') - if [[ "${llvm_vers}" != "18" ]]; then + if [[ "${llvm_vers}" == "16" ]]||[[ "${llvm_vers}" == "17" ]]; then git apply -v ../patches/llvm/clang${{ matrix.clang-runtime }}-*.patch echo "Apply clang${{ matrix.clang-runtime }}-*.patch patches:" fi @@ -470,6 +495,13 @@ jobs: fail-fast: false matrix: include: + - name: ubu22-x86-gcc12-clang-repl-19-cppyy + os: ubuntu-22.04 + compiler: gcc-12 + clang-runtime: '19' + cling: Off + cppyy: On + coverage: true - name: ubu22-x86-gcc12-clang-repl-18-cppyy os: ubuntu-22.04 compiler: gcc-12 @@ -498,6 +530,12 @@ jobs: cppyy: On #FIXME: Windows CppInterOp tests expected to fail #until https://github.com/compiler-research/CppInterOp/issues/188 is solved + - name: win2022-msvc-clang-repl-19 + os: windows-2022 + compiler: msvc + clang-runtime: '19' + cling: Off + cppyy: Off - name: win2022-msvc-clang-repl-18 os: windows-2022 compiler: msvc @@ -542,6 +580,12 @@ jobs: # cling: On # cling-version: '1.0' # cppyy: On + - name: osx14-arm-clang-clang-repl-19-cppyy + os: macos-14 + compiler: clang + clang-runtime: '19' + cling: Off + cppyy: On - name: osx14-arm-clang-clang-repl-18-cppyy os: macos-14 compiler: clang @@ -567,6 +611,12 @@ jobs: cling: On cling-version: '1.0' cppyy: On + - name: osx13-x86-clang-clang-repl-19-cppyy + os: macos-13 + compiler: clang + clang-runtime: '19' + cling: Off + cppyy: On - name: osx13-x86-clang-clang-repl-18-cppyy os: macos-13 compiler: clang @@ -1076,6 +1126,12 @@ jobs: fail-fast: false matrix: include: + - name: ubu22-x86-gcc12-clang-repl-19-emscripten_wasm + os: ubuntu-22.04 + compiler: gcc-12 + clang-runtime: '19' + cling: Off + micromamba_shell_init: bash - name: ubu22-x86-gcc12-clang-repl-18-emscripten_wasm os: ubuntu-22.04 compiler: gcc-12 @@ -1101,6 +1157,12 @@ jobs: cling: On cling-version: '1.0' micromamba_shell_init: bash + - name: osx14-arm-clang-clang-repl-19-emscripten_wasm + os: macos-14 + compiler: clang + clang-runtime: '19' + cling: Off + micromamba_shell_init: bash - name: osx14-arm-clang-clang-repl-18-emscripten_wasm os: macos-14 compiler: clang @@ -1126,6 +1188,12 @@ jobs: cling: On cling-version: '1.0' micromamba_shell_init: bash + - name: osx13-x86-clang-clang-repl-19-emscripten_wasm + os: macos-13 + compiler: clang + clang-runtime: '19' + cling: Off + micromamba_shell_init: bash - name: osx13-x86-clang-clang-repl-18-emscripten_wasm os: macos-13 compiler: clang diff --git a/CMakeLists.txt b/CMakeLists.txt index b87a26303..bcd16a956 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,11 +59,11 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR ) ## Define supported version of clang and llvm set(CLANG_MIN_SUPPORTED 13.0) - set(CLANG_MAX_SUPPORTED "18.1.x") - set(CLANG_VERSION_UPPER_BOUND 19.0.0) + set(CLANG_MAX_SUPPORTED "19.1.x") + set(CLANG_VERSION_UPPER_BOUND 20.0.0) set(LLVM_MIN_SUPPORTED 13.0) - set(LLVM_MAX_SUPPORTED "18.1.x") - set(LLVM_VERSION_UPPER_BOUND 19.0.0) + set(LLVM_MAX_SUPPORTED "19.1.x") + set(LLVM_VERSION_UPPER_BOUND 20.0.0) ## Set Cmake packages search order diff --git a/lib/Interpreter/Compatibility.h b/lib/Interpreter/Compatibility.h index ecc5a3be1..06a863152 100644 --- a/lib/Interpreter/Compatibility.h +++ b/lib/Interpreter/Compatibility.h @@ -10,6 +10,38 @@ #include "clang/Basic/Version.h" #include "clang/Config/config.h" +#if CLANG_VERSION_MAJOR < 19 +#define Template_Deduction_Result Sema::TemplateDeductionResult +#define Template_Deduction_Result_Success \ + Sema::TemplateDeductionResult::TDK_Success +#else +#define Template_Deduction_Result TemplateDeductionResult +#define Template_Deduction_Result_Success TemplateDeductionResult::Success +#endif + +#if CLANG_VERSION_MAJOR < 19 +#define For_Visible_Redeclaration Sema::ForVisibleRedeclaration +#define Clang_For_Visible_Redeclaration clang::Sema::ForVisibleRedeclaration +#else +#define For_Visible_Redeclaration RedeclarationKind::ForVisibleRedeclaration +#define Clang_For_Visible_Redeclaration \ + RedeclarationKind::ForVisibleRedeclaration +#endif + +#if CLANG_VERSION_MAJOR < 19 +#define CXXSpecialMemberKindDefaultConstructor \ + clang::Sema::CXXDefaultConstructor +#define CXXSpecialMemberKindCopyConstructor clang::Sema::CXXCopyConstructor +#define CXXSpecialMemberKindMoveConstructor clang::Sema::CXXMoveConstructor +#else +#define CXXSpecialMemberKindDefaultConstructor \ + CXXSpecialMemberKind::DefaultConstructor +#define CXXSpecialMemberKindCopyConstructor \ + CXXSpecialMemberKind::CopyConstructor +#define CXXSpecialMemberKindMoveConstructor \ + CXXSpecialMemberKind::MoveConstructor +#endif + #if LLVM_VERSION_MAJOR < 18 #define starts_with startswith #define ends_with endswith diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index a1b3b97da..67d0acfbb 100644 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -24,6 +24,9 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" +#if CLANG_VERSION_MAJOR >= 19 +#include "clang/Sema/Redeclaration.h" +#endif #include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/StringRef.h" @@ -49,6 +52,8 @@ #include #endif // WIN32 +#include + namespace Cpp { using namespace clang; @@ -805,11 +810,8 @@ namespace Cpp { llvm::StringRef Name(name); auto &S = getSema(); DeclarationName DName = &getASTContext().Idents.get(name); - clang::LookupResult R(S, - DName, - SourceLocation(), - Sema::LookupOrdinaryName, - Sema::ForVisibleRedeclaration); + clang::LookupResult R(S, DName, SourceLocation(), Sema::LookupOrdinaryName, + For_Visible_Redeclaration); Cpp_utils::Lookup::Named(&S, R, Decl::castToDeclContext(D)); @@ -962,7 +964,7 @@ namespace Cpp { auto& S = getSema(); DeclarationName DName = &getASTContext().Idents.get(name); clang::LookupResult R(S, DName, SourceLocation(), Sema::LookupOrdinaryName, - Sema::ForVisibleRedeclaration); + For_Visible_Redeclaration); Cpp_utils::Lookup::Named(&S, R, Decl::castToDeclContext(D)); @@ -1348,36 +1350,43 @@ namespace Cpp { isunsigned = true; typeName = StringRef(typeName.data()+9, typeName.size()-9); } - if (typeName.equals("char")) { + if (typeName == "char") { if (isunsigned) return Context.UnsignedCharTy; return Context.SignedCharTy; } - if (typeName.equals("short")) { + if (typeName == "short") { if (isunsigned) return Context.UnsignedShortTy; return Context.ShortTy; } - if (typeName.equals("int")) { + if (typeName == "int") { if (isunsigned) return Context.UnsignedIntTy; return Context.IntTy; } - if (typeName.equals("long")) { + if (typeName == "long") { if (isunsigned) return Context.UnsignedLongTy; return Context.LongTy; } - if (typeName.equals("long long")) { + if (typeName == "long long") { if (isunsigned) return Context.UnsignedLongLongTy; return Context.LongLongTy; } if (!issigned && !isunsigned) { - if (typeName.equals("bool")) return Context.BoolTy; - if (typeName.equals("float")) return Context.FloatTy; - if (typeName.equals("double")) return Context.DoubleTy; - if (typeName.equals("long double")) return Context.LongDoubleTy; - - if (typeName.equals("wchar_t")) return Context.WCharTy; - if (typeName.equals("char16_t")) return Context.Char16Ty; - if (typeName.equals("char32_t")) return Context.Char32Ty; + if (typeName == "bool") + return Context.BoolTy; + if (typeName == "float") + return Context.FloatTy; + if (typeName == "double") + return Context.DoubleTy; + if (typeName == "long double") + return Context.LongDoubleTy; + + if (typeName == "wchar_t") + return Context.WCharTy; + if (typeName == "char16_t") + return Context.Char16Ty; + if (typeName == "char32_t") + return Context.Char32Ty; } /* Missing CanQualType WideCharTy; // Same as WCharTy in C++, integer type in C99. @@ -1747,9 +1756,11 @@ namespace Cpp { if (const CXXConstructorDecl* CD = dyn_cast(FD)) { if (N <= 1 && llvm::isa(FD)) { auto SpecMemKind = I.getCI()->getSema().getSpecialMember(CD); - if ((N == 0 && SpecMemKind == clang::Sema::CXXDefaultConstructor) || - (N == 1 && (SpecMemKind == clang::Sema::CXXCopyConstructor || - SpecMemKind == clang::Sema::CXXMoveConstructor))) { + if ((N == 0 && + SpecMemKind == CXXSpecialMemberKindDefaultConstructor) || + (N == 1 && + (SpecMemKind == CXXSpecialMemberKindCopyConstructor || + SpecMemKind == CXXSpecialMemberKindMoveConstructor))) { // Using declarations cannot inject special members; do not call // them as such. This might happen by using `Base(Base&, int = 12)`, // which is fine to be called as `Derived d(someBase, 42)` but not @@ -2866,9 +2877,10 @@ namespace Cpp { if (auto* FunctionTemplate = dyn_cast(TemplateD)) { FunctionDecl* Specialization = nullptr; clang::sema::TemplateDeductionInfo Info(fakeLoc); - if (Sema::TemplateDeductionResult Result = S.DeduceTemplateArguments( - FunctionTemplate, &TLI, Specialization, Info, - /*IsAddressOfFunction*/ true)) { + Template_Deduction_Result Result = S.DeduceTemplateArguments( + FunctionTemplate, &TLI, Specialization, Info, + /*IsAddressOfFunction*/ true); + if (Result != Template_Deduction_Result_Success) { // FIXME: Diagnose what happened. (void)Result; } diff --git a/lib/Interpreter/CppInterOpInterpreter.h b/lib/Interpreter/CppInterOpInterpreter.h index 07b74f1bb..5c905002a 100644 --- a/lib/Interpreter/CppInterOpInterpreter.h +++ b/lib/Interpreter/CppInterOpInterpreter.h @@ -22,6 +22,9 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" +#if CLANG_VERSION_MAJOR >= 19 +#include "clang/Sema/Redeclaration.h" +#endif #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallSet.h" @@ -105,7 +108,7 @@ inline clang::NamedDecl* Named(clang::Sema* S, const clang::DeclContext* Within = nullptr) { clang::LookupResult R(*S, Name, clang::SourceLocation(), clang::Sema::LookupOrdinaryName, - clang::Sema::ForVisibleRedeclaration); + Clang_For_Visible_Redeclaration); Named(S, R, Within); return LookupResult2Decl(R); } diff --git a/lib/Interpreter/DynamicLibraryManager.h b/lib/Interpreter/DynamicLibraryManager.h index 17d95c066..5ed6a7e74 100644 --- a/lib/Interpreter/DynamicLibraryManager.h +++ b/lib/Interpreter/DynamicLibraryManager.h @@ -130,7 +130,7 @@ class DynamicLibraryManager { bool prepend = false) { if (!dir.empty()) { for (auto& item : m_SearchPaths) - if (dir.equals(item.Path)) + if (dir == item.Path) return; auto pos = prepend ? m_SearchPaths.begin() : m_SearchPaths.end(); m_SearchPaths.insert(pos, SearchPathInfo{dir.str(), isUser}); diff --git a/lib/Interpreter/Paths.cpp b/lib/Interpreter/Paths.cpp index 4e7c1f622..c4997abb3 100644 --- a/lib/Interpreter/Paths.cpp +++ b/lib/Interpreter/Paths.cpp @@ -312,7 +312,7 @@ bool LookForFile(const std::vector& Args, std::string& Path, return true; } // Don't write same same log entry twice when FilePath == Path - if (FileType && !FilePath.str().equals(Path)) + if (FileType && FilePath.str() != Path) LogFileStatus("Ignoring", FileType, FilePath); } else if (llvm::sys::path::is_absolute(Path)) @@ -354,7 +354,7 @@ bool SplitPaths(llvm::StringRef PathStr, #if defined(_WIN32) // Support using a ':' delimiter on Windows. - const bool WindowsColon = Delim.equals(":"); + const bool WindowsColon = (Delim == ":"); #endif bool AllExisted = true; diff --git a/unittests/CppInterOp/ScopeReflectionTest.cpp b/unittests/CppInterOp/ScopeReflectionTest.cpp index 2939ae966..249462c4c 100644 --- a/unittests/CppInterOp/ScopeReflectionTest.cpp +++ b/unittests/CppInterOp/ScopeReflectionTest.cpp @@ -772,7 +772,11 @@ template constexpr T pi = T(3.1415926535897932385L); VarTemplateDecl* VDTD1 = VD->getSpecializedTemplate(); EXPECT_TRUE(VDTD1->isThisDeclarationADefinition()); #if CLANG_VERSION_MAJOR > 13 +#if CLANG_VERSION_MAJOR <= 18 TemplateArgument TA1 = (*VD->getTemplateArgsInfo())[0].getArgument(); +#else + TemplateArgument TA1 = (*VD->getTemplateArgsAsWritten())[0].getArgument(); +#endif // CLANG_VERSION_MAJOR #else TemplateArgument TA1 = VD->getTemplateArgsInfo()[0].getArgument(); #endif // CLANG_VERSION_MAJOR From bebebcdb22a21ac27e33f9e11201309c6a55034e Mon Sep 17 00:00:00 2001 From: Vipul Cariappa Date: Mon, 12 Aug 2024 10:02:41 +0530 Subject: [PATCH 08/22] Implement `GetIncludePaths` (#311) Fixes #69 --- include/clang/Interpreter/CppInterOp.h | 7 +++++++ lib/Interpreter/CppInterOp.cpp | 8 ++++++++ lib/Interpreter/CppInterOpInterpreter.h | 18 ++++++++++++++++++ unittests/CppInterOp/InterpreterTest.cpp | 18 ++++++++++++++++++ 4 files changed, 51 insertions(+) diff --git a/include/clang/Interpreter/CppInterOp.h b/include/clang/Interpreter/CppInterOp.h index 12e16eecb..c7426232e 100644 --- a/include/clang/Interpreter/CppInterOp.h +++ b/include/clang/Interpreter/CppInterOp.h @@ -507,6 +507,13 @@ namespace Cpp { /// GetResourceDir() function. CPPINTEROP_API void AddIncludePath(const char* dir); + // Gets the currently used include paths + ///\param[out] IncludePaths - the list of include paths + /// + CPPINTEROP_API void GetIncludePaths(std::vector& IncludePaths, + bool withSystem = false, + bool withFlags = false); + /// Only Declares a code snippet in \c code and does not execute it. ///\returns 0 on success CPPINTEROP_API int Declare(const char* code, bool silent = false); diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index 67d0acfbb..2d10fc66d 100644 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -2702,6 +2702,14 @@ namespace Cpp { getInterp().AddIncludePath(dir); } + void GetIncludePaths(std::vector& IncludePaths, bool withSystem, + bool withFlags) { + llvm::SmallVector paths(1); + getInterp().GetIncludePaths(paths, withSystem, withFlags); + for (auto& i : paths) + IncludePaths.push_back(i); + } + namespace { class clangSilent { diff --git a/lib/Interpreter/CppInterOpInterpreter.h b/lib/Interpreter/CppInterOpInterpreter.h index 5c905002a..e35840633 100644 --- a/lib/Interpreter/CppInterOpInterpreter.h +++ b/lib/Interpreter/CppInterOpInterpreter.h @@ -381,6 +381,24 @@ class Interpreter { return AddIncludePaths(PathsStr, nullptr); } + ///\brief Get the current include paths that are used. + /// + ///\param[out] incpaths - Pass in a llvm::SmallVector with + /// sufficiently sized N, to hold the result of the call. + ///\param[in] withSystem - if true, incpaths will also contain system + /// include paths (framework, STL etc). + ///\param[in] withFlags - if true, each element in incpaths will be prefixed + /// with a "-I" or similar, and some entries of incpaths will signal + /// a new include path region (e.g. "-cxx-isystem"). Also, flags + /// defining header search behavior will be included in incpaths, e.g. + /// "-nostdinc". + /// + void GetIncludePaths(llvm::SmallVectorImpl& incpaths, + bool withSystem, bool withFlags) const { + utils::CopyIncludePaths(getCI()->getHeaderSearchOpts(), incpaths, + withSystem, withFlags); + } + CompilationResult loadLibrary(const std::string& filename, bool lookup) { DynamicLibraryManager* DLM = getDynamicLibraryManager(); std::string canonicalLib; diff --git a/unittests/CppInterOp/InterpreterTest.cpp b/unittests/CppInterOp/InterpreterTest.cpp index 01b3bb114..e72f26d4c 100644 --- a/unittests/CppInterOp/InterpreterTest.cpp +++ b/unittests/CppInterOp/InterpreterTest.cpp @@ -113,6 +113,24 @@ TEST(InterpreterTest, DetectSystemCompilerIncludePaths) { EXPECT_FALSE(includes.empty()); } +TEST(InterpreterTest, GetIncludePaths) { + std::vector includes; + Cpp::GetIncludePaths(includes); + EXPECT_FALSE(includes.empty()); + + size_t len = includes.size(); + includes.clear(); + Cpp::GetIncludePaths(includes, true, false); + EXPECT_FALSE(includes.empty()); + EXPECT_TRUE(includes.size() >= len); + + len = includes.size(); + includes.clear(); + Cpp::GetIncludePaths(includes, true, true); + EXPECT_FALSE(includes.empty()); + EXPECT_TRUE(includes.size() >= len); +} + TEST(InterpreterTest, CodeCompletion) { #if CLANG_VERSION_MAJOR >= 18 || defined(USE_CLING) Cpp::CreateInterpreter(); From 519432740d0bca554b8a36647e7210e839368403 Mon Sep 17 00:00:00 2001 From: mcbarton <150042563+mcbarton@users.noreply.github.com> Date: Wed, 14 Aug 2024 13:04:09 +0100 Subject: [PATCH 09/22] Remove Windows wasm llvm --- .github/workflows/ci.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 08f4ebf5c..90b2d3ca9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -424,10 +424,10 @@ jobs: if ( "${{ matrix.cling }}" -imatch "On" ) { cd build - cmake -DLLVM_ENABLE_PROJECTS="clang;lld" ` + cmake -DLLVM_ENABLE_PROJECTS="clang" ` -DLLVM_EXTERNAL_PROJECTS=cling ` -DLLVM_EXTERNAL_CLING_SOURCE_DIR="$env:CLING_DIR" ` - -DLLVM_TARGETS_TO_BUILD="WebAssembly;host;NVPTX" ` + -DLLVM_TARGETS_TO_BUILD="host;NVPTX" ` -DCMAKE_BUILD_TYPE=Release ` -DLLVM_ENABLE_ASSERTIONS=ON ` -DCLANG_ENABLE_STATIC_ANALYZER=OFF ` @@ -438,7 +438,6 @@ jobs: -DLLVM_ENABLE_TERMINFO=OFF ` -DLLVM_ENABLE_LIBXML2=OFF ` ..\llvm - cmake --build . --config Release --target lld --parallel ${{ env.ncpus }} cmake --build . --config Release --target clang --parallel ${{ env.ncpus }} cmake --build . --config Release --target cling --parallel ${{ env.ncpus }} # Now build gtest.a and gtest_main for CppInterOp to run its tests. @@ -460,8 +459,8 @@ jobs: } cd build echo "Apply clang${{ matrix.clang-runtime }}-*.patch patches:" - cmake -DLLVM_ENABLE_PROJECTS="clang;lld" ` - -DLLVM_TARGETS_TO_BUILD="WebAssembly;host;NVPTX" ` + cmake -DLLVM_ENABLE_PROJECTS="clang" ` + -DLLVM_TARGETS_TO_BUILD="host;NVPTX" ` -DCMAKE_BUILD_TYPE=Release ` -DLLVM_ENABLE_ASSERTIONS=ON ` -DCLANG_ENABLE_STATIC_ANALYZER=OFF ` @@ -472,7 +471,7 @@ jobs: -DLLVM_ENABLE_TERMINFO=OFF ` -DLLVM_ENABLE_LIBXML2=OFF ` ..\llvm - cmake --build . --config Release --target clang clang-repl lld --parallel ${{ env.ncpus }} + cmake --build . --config Release --target clang clang-repl --parallel ${{ env.ncpus }} } cd ..\ rm -r -force $(find.exe . -maxdepth 1 ! -name "build" ! -name "llvm" ! -name "clang" ! -name ".") From af8e9020afc9130983187d47bb4b127ac684e573 Mon Sep 17 00:00:00 2001 From: Aaron Jomy <75925957+aaronj0@users.noreply.github.com> Date: Thu, 22 Aug 2024 09:45:58 +0200 Subject: [PATCH 10/22] [docs] Update LLVM version --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e3f1d457d..fec26983d 100644 --- a/README.md +++ b/README.md @@ -77,19 +77,20 @@ git clone --depth=1 https://github.com/compiler-research/cppyy-backend.git ``` #### Setup Clang-REPL -Clone the 17.x release of the LLVM project repository. +Clone the 18.x release of the LLVM project repository. ``` -git clone --depth=1 --branch release/17.x https://github.com/llvm/llvm-project.git +git clone --depth=1 --branch release/18.x https://github.com/llvm/llvm-project.git cd llvm-project ``` -Get the following patches required for development work. To apply these patches on Linux and MacOS execute the following command + +For Clang 16 & 17, the following patches required for development work. To apply these patches on Linux and MacOS execute the following command(substitute `{version}` with your clang version): ``` -git apply -v ../CppInterOp/patches/llvm/clang17-*.patch +git apply -v ../CppInterOp/patches/llvm/clang{version}-*.patch ``` and ``` cp -r ..\CppInterOp\patches\llvm\clang17* . -git apply -v clang17-1-NewOperator.patch +git apply -v clang{version}-*.patch ``` on Windows. From 91e392d846411ee740bb02f4ce3a6839261a8af4 Mon Sep 17 00:00:00 2001 From: Vassil Vassilev Date: Thu, 22 Aug 2024 13:56:07 +0000 Subject: [PATCH 11/22] Support recent cling. --- lib/Interpreter/Compatibility.h | 34 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/lib/Interpreter/Compatibility.h b/lib/Interpreter/Compatibility.h index 06a863152..4feb60cb1 100644 --- a/lib/Interpreter/Compatibility.h +++ b/lib/Interpreter/Compatibility.h @@ -110,8 +110,14 @@ getSymbolAddress(const cling::Interpreter& I, llvm::StringRef IRName) { llvm::orc::LLJIT& Jit = *compat::getExecutionEngine(I); llvm::orc::SymbolNameVector Names; - Names.push_back(Jit.getExecutionSession().intern(IRName)); + llvm::orc::ExecutionSession& ES = Jit.getExecutionSession(); + Names.push_back(ES.intern(IRName)); +#if CLANG_VERSION_MAJOR < 16 return llvm::make_error(Names); +#else + return llvm::make_error(ES.getSymbolStringPool(), + std::move(Names)); +#endif // CLANG_VERSION_MAJOR } inline void codeComplete(std::vector& Results, @@ -399,29 +405,15 @@ inline std::string MakeResourceDir(llvm::StringRef Dir) { } // Clang >= 16 (=16 with Value patch) change castAs to converTo -#if CLANG_VERSION_MAJOR >= 16 -template -inline T convertTo( -#ifdef USE_CLING - cling::Value V -#else - clang::Value V -#endif -) { - return V.convertTo(); -} -#else -template -inline T convertTo( #ifdef USE_CLING - cling::Value V -#else - clang::Value V -#endif -) { +template inline T convertTo(cling::Value V) { return V.castAs(); } -#endif +#else // CLANG_REPL +template inline T convertTo(clang::Value V) { + return V.convertTo(); +} +#endif // USE_CLING } // namespace compat From 9bd4678e934e902538abf0d920e367cb15d55a9e Mon Sep 17 00:00:00 2001 From: Vipul Cariappa Date: Thu, 5 Sep 2024 19:36:37 +0530 Subject: [PATCH 12/22] Add `GetBinaryOperator` (#319) --- include/clang/Interpreter/CppInterOp.h | 42 +++++++++++++++++ lib/Interpreter/CppInterOp.cpp | 43 ++++++++++++++++++ unittests/CppInterOp/ScopeReflectionTest.cpp | 47 ++++++++++++++++++++ 3 files changed, 132 insertions(+) diff --git a/include/clang/Interpreter/CppInterOp.h b/include/clang/Interpreter/CppInterOp.h index c7426232e..e4a9969ec 100644 --- a/include/clang/Interpreter/CppInterOp.h +++ b/include/clang/Interpreter/CppInterOp.h @@ -35,6 +35,43 @@ namespace Cpp { using TCppFuncAddr_t = void*; using TInterp_t = void*; using TCppObject_t = void*; + + enum BinaryOperator { + PtrMemD = 0, + PtrMemI, + Mul, + Div, + Rem, + Add, + Sub, + Shl, + Shr, + Cmp, + LT, + GT, + LE, + GE, + EQ, + NE, + And, + Xor, + Or, + LAnd, + LOr, + Assign, + MulAssign, + DivAssign, + RemAssign, + AddAssign, + SubAssign, + ShlAssign, + ShrAssign, + AndAssign, + XorAssign, + OrAssign, + Comma, + }; + /// A class modeling function calls for functions produced by the interpreter /// in compiled code. It provides an information if we are calling a standard /// function, constructor or destructor. @@ -464,6 +501,11 @@ namespace Cpp { CPPINTEROP_API std::string GetFunctionArgName(TCppFunction_t func, TCppIndex_t param_index); + ///\returns function that performs operation op on lc and rc + TCppFunction_t GetBinaryOperator(TCppScope_t scope, enum BinaryOperator op, + const std::string& lc, + const std::string& rc); + /// Creates an instance of the interpreter we need for the various interop /// services. ///\param[in] Args - the list of arguments for interpreter constructor. diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index 2d10fc66d..a6f1710bc 100644 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -3161,6 +3161,49 @@ namespace Cpp { return PI->getNameAsString(); } + TCppFunction_t GetBinaryOperator(TCppScope_t scope, enum BinaryOperator op, + const std::string& lc, + const std::string& rc) { + Decl* D = static_cast(scope); + if (!D) + return nullptr; + + DeclContext* DC = nullptr; + if (llvm::isa_and_nonnull(D)) + DC = llvm::dyn_cast(D); + else + DC = D->getDeclContext(); + + if (!DC) + return nullptr; + + Scope* S = getSema().getScopeForContext(DC); + if (!S) + return nullptr; + + clang::UnresolvedSet<8> lookup; + + getSema().LookupBinOp(S, SourceLocation(), (clang::BinaryOperatorKind)op, + lookup); + + for (NamedDecl* D : lookup) { + if (auto* FD = llvm::dyn_cast(D)) { + assert(GetFunctionNumArgs(FD) == 2 && + "LookupBinOp returned function without 2 arguments"); + + std::string arg_type = GetTypeAsString(GetFunctionArgType(FD, 0)); + if (arg_type != lc) + continue; + arg_type = GetTypeAsString(GetFunctionArgType(FD, 1)); + if (arg_type != rc) + continue; + + return FD; + } + } + return nullptr; + } + TCppObject_t Allocate(TCppScope_t scope) { return (TCppObject_t)::operator new(Cpp::SizeOf(scope)); } diff --git a/unittests/CppInterOp/ScopeReflectionTest.cpp b/unittests/CppInterOp/ScopeReflectionTest.cpp index 249462c4c..ee4ea6d93 100644 --- a/unittests/CppInterOp/ScopeReflectionTest.cpp +++ b/unittests/CppInterOp/ScopeReflectionTest.cpp @@ -952,3 +952,50 @@ TEST(ScopeReflectionTest, IncludeVector) { )"; Interp->process(code); } + +TEST(ScopeReflectionTest, GetBinaryOperator) { + if (llvm::sys::RunningOnValgrind()) + GTEST_SKIP() << "XFAIL due to Valgrind report"; + + Cpp::CreateInterpreter(); + + std::string code = R"( + class MyClass { + public: + int x; + MyClass(int x) : x(x) {} + }; + + MyClass operator-(MyClass lhs, MyClass rhs) { + return MyClass(lhs.x - rhs.x); + } + + MyClass operator+(MyClass lhs, MyClass rhs) { + return MyClass(lhs.x + rhs.x); + } + + MyClass operator+(MyClass lhs, int rhs) { + return MyClass(lhs.x + rhs); + } + + MyClass operator+(int lhs, MyClass rhs) { + return MyClass(lhs + rhs.x); + } + )"; + + Cpp::Declare(code.c_str()); + + EXPECT_TRUE(Cpp::GetBinaryOperator( + Cpp::GetGlobalScope(), Cpp::BinaryOperator::Add, "MyClass", "MyClass")); + EXPECT_TRUE(Cpp::GetBinaryOperator( + Cpp::GetGlobalScope(), Cpp::BinaryOperator::Sub, "MyClass", "MyClass")); + EXPECT_TRUE(Cpp::GetBinaryOperator( + Cpp::GetGlobalScope(), Cpp::BinaryOperator::Add, "MyClass", "int")); + EXPECT_TRUE(Cpp::GetBinaryOperator( + Cpp::GetGlobalScope(), Cpp::BinaryOperator::Add, "int", "MyClass")); + + EXPECT_FALSE(Cpp::GetBinaryOperator( + Cpp::GetGlobalScope(), Cpp::BinaryOperator::Add, "float", "MyClass")); + EXPECT_FALSE(Cpp::GetBinaryOperator( + Cpp::GetGlobalScope(), Cpp::BinaryOperator::Add, "MyClass", "float")); +} From ea731053138b31f5b246ede733513e2b6a93fdb5 Mon Sep 17 00:00:00 2001 From: Vipul Cariappa Date: Sun, 8 Sep 2024 10:46:23 +0530 Subject: [PATCH 13/22] GetBinaryOperator returns vector of functions (#320) --- include/clang/Interpreter/CppInterOp.h | 5 ++- lib/Interpreter/CppInterOp.cpp | 36 ++++---------------- unittests/CppInterOp/ScopeReflectionTest.cpp | 25 +++++++------- 3 files changed, 20 insertions(+), 46 deletions(-) diff --git a/include/clang/Interpreter/CppInterOp.h b/include/clang/Interpreter/CppInterOp.h index e4a9969ec..ef630de96 100644 --- a/include/clang/Interpreter/CppInterOp.h +++ b/include/clang/Interpreter/CppInterOp.h @@ -502,9 +502,8 @@ namespace Cpp { TCppIndex_t param_index); ///\returns function that performs operation op on lc and rc - TCppFunction_t GetBinaryOperator(TCppScope_t scope, enum BinaryOperator op, - const std::string& lc, - const std::string& rc); + void GetBinaryOperator(TCppScope_t scope, enum BinaryOperator op, + std::vector& operators); /// Creates an instance of the interpreter we need for the various interop /// services. diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index a6f1710bc..96aab8020 100644 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -3161,25 +3161,13 @@ namespace Cpp { return PI->getNameAsString(); } - TCppFunction_t GetBinaryOperator(TCppScope_t scope, enum BinaryOperator op, - const std::string& lc, - const std::string& rc) { + void GetBinaryOperator(TCppScope_t scope, enum BinaryOperator op, + std::vector& operators) { Decl* D = static_cast(scope); - if (!D) - return nullptr; - - DeclContext* DC = nullptr; - if (llvm::isa_and_nonnull(D)) - DC = llvm::dyn_cast(D); - else - DC = D->getDeclContext(); - - if (!DC) - return nullptr; - + auto* DC = llvm::dyn_cast(D); Scope* S = getSema().getScopeForContext(DC); if (!S) - return nullptr; + return; clang::UnresolvedSet<8> lookup; @@ -3187,21 +3175,9 @@ namespace Cpp { lookup); for (NamedDecl* D : lookup) { - if (auto* FD = llvm::dyn_cast(D)) { - assert(GetFunctionNumArgs(FD) == 2 && - "LookupBinOp returned function without 2 arguments"); - - std::string arg_type = GetTypeAsString(GetFunctionArgType(FD, 0)); - if (arg_type != lc) - continue; - arg_type = GetTypeAsString(GetFunctionArgType(FD, 1)); - if (arg_type != rc) - continue; - - return FD; - } + if (auto* FD = llvm::dyn_cast(D)) + operators.push_back(FD); } - return nullptr; } TCppObject_t Allocate(TCppScope_t scope) { diff --git a/unittests/CppInterOp/ScopeReflectionTest.cpp b/unittests/CppInterOp/ScopeReflectionTest.cpp index ee4ea6d93..d0da1c2f8 100644 --- a/unittests/CppInterOp/ScopeReflectionTest.cpp +++ b/unittests/CppInterOp/ScopeReflectionTest.cpp @@ -985,17 +985,16 @@ TEST(ScopeReflectionTest, GetBinaryOperator) { Cpp::Declare(code.c_str()); - EXPECT_TRUE(Cpp::GetBinaryOperator( - Cpp::GetGlobalScope(), Cpp::BinaryOperator::Add, "MyClass", "MyClass")); - EXPECT_TRUE(Cpp::GetBinaryOperator( - Cpp::GetGlobalScope(), Cpp::BinaryOperator::Sub, "MyClass", "MyClass")); - EXPECT_TRUE(Cpp::GetBinaryOperator( - Cpp::GetGlobalScope(), Cpp::BinaryOperator::Add, "MyClass", "int")); - EXPECT_TRUE(Cpp::GetBinaryOperator( - Cpp::GetGlobalScope(), Cpp::BinaryOperator::Add, "int", "MyClass")); - - EXPECT_FALSE(Cpp::GetBinaryOperator( - Cpp::GetGlobalScope(), Cpp::BinaryOperator::Add, "float", "MyClass")); - EXPECT_FALSE(Cpp::GetBinaryOperator( - Cpp::GetGlobalScope(), Cpp::BinaryOperator::Add, "MyClass", "float")); + std::vector ops; + + Cpp::GetBinaryOperator(Cpp::GetGlobalScope(), Cpp::BinaryOperator::Add, ops); + EXPECT_EQ(ops.size(), 3); + ops.clear(); + + Cpp::GetBinaryOperator(Cpp::GetGlobalScope(), Cpp::BinaryOperator::Sub, ops); + EXPECT_EQ(ops.size(), 1); + ops.clear(); + + Cpp::GetBinaryOperator(Cpp::GetGlobalScope(), Cpp::BinaryOperator::Mul, ops); + EXPECT_EQ(ops.size(), 0); } From 33546ba1273b3c59744f7baec38d8997ae0251c3 Mon Sep 17 00:00:00 2001 From: Vipul Cariappa Date: Fri, 13 Sep 2024 13:45:55 +0530 Subject: [PATCH 14/22] Fix: resolve nested attributes of anonymous records in GetDatamembers (#321) --- lib/Interpreter/CppInterOp.cpp | 51 +++++++++++-- unittests/CppInterOp/CMakeLists.txt | 6 ++ .../CppInterOp/VariableReflectionTest.cpp | 74 +++++++++++++++++++ 3 files changed, 125 insertions(+), 6 deletions(-) diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index 96aab8020..c91b26d79 100644 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -1128,9 +1128,31 @@ namespace Cpp { if (auto *CXXRD = llvm::dyn_cast_or_null(D)) { std::vector datamembers; - for (auto it = CXXRD->field_begin(), end = CXXRD->field_end(); it != end; - it++) { - datamembers.push_back((TCppScope_t)*it); + llvm::SmallVector stack_begin; + llvm::SmallVector stack_end; + stack_begin.push_back(CXXRD->field_begin()); + stack_end.push_back(CXXRD->field_end()); + while (!stack_begin.empty()) { + if (stack_begin.back() == stack_end.back()) { + stack_begin.pop_back(); + stack_end.pop_back(); + continue; + } + Decl* D = *(stack_begin.back()); + if (auto* FD = llvm::dyn_cast(D)) { + if (FD->isAnonymousStructOrUnion()) { + if (const auto* RT = FD->getType()->getAs()) { + if (auto* CXXRD = llvm::dyn_cast(RT->getDecl())) { + stack_begin.back()++; + stack_begin.push_back(CXXRD->field_begin()); + stack_end.push_back(CXXRD->field_end()); + continue; + } + } + } + } + datamembers.push_back((TCppScope_t)D); + stack_begin.back()++; } return datamembers; @@ -1175,9 +1197,26 @@ namespace Cpp { auto *D = (Decl *) var; auto &C = getASTContext(); - if (auto *FD = llvm::dyn_cast(D)) - return (intptr_t) C.toCharUnitsFromBits(C.getASTRecordLayout(FD->getParent()) - .getFieldOffset(FD->getFieldIndex())).getQuantity(); + if (auto* FD = llvm::dyn_cast(D)) { + const clang::RecordDecl* RD = FD->getParent(); + intptr_t offset = + C.toCharUnitsFromBits(C.getFieldOffset(FD)).getQuantity(); + while (RD->isAnonymousStructOrUnion()) { + const clang::RecordDecl* anon = RD; + RD = llvm::dyn_cast(anon->getParent()); + for (auto F = RD->field_begin(); F != RD->field_end(); ++F) { + const auto* RT = F->getType()->getAs(); + if (!RT) + continue; + if (anon == RT->getDecl()) { + FD = *F; + break; + } + } + offset += C.toCharUnitsFromBits(C.getFieldOffset(FD)).getQuantity(); + } + return offset; + } if (auto *VD = llvm::dyn_cast(D)) { auto GD = GlobalDecl(VD); diff --git a/unittests/CppInterOp/CMakeLists.txt b/unittests/CppInterOp/CMakeLists.txt index 00e455605..0e155f709 100644 --- a/unittests/CppInterOp/CMakeLists.txt +++ b/unittests/CppInterOp/CMakeLists.txt @@ -18,6 +18,12 @@ target_link_libraries(CppInterOpTests clangCppInterOp ) +if(NOT WIN32) + set_source_files_properties(VariableReflectionTest.cpp PROPERTIES COMPILE_FLAGS + "-Wno-pedantic" + ) +endif() + set_source_files_properties(InterpreterTest.cpp PROPERTIES COMPILE_DEFINITIONS "LLVM_BINARY_DIR=\"${LLVM_BINARY_DIR}\"" ) diff --git a/unittests/CppInterOp/VariableReflectionTest.cpp b/unittests/CppInterOp/VariableReflectionTest.cpp index 2c42897dd..efb604cde 100644 --- a/unittests/CppInterOp/VariableReflectionTest.cpp +++ b/unittests/CppInterOp/VariableReflectionTest.cpp @@ -39,6 +39,80 @@ TEST(VariableReflectionTest, GetDatamembers) { EXPECT_EQ(datamembers1.size(), 0); } +#define CODE \ + struct Klass1 { \ + Klass1(int i) : num(1), b(i) {} \ + int num; \ + union { \ + double a; \ + int b; \ + }; \ + } const k1(5); \ + struct Klass2 { \ + Klass2(double d) : num(2), a(d) {} \ + int num; \ + struct { \ + double a; \ + int b; \ + }; \ + } const k2(2.5); \ + struct Klass3 { \ + Klass3(int i) : num(i) {} \ + int num; \ + struct { \ + double a; \ + union { \ + float b; \ + int c; \ + }; \ + }; \ + int num2; \ + } const k3(5); + +CODE + +TEST(VariableReflectionTest, DatamembersWithAnonymousStructOrUnion) { + if (llvm::sys::RunningOnValgrind()) + GTEST_SKIP() << "XFAIL due to Valgrind report"; + + std::vector Decls; +#define Stringify(s) Stringifyx(s) +#define Stringifyx(...) #__VA_ARGS__ + GetAllTopLevelDecls(Stringify(CODE), Decls); +#undef Stringifyx +#undef Stringify +#undef CODE + + auto datamembers_klass1 = Cpp::GetDatamembers(Decls[0]); + auto datamembers_klass2 = Cpp::GetDatamembers(Decls[2]); + auto datamembers_klass3 = Cpp::GetDatamembers(Decls[4]); + + EXPECT_EQ(datamembers_klass1.size(), 3); + EXPECT_EQ(datamembers_klass2.size(), 3); + + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass1[0]), 0); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass1[1]), + ((intptr_t) & (k1.a)) - ((intptr_t) & (k1.num))); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass1[2]), + ((intptr_t) & (k1.b)) - ((intptr_t) & (k1.num))); + + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass2[0]), 0); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass2[1]), + ((intptr_t) & (k2.a)) - ((intptr_t) & (k2.num))); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass2[2]), + ((intptr_t) & (k2.b)) - ((intptr_t) & (k2.num))); + + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[0]), 0); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[1]), + ((intptr_t) & (k3.a)) - ((intptr_t) & (k3.num))); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[2]), + ((intptr_t) & (k3.b)) - ((intptr_t) & (k3.num))); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[3]), + ((intptr_t) & (k3.c)) - ((intptr_t) & (k3.num))); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[4]), + ((intptr_t) & (k3.num2)) - ((intptr_t) & (k3.num))); +} + TEST(VariableReflectionTest, LookupDatamember) { std::vector Decls; std::string code = R"( From 3f22184a5a13c9e86de255907914192bbacb4a99 Mon Sep 17 00:00:00 2001 From: Vipul Cariappa Date: Tue, 17 Sep 2024 14:33:02 +0000 Subject: [PATCH 15/22] resolve static attributes of records --- lib/Interpreter/CppInterOp.cpp | 3 +++ unittests/CppInterOp/VariableReflectionTest.cpp | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index c91b26d79..49814927d 100644 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -1155,6 +1155,9 @@ namespace Cpp { stack_begin.back()++; } + // static field member + GetClassDecls(scope, datamembers); + return datamembers; } diff --git a/unittests/CppInterOp/VariableReflectionTest.cpp b/unittests/CppInterOp/VariableReflectionTest.cpp index efb604cde..bbccb21f1 100644 --- a/unittests/CppInterOp/VariableReflectionTest.cpp +++ b/unittests/CppInterOp/VariableReflectionTest.cpp @@ -32,10 +32,15 @@ TEST(VariableReflectionTest, GetDatamembers) { auto datamembers = Cpp::GetDatamembers(Decls[0]); auto datamembers1 = Cpp::GetDatamembers(Decls[1]); + // non static field first EXPECT_EQ(Cpp::GetQualifiedName(datamembers[0]), "C::a"); EXPECT_EQ(Cpp::GetQualifiedName(datamembers[1]), "C::c"); EXPECT_EQ(Cpp::GetQualifiedName(datamembers[2]), "C::e"); - EXPECT_EQ(datamembers.size(), 3); + // static fields + EXPECT_EQ(Cpp::GetQualifiedName(datamembers[3]), "C::b"); + EXPECT_EQ(Cpp::GetQualifiedName(datamembers[4]), "C::d"); + EXPECT_EQ(Cpp::GetQualifiedName(datamembers[5]), "C::f"); + EXPECT_EQ(datamembers.size(), 6); EXPECT_EQ(datamembers1.size(), 0); } From bbb889568e6fc34227c32ab6bcba20f7ac8763a4 Mon Sep 17 00:00:00 2001 From: Vipul Cariappa Date: Wed, 18 Sep 2024 03:53:26 +0000 Subject: [PATCH 16/22] extracted to `GetStaticDatamembers` --- include/clang/Interpreter/CppInterOp.h | 8 +++++--- lib/Interpreter/CppInterOp.cpp | 9 ++++++--- unittests/CppInterOp/VariableReflectionTest.cpp | 15 ++++++++++----- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/include/clang/Interpreter/CppInterOp.h b/include/clang/Interpreter/CppInterOp.h index ef630de96..226a2ff99 100644 --- a/include/clang/Interpreter/CppInterOp.h +++ b/include/clang/Interpreter/CppInterOp.h @@ -424,11 +424,13 @@ namespace Cpp { /// Checks if the provided parameter is a 'Virtual' method. CPPINTEROP_API bool IsVirtualMethod(TCppFunction_t method); - /// Gets all the Fields/Data Members of a Class. For now, it - /// only gets non-static data members but in a future update, - /// it may support getting static data members as well. + /// Gets all the Fields/Data Members of a Class CPPINTEROP_API std::vector GetDatamembers(TCppScope_t scope); + /// Gets all the Static Fields/Data Members of a Class + CPPINTEROP_API std::vector + GetStaticDatamembers(TCppScope_t scope); + /// This is a Lookup function to be used specifically for data members. CPPINTEROP_API TCppScope_t LookupDatamember(const std::string& name, TCppScope_t parent); diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index 49814927d..1773abe99 100644 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -1155,15 +1155,18 @@ namespace Cpp { stack_begin.back()++; } - // static field member - GetClassDecls(scope, datamembers); - return datamembers; } return {}; } + std::vector GetStaticDatamembers(TCppScope_t scope) { + std::vector datamembers; + GetClassDecls(scope, datamembers); + return datamembers; + } + TCppScope_t LookupDatamember(const std::string& name, TCppScope_t parent) { clang::DeclContext *Within = 0; if (parent) { diff --git a/unittests/CppInterOp/VariableReflectionTest.cpp b/unittests/CppInterOp/VariableReflectionTest.cpp index bbccb21f1..7dc694297 100644 --- a/unittests/CppInterOp/VariableReflectionTest.cpp +++ b/unittests/CppInterOp/VariableReflectionTest.cpp @@ -31,17 +31,22 @@ TEST(VariableReflectionTest, GetDatamembers) { GetAllTopLevelDecls(code, Decls); auto datamembers = Cpp::GetDatamembers(Decls[0]); auto datamembers1 = Cpp::GetDatamembers(Decls[1]); + auto static_datamembers = Cpp::GetStaticDatamembers(Decls[0]); + auto static_datamembers1 = Cpp::GetStaticDatamembers(Decls[1]); // non static field first EXPECT_EQ(Cpp::GetQualifiedName(datamembers[0]), "C::a"); EXPECT_EQ(Cpp::GetQualifiedName(datamembers[1]), "C::c"); EXPECT_EQ(Cpp::GetQualifiedName(datamembers[2]), "C::e"); - // static fields - EXPECT_EQ(Cpp::GetQualifiedName(datamembers[3]), "C::b"); - EXPECT_EQ(Cpp::GetQualifiedName(datamembers[4]), "C::d"); - EXPECT_EQ(Cpp::GetQualifiedName(datamembers[5]), "C::f"); - EXPECT_EQ(datamembers.size(), 6); + EXPECT_EQ(datamembers.size(), 3); EXPECT_EQ(datamembers1.size(), 0); + + // static fields + EXPECT_EQ(Cpp::GetQualifiedName(static_datamembers[0]), "C::b"); + EXPECT_EQ(Cpp::GetQualifiedName(static_datamembers[1]), "C::d"); + EXPECT_EQ(Cpp::GetQualifiedName(static_datamembers[2]), "C::f"); + EXPECT_EQ(static_datamembers.size(), 3); + EXPECT_EQ(static_datamembers1.size(), 0); } #define CODE \ From 12e6e69f6d937dafb7eba72418fbb022d3fef125 Mon Sep 17 00:00:00 2001 From: Vipul Cariappa Date: Wed, 18 Sep 2024 14:33:01 +0000 Subject: [PATCH 17/22] apply changes from code review --- include/clang/Interpreter/CppInterOp.h | 7 +++++-- lib/Interpreter/CppInterOp.cpp | 5 ++--- .../CppInterOp/VariableReflectionTest.cpp | 20 +++++++++++-------- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/include/clang/Interpreter/CppInterOp.h b/include/clang/Interpreter/CppInterOp.h index 226a2ff99..5d8180c88 100644 --- a/include/clang/Interpreter/CppInterOp.h +++ b/include/clang/Interpreter/CppInterOp.h @@ -428,8 +428,11 @@ namespace Cpp { CPPINTEROP_API std::vector GetDatamembers(TCppScope_t scope); /// Gets all the Static Fields/Data Members of a Class - CPPINTEROP_API std::vector - GetStaticDatamembers(TCppScope_t scope); + ///\param[in] scope - class + ///\param[out] funcs - vector of static data members + CPPINTEROP_API void + GetStaticDatamembers(TCppScope_t scope, + std::vector& datamembers); /// This is a Lookup function to be used specifically for data members. CPPINTEROP_API TCppScope_t LookupDatamember(const std::string& name, diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index 1773abe99..d4b1578ea 100644 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -1161,10 +1161,9 @@ namespace Cpp { return {}; } - std::vector GetStaticDatamembers(TCppScope_t scope) { - std::vector datamembers; + void GetStaticDatamembers(TCppScope_t scope, + std::vector& datamembers) { GetClassDecls(scope, datamembers); - return datamembers; } TCppScope_t LookupDatamember(const std::string& name, TCppScope_t parent) { diff --git a/unittests/CppInterOp/VariableReflectionTest.cpp b/unittests/CppInterOp/VariableReflectionTest.cpp index 7dc694297..0cc01c9de 100644 --- a/unittests/CppInterOp/VariableReflectionTest.cpp +++ b/unittests/CppInterOp/VariableReflectionTest.cpp @@ -31,10 +31,8 @@ TEST(VariableReflectionTest, GetDatamembers) { GetAllTopLevelDecls(code, Decls); auto datamembers = Cpp::GetDatamembers(Decls[0]); auto datamembers1 = Cpp::GetDatamembers(Decls[1]); - auto static_datamembers = Cpp::GetStaticDatamembers(Decls[0]); - auto static_datamembers1 = Cpp::GetStaticDatamembers(Decls[1]); - // non static field first + // non static field EXPECT_EQ(Cpp::GetQualifiedName(datamembers[0]), "C::a"); EXPECT_EQ(Cpp::GetQualifiedName(datamembers[1]), "C::c"); EXPECT_EQ(Cpp::GetQualifiedName(datamembers[2]), "C::e"); @@ -42,11 +40,17 @@ TEST(VariableReflectionTest, GetDatamembers) { EXPECT_EQ(datamembers1.size(), 0); // static fields - EXPECT_EQ(Cpp::GetQualifiedName(static_datamembers[0]), "C::b"); - EXPECT_EQ(Cpp::GetQualifiedName(static_datamembers[1]), "C::d"); - EXPECT_EQ(Cpp::GetQualifiedName(static_datamembers[2]), "C::f"); - EXPECT_EQ(static_datamembers.size(), 3); - EXPECT_EQ(static_datamembers1.size(), 0); + datamembers.clear(); + datamembers1.clear(); + + Cpp::GetStaticDatamembers(Decls[0], datamembers); + Cpp::GetStaticDatamembers(Decls[1], datamembers1); + + EXPECT_EQ(Cpp::GetQualifiedName(datamembers[0]), "C::b"); + EXPECT_EQ(Cpp::GetQualifiedName(datamembers[1]), "C::d"); + EXPECT_EQ(Cpp::GetQualifiedName(datamembers[2]), "C::f"); + EXPECT_EQ(datamembers.size(), 3); + EXPECT_EQ(datamembers1.size(), 0); } #define CODE \ From 85b98c761e22d5b01b55508408f28ccf9363e256 Mon Sep 17 00:00:00 2001 From: maximusron Date: Thu, 19 Sep 2024 13:15:19 +0200 Subject: [PATCH 18/22] Make GetDataMember use an out param --- include/clang/Interpreter/CppInterOp.h | 3 ++- lib/Interpreter/CppInterOp.cpp | 11 +++-------- .../CppInterOp/VariableReflectionTest.cpp | 19 +++++++++++++------ 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/include/clang/Interpreter/CppInterOp.h b/include/clang/Interpreter/CppInterOp.h index 5d8180c88..2cbb66c61 100644 --- a/include/clang/Interpreter/CppInterOp.h +++ b/include/clang/Interpreter/CppInterOp.h @@ -425,7 +425,8 @@ namespace Cpp { CPPINTEROP_API bool IsVirtualMethod(TCppFunction_t method); /// Gets all the Fields/Data Members of a Class - CPPINTEROP_API std::vector GetDatamembers(TCppScope_t scope); + CPPINTEROP_API void GetDatamembers(TCppScope_t scope, + std::vector& datamembers); /// Gets all the Static Fields/Data Members of a Class ///\param[in] scope - class diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index d4b1578ea..1e2e66af7 100644 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -1122,12 +1122,11 @@ namespace Cpp { return false; } - std::vector GetDatamembers(TCppScope_t scope) - { + void GetDatamembers(TCppScope_t scope, + std::vector& datamembers) { auto *D = (Decl *) scope; - if (auto *CXXRD = llvm::dyn_cast_or_null(D)) { - std::vector datamembers; + if (auto* CXXRD = llvm::dyn_cast_or_null(D)) { llvm::SmallVector stack_begin; llvm::SmallVector stack_end; stack_begin.push_back(CXXRD->field_begin()); @@ -1154,11 +1153,7 @@ namespace Cpp { datamembers.push_back((TCppScope_t)D); stack_begin.back()++; } - - return datamembers; } - - return {}; } void GetStaticDatamembers(TCppScope_t scope, diff --git a/unittests/CppInterOp/VariableReflectionTest.cpp b/unittests/CppInterOp/VariableReflectionTest.cpp index 0cc01c9de..a1bd02810 100644 --- a/unittests/CppInterOp/VariableReflectionTest.cpp +++ b/unittests/CppInterOp/VariableReflectionTest.cpp @@ -28,9 +28,11 @@ TEST(VariableReflectionTest, GetDatamembers) { void sum(int,int); )"; + std::vector datamembers; + std::vector datamembers1; GetAllTopLevelDecls(code, Decls); - auto datamembers = Cpp::GetDatamembers(Decls[0]); - auto datamembers1 = Cpp::GetDatamembers(Decls[1]); + Cpp::GetDatamembers(Decls[0], datamembers); + Cpp::GetDatamembers(Decls[1], datamembers1); // non static field EXPECT_EQ(Cpp::GetQualifiedName(datamembers[0]), "C::a"); @@ -97,9 +99,13 @@ TEST(VariableReflectionTest, DatamembersWithAnonymousStructOrUnion) { #undef Stringify #undef CODE - auto datamembers_klass1 = Cpp::GetDatamembers(Decls[0]); - auto datamembers_klass2 = Cpp::GetDatamembers(Decls[2]); - auto datamembers_klass3 = Cpp::GetDatamembers(Decls[4]); + std::vector datamembers_klass1; + std::vector datamembers_klass2; + std::vector datamembers_klass3; + + Cpp::GetDatamembers(Decls[0], datamembers_klass1); + Cpp::GetDatamembers(Decls[2], datamembers_klass2); + Cpp::GetDatamembers(Decls[4], datamembers_klass3); EXPECT_EQ(datamembers_klass1.size(), 3); EXPECT_EQ(datamembers_klass2.size(), 3); @@ -203,7 +209,8 @@ TEST(VariableReflectionTest, GetVariableOffset) { #undef Stringify #undef CODE - auto datamembers = Cpp::GetDatamembers(Decls[2]); + std::vector datamembers; + Cpp::GetDatamembers(Decls[2], datamembers); EXPECT_TRUE((bool) Cpp::GetVariableOffset(Decls[0])); // a EXPECT_TRUE((bool) Cpp::GetVariableOffset(Decls[1])); // N From 57d09bda0892ac6241f994a96bdf845b4f55b936 Mon Sep 17 00:00:00 2001 From: Aaron Jomy <75925957+aaronj0@users.noreply.github.com> Date: Sun, 22 Sep 2024 20:17:43 +0200 Subject: [PATCH 19/22] Update README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fec26983d..cc7e2ddc7 100644 --- a/README.md +++ b/README.md @@ -212,14 +212,14 @@ cd ..\ ``` #### Environment variables -Regardless of whether you are building CppInterOP with Cling or Clang-REPL you will need to define the following Envirnoment variables (as they clear for a new session, it is recommended that you also add these to your .bashrc in linux, .bash_profile if on MacOS, or profile.ps1 on Windows). On Linux and MacOS you define as follows +Regardless of whether you are building CppInterOP with Cling or Clang-REPL you will need to define the following environment variables (as they clear for a new session, it is recommended that you also add these to your .bashrc in linux, .bash_profile if on MacOS, or profile.ps1 on Windows). On Linux and MacOS you define as follows ``` export CB_PYTHON_DIR="$PWD/cppyy-backend/python" export CPPINTEROP_DIR="$CB_PYTHON_DIR/cppyy_backend" export CPLUS_INCLUDE_PATH="${CPLUS_INCLUDE_PATH}:${LLVM_DIR}/llvm/include:${LLVM_DIR}/clang/include:${LLVM_DIR}/build/include:${LLVM_DIR}/build/tools/clang/include" export PYTHONPATH=$PYTHONPATH:$CPYCPPYY_DIR:$CB_PYTHON_DIR ``` -If on MacOS you will also need the following envirnoment variable defined +If on MacOS you will also need the following environment variable defined ``` export SDKROOT=`xcrun --show-sdk-path` ``` From 1c35b4179c04b49b3e409f52afca59b530600edb Mon Sep 17 00:00:00 2001 From: Aaron Jomy <75925957+aaronj0@users.noreply.github.com> Date: Tue, 24 Sep 2024 13:49:22 +0200 Subject: [PATCH 20/22] README update for cppyy build isolation --- README.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cc7e2ddc7..54cb6c4e7 100644 --- a/README.md +++ b/README.md @@ -217,7 +217,6 @@ Regardless of whether you are building CppInterOP with Cling or Clang-REPL you w export CB_PYTHON_DIR="$PWD/cppyy-backend/python" export CPPINTEROP_DIR="$CB_PYTHON_DIR/cppyy_backend" export CPLUS_INCLUDE_PATH="${CPLUS_INCLUDE_PATH}:${LLVM_DIR}/llvm/include:${LLVM_DIR}/clang/include:${LLVM_DIR}/build/include:${LLVM_DIR}/build/tools/clang/include" -export PYTHONPATH=$PYTHONPATH:$CPYCPPYY_DIR:$CB_PYTHON_DIR ``` If on MacOS you will also need the following environment variable defined ``` @@ -228,7 +227,6 @@ On Windows you define as follows (assumes you have defined $env:PWD_DIR= $PWD.Pa $env:CB_PYTHON_DIR="$env:PWD_DIR\cppyy-backend\python" $env:CPPINTEROP_DIR="$env:CB_PYTHON_DIR\cppyy_backend" $env:CPLUS_INCLUDE_PATH="$env:CPLUS_INCLUDE_PATH;$env:LLVM_DIR\llvm\include;$env:LLVM_DIR\clang\include;$env:LLVM_DIR\build\include;$env:LLVM_DIR\build\tools\clang\include" -$env:PYTHONPATH="$env:PYTHONPATH;$env:CPYCPPYY_DIR;$env:CB_PYTHON_DIR" ``` #### Build CppInterOp @@ -329,13 +327,22 @@ Note down the path to the `build` directory as `CPYCPPYY_DIR`: export CPYCPPYY_DIR=$PWD cd ../.. ``` +Export the `libcppyy` path to python: + +``` +export PYTHONPATH=$PYTHONPATH:$CPYCPPYY_DIR:$CB_PYTHON_DIR +``` +and on Windows: +``` +$env:PYTHONPATH="$env:PYTHONPATH;$env:CPYCPPYY_DIR;$env:CB_PYTHON_DIR" +``` #### Install cppyy ``` git clone --depth=1 https://github.com/compiler-research/cppyy.git cd cppyy -python -m pip install --upgrade . --no-deps +python -m pip install --upgrade . --no-deps --no-build-isolation cd .. ``` From f59f2cf1995f05db06bda577f6b406da9db57daa Mon Sep 17 00:00:00 2001 From: maximusron Date: Tue, 10 Sep 2024 12:19:31 +0200 Subject: [PATCH 21/22] Improve template instantiation for GetMethodTemplate --- lib/Interpreter/CppInterOp.cpp | 16 +++++++++++++++- unittests/CppInterOp/FunctionReflectionTest.cpp | 11 ++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index 1e2e66af7..074c7bf79 100644 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -1004,8 +1004,9 @@ namespace Cpp { continue; #endif - // FIXME : first score based on the type similarity before forcing + // TODO(aaronj0) : first score based on the type similarity before forcing // instantiation. + TCppFunction_t instantiated = InstantiateTemplate(candidate, arg_types.data(), arg_types.size()); if (instantiated) @@ -1018,6 +1019,19 @@ namespace Cpp { explicit_types.size()); if (instantiated) return instantiated; + + // join explicit and arg_types + std::vector total_arg_set; + total_arg_set.reserve(explicit_types.size() + arg_types.size()); + total_arg_set.insert(total_arg_set.end(), explicit_types.begin(), + explicit_types.end()); + total_arg_set.insert(total_arg_set.end(), arg_types.begin(), + arg_types.end()); + + instantiated = InstantiateTemplate(candidate, total_arg_set.data(), + total_arg_set.size()); + if (instantiated) + return instantiated; } return nullptr; } diff --git a/unittests/CppInterOp/FunctionReflectionTest.cpp b/unittests/CppInterOp/FunctionReflectionTest.cpp index 5b76e1001..c3c643b8d 100644 --- a/unittests/CppInterOp/FunctionReflectionTest.cpp +++ b/unittests/CppInterOp/FunctionReflectionTest.cpp @@ -597,6 +597,7 @@ TEST(FunctionReflectionTest, BestTemplateFunctionMatch) { template long get_size(A&); template long get_size(); template long get_size(A a, B b); + template long add_size(float a); }; template @@ -609,6 +610,11 @@ TEST(FunctionReflectionTest, BestTemplateFunctionMatch) { return sizeof(A) + 1; } + template + long MyTemplatedMethodClass::add_size(float a) { + return sizeof(A) + long(a); + } + template long MyTemplatedMethodClass::get_size(A a, B b) { return sizeof(A) + sizeof(B); @@ -626,14 +632,15 @@ TEST(FunctionReflectionTest, BestTemplateFunctionMatch) { std::vector args0; std::vector args1 = {C.IntTy.getAsOpaquePtr()}; std::vector args2 = {C.CharTy.getAsOpaquePtr(), C.FloatTy.getAsOpaquePtr()}; + std::vector args3 = {C.FloatTy.getAsOpaquePtr()}; std::vector explicit_args0; std::vector explicit_args1 = {C.IntTy.getAsOpaquePtr()}; - Cpp::TCppFunction_t func1 = Cpp::BestTemplateFunctionMatch(candidates, explicit_args0, args1); Cpp::TCppFunction_t func2 = Cpp::BestTemplateFunctionMatch(candidates, explicit_args1, args0); Cpp::TCppFunction_t func3 = Cpp::BestTemplateFunctionMatch(candidates, explicit_args0, args2); + Cpp::TCppFunction_t func4 = Cpp::BestTemplateFunctionMatch(candidates, explicit_args1, args3); EXPECT_EQ(Cpp::GetFunctionSignature(func1), "template<> long MyTemplatedMethodClass::get_size(int &)"); @@ -641,6 +648,8 @@ TEST(FunctionReflectionTest, BestTemplateFunctionMatch) { "template<> long MyTemplatedMethodClass::get_size()"); EXPECT_EQ(Cpp::GetFunctionSignature(func3), "template<> long MyTemplatedMethodClass::get_size(char a, float b)"); + EXPECT_EQ(Cpp::GetFunctionSignature(func4), + "template<> long MyTemplatedMethodClass::get_size(float &)"); } TEST(FunctionReflectionTest, IsPublicMethod) { From 0f406dacfcd28e8e617c5ebb2c49df9125e6b827 Mon Sep 17 00:00:00 2001 From: Vipul Cariappa Date: Fri, 27 Sep 2024 16:50:21 +0530 Subject: [PATCH 22/22] using `getFirstDecl` for `TranslationUnitDecl` for consistent pointers (#329) refactored `GetEnums` for this change by using `collectAllContexts` --- lib/Interpreter/CppInterOp.cpp | 41 +++++++++++++++++----------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index 074c7bf79..2b251dea3 100644 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -498,7 +498,7 @@ namespace Cpp { TCppScope_t GetGlobalScope() { - return getSema().getASTContext().getTranslationUnitDecl(); + return getSema().getASTContext().getTranslationUnitDecl()->getFirstDecl(); } static Decl *GetScopeFromType(QualType QT) { @@ -604,8 +604,12 @@ namespace Cpp { if (!ParentDC) return 0; - return (TCppScope_t) clang::Decl::castFromDeclContext( - ParentDC)->getCanonicalDecl(); + auto* P = clang::Decl::castFromDeclContext(ParentDC)->getCanonicalDecl(); + + if (auto* TU = llvm::dyn_cast_or_null(P)) + return (TCppScope_t)TU->getFirstDecl(); + + return (TCppScope_t)P; } TCppIndex_t GetNumBases(TCppScope_t klass) @@ -3088,27 +3092,22 @@ namespace Cpp { } void GetEnums(TCppScope_t scope, std::vector& Result) { - auto *D = (clang::Decl *)scope; - clang::DeclContext *DC; - clang::DeclContext::decl_iterator decl; + auto* D = static_cast(scope); - if (auto *TD = dyn_cast_or_null(D)) { - DC = clang::TagDecl::castToDeclContext(TD); - decl = DC->decls_begin(); - decl++; - } else if (auto *ND = dyn_cast_or_null(D)) { - DC = clang::NamespaceDecl::castToDeclContext(ND); - decl = DC->decls_begin(); - } else if (auto *TUD = dyn_cast_or_null(D)) { - DC = clang::TranslationUnitDecl::castToDeclContext(TUD); - decl = DC->decls_begin(); - } else { + if (!llvm::isa_and_nonnull(D)) return; - } - for (/* decl set above */; decl != DC->decls_end(); decl++) { - if (auto *ND = llvm::dyn_cast_or_null(*decl)) { - Result.push_back(ND->getNameAsString()); + auto* DC = llvm::dyn_cast(D); + + llvm::SmallVector DCs; + DC->collectAllContexts(DCs); + + // FIXME: We should use a lookup based approach instead of brute force + for (auto* DC : DCs) { + for (auto decl = DC->decls_begin(); decl != DC->decls_end(); decl++) { + if (auto* ND = llvm::dyn_cast_or_null(*decl)) { + Result.push_back(ND->getNameAsString()); + } } } }