diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 682b79021..90b2d3ca9 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 @@ -399,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 ` @@ -413,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. @@ -435,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 ` @@ -447,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 ".") @@ -470,6 +494,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 +529,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 +579,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 +610,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 +1125,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 +1156,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 +1187,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 @@ -1195,15 +1262,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: 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" 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/README.md b/README.md index e3f1d457d..54cb6c4e7 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. @@ -211,14 +212,13 @@ 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` ``` @@ -227,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 @@ -328,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 .. ``` 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 diff --git a/include/clang/Interpreter/CppInterOp.h b/include/clang/Interpreter/CppInterOp.h index 16451eb47..2cbb66c61 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 +#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 { @@ -31,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. @@ -272,8 +313,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. @@ -384,10 +424,16 @@ 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. - CPPINTEROP_API std::vector GetDatamembers(TCppScope_t scope); + /// Gets all the Fields/Data Members of a Class + CPPINTEROP_API void GetDatamembers(TCppScope_t scope, + std::vector& datamembers); + + /// Gets all the Static Fields/Data Members of a Class + ///\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, @@ -461,6 +507,10 @@ namespace Cpp { CPPINTEROP_API std::string GetFunctionArgName(TCppFunction_t func, TCppIndex_t param_index); + ///\returns function that performs operation op on lc and 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. ///\param[in] Args - the list of arguments for interpreter constructor. @@ -504,6 +554,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); @@ -518,7 +575,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. diff --git a/lib/Interpreter/Compatibility.h b/lib/Interpreter/Compatibility.h index ecc5a3be1..4feb60cb1 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 @@ -78,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, @@ -367,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 diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index 6eed01289..2b251dea3 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; @@ -493,7 +498,7 @@ namespace Cpp { TCppScope_t GetGlobalScope() { - return getSema().getASTContext().getTranslationUnitDecl(); + return getSema().getASTContext().getTranslationUnitDecl()->getFirstDecl(); } static Decl *GetScopeFromType(QualType QT) { @@ -599,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) @@ -805,11 +814,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 +968,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)); @@ -993,11 +999,18 @@ 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 + + // TODO(aaronj0) : first score based on the type similarity before forcing + // instantiation. - // FIXME : first score based on the type similarity before forcing - // instantiation try instantiating TCppFunction_t instantiated = InstantiateTemplate(candidate, arg_types.data(), arg_types.size()); if (instantiated) @@ -1010,6 +1023,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; } @@ -1114,21 +1140,43 @@ 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; - for (auto it = CXXRD->field_begin(), end = CXXRD->field_end(); it != end; - it++) { - datamembers.push_back((TCppScope_t)*it); + if (auto* CXXRD = llvm::dyn_cast_or_null(D)) { + 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; } + } - return {}; + void GetStaticDatamembers(TCppScope_t scope, + std::vector& datamembers) { + GetClassDecls(scope, datamembers); } TCppScope_t LookupDatamember(const std::string& name, TCppScope_t parent) { @@ -1167,9 +1215,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); @@ -1342,36 +1407,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. @@ -1741,9 +1813,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 @@ -2685,6 +2759,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 { @@ -2860,9 +2942,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; } @@ -3009,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()); + } } } } @@ -3135,6 +3213,25 @@ namespace Cpp { return PI->getNameAsString(); } + void GetBinaryOperator(TCppScope_t scope, enum BinaryOperator op, + std::vector& operators) { + Decl* D = static_cast(scope); + auto* DC = llvm::dyn_cast(D); + Scope* S = getSema().getScopeForContext(DC); + if (!S) + return; + + clang::UnresolvedSet<8> lookup; + + getSema().LookupBinOp(S, SourceLocation(), (clang::BinaryOperatorKind)op, + lookup); + + for (NamedDecl* D : lookup) { + if (auto* FD = llvm::dyn_cast(D)) + operators.push_back(FD); + } + } + TCppObject_t Allocate(TCppScope_t scope) { return (TCppObject_t)::operator new(Cpp::SizeOf(scope)); } diff --git a/lib/Interpreter/CppInterOpInterpreter.h b/lib/Interpreter/CppInterOpInterpreter.h index 07b74f1bb..e35840633 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); } @@ -378,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/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/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/FunctionReflectionTest.cpp b/unittests/CppInterOp/FunctionReflectionTest.cpp index afa5a584d..c3c643b8d 100644 --- a/unittests/CppInterOp/FunctionReflectionTest.cpp +++ b/unittests/CppInterOp/FunctionReflectionTest.cpp @@ -589,6 +589,69 @@ 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 add_size(float a); + }; + + template + long MyTemplatedMethodClass::get_size(A&) { + return sizeof(A); + } + + template + long MyTemplatedMethodClass::get_size() { + 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); + } + )"; + + 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 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 &)"); + EXPECT_EQ(Cpp::GetFunctionSignature(func2), + "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) { std::vector Decls, SubDecls; std::string code = R"( 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(); diff --git a/unittests/CppInterOp/ScopeReflectionTest.cpp b/unittests/CppInterOp/ScopeReflectionTest.cpp index 2939ae966..d0da1c2f8 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 @@ -948,3 +952,49 @@ 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()); + + 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); +} diff --git a/unittests/CppInterOp/VariableReflectionTest.cpp b/unittests/CppInterOp/VariableReflectionTest.cpp index 2c42897dd..a1bd02810 100644 --- a/unittests/CppInterOp/VariableReflectionTest.cpp +++ b/unittests/CppInterOp/VariableReflectionTest.cpp @@ -28,15 +28,109 @@ 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"); EXPECT_EQ(Cpp::GetQualifiedName(datamembers[1]), "C::c"); EXPECT_EQ(Cpp::GetQualifiedName(datamembers[2]), "C::e"); EXPECT_EQ(datamembers.size(), 3); EXPECT_EQ(datamembers1.size(), 0); + + // static fields + 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 \ + 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 + + 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); + + 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) { @@ -115,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