From ad03dcb3358ed69326dc216979766be69b37df84 Mon Sep 17 00:00:00 2001 From: Aaron Jomy Date: Wed, 15 Oct 2025 14:07:22 +0200 Subject: [PATCH 1/9] Add CppInterOp API dispatch mechanism This defines the mechanism which enables dispatching of the CppInterOp API without linking to it, preventing any LLVM or Clang symbols from being leaked into the client application. Can be used to deploy CppInterOp in an environment where dynamic linking is not favourable and the only option is dlopen'ing `libClangCppInterOp.so` with `RTLD_LOCAL` --- include/CppInterOp/CppInterOpDispatch.h | 597 +++++++++++++++++++++++ lib/CppInterOp/CMakeLists.txt | 1 + lib/CppInterOp/CppInterOpDispatch.cpp | 148 ++++++ unittests/CppInterOp/CMakeLists.txt | 8 + unittests/CppInterOp/DispatchAPITest.cpp | 57 +++ 5 files changed, 811 insertions(+) create mode 100644 include/CppInterOp/CppInterOpDispatch.h create mode 100644 lib/CppInterOp/CppInterOpDispatch.cpp create mode 100644 unittests/CppInterOp/DispatchAPITest.cpp diff --git a/include/CppInterOp/CppInterOpDispatch.h b/include/CppInterOp/CppInterOpDispatch.h new file mode 100644 index 000000000..b7db9cd95 --- /dev/null +++ b/include/CppInterOp/CppInterOpDispatch.h @@ -0,0 +1,597 @@ +//--------------------------------------------------------------------*- C++ -*- +// CppInterOp Dispatch Mechanism +// author: Aaron Jomy +//===----------------------------------------------------------------------===// +// +// This defines the mechanism which enables dispatching of the CppInterOp API +// without linking to it, preventing any LLVM or Clang symbols from being leaked +// into the client application. +// +//===----------------------------------------------------------------------===// +#ifndef CPPINTEROP_CPPINTEROPDISPATCH_H +#define CPPINTEROP_CPPINTEROPDISPATCH_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +// Configured by CMake, can be overridden by defining before including this +// header +#ifndef CPPINTEROP_LIBRARY_PATH +#define CPPINTEROP_LIBRARY_PATH "@CPPINTEROP_LIBRARY_PATH@" +#endif + +using __CPP_FUNC = void (*)(); + +///\param[in] procname - the name of the FunctionEntry in the symbol lookup +/// table. +/// +///\returns the function address of the requested API, or nullptr if not found +extern "C" CPPINTEROP_API void ( + *CppGetProcAddress(const unsigned char* procname))(void); + +#define DECLARE_CPP_NULL(func_name) CppAPIType::func_name func_name = nullptr; + +#define EXTERN_CPP_FUNC(func_name) extern CppAPIType::func_name func_name; + +#define LOAD_CPP_FUNCTION(func_name) \ + func_name = \ + reinterpret_cast(dlGetProcAddress(#func_name)); + +// macro that allows declaration and loading of all CppInterOp API functions in +// a consistent way. This is used as our dispatched API list, along with the +// name-address pair table +#define FOR_EACH_CPP_FUNCTION(DO) \ + DO(CreateInterpreter) \ + DO(GetInterpreter) \ + DO(Process) \ + DO(GetResourceDir) \ + DO(AddIncludePath) \ + DO(LoadLibrary) \ + DO(Declare) \ + DO(DeleteInterpreter) \ + DO(IsNamespace) \ + DO(ObjToString) \ + DO(GetQualifiedCompleteName) \ + DO(GetValueKind) \ + DO(GetNonReferenceType) \ + DO(IsEnumType) \ + DO(GetIntegerTypeFromEnumType) \ + DO(GetReferencedType) \ + DO(IsPointerType) \ + DO(GetPointeeType) \ + DO(GetPointerType) \ + DO(IsReferenceType) \ + DO(GetTypeAsString) \ + DO(GetCanonicalType) \ + DO(HasTypeQualifier) \ + DO(RemoveTypeQualifier) \ + DO(GetUnderlyingType) \ + DO(IsRecordType) \ + DO(IsFunctionPointerType) \ + DO(GetVariableType) \ + DO(GetNamed) \ + DO(GetScopeFromType) \ + DO(GetClassTemplateInstantiationArgs) \ + DO(IsClass) \ + DO(GetType) \ + DO(GetTypeFromScope) \ + DO(GetComplexType) \ + DO(GetIntegerTypeFromEnumScope) \ + DO(GetUnderlyingScope) \ + DO(GetScope) \ + DO(GetGlobalScope) \ + DO(GetScopeFromCompleteName) \ + DO(InstantiateTemplate) \ + DO(GetParentScope) \ + DO(IsTemplate) \ + DO(IsTemplateSpecialization) \ + DO(IsTypedefed) \ + DO(IsClassPolymorphic) \ + DO(Demangle) \ + DO(SizeOf) \ + DO(GetSizeOfType) \ + DO(IsBuiltin) \ + DO(IsComplete) \ + DO(Allocate) \ + DO(Deallocate) \ + DO(Construct) \ + DO(Destruct) \ + DO(MakeFunctionCallable) \ + DO(GetFunctionAddress) \ + DO(IsAbstract) \ + DO(IsEnumScope) \ + DO(IsEnumConstant) \ + DO(IsAggregate) \ + DO(HasDefaultConstructor) \ + DO(IsVariable) \ + DO(GetAllCppNames) \ + DO(GetUsingNamespaces) \ + DO(GetCompleteName) \ + DO(GetDestructor) \ + DO(IsVirtualMethod) \ + DO(GetNumBases) \ + DO(GetName) \ + DO(GetBaseClass) \ + DO(IsSubclass) \ + DO(GetOperator) \ + DO(GetFunctionReturnType) \ + DO(GetBaseClassOffset) \ + DO(GetClassMethods) \ + DO(GetFunctionsUsingName) \ + DO(GetFunctionNumArgs) \ + DO(GetFunctionRequiredArgs) \ + DO(GetFunctionArgName) \ + DO(GetFunctionArgType) \ + DO(GetFunctionArgDefault) \ + DO(IsConstMethod) \ + DO(GetFunctionTemplatedDecls) \ + DO(ExistsFunctionTemplate) \ + DO(IsTemplatedFunction) \ + DO(IsStaticMethod) \ + DO(GetClassTemplatedMethods) \ + DO(BestOverloadFunctionMatch) \ + DO(GetOperatorFromSpelling) \ + DO(IsFunctionDeleted) \ + DO(IsPublicMethod) \ + DO(IsProtectedMethod) \ + DO(IsPrivateMethod) \ + DO(IsConstructor) \ + DO(IsDestructor) \ + DO(GetDatamembers) \ + DO(GetStaticDatamembers) \ + DO(GetEnumConstantDatamembers) \ + DO(LookupDatamember) \ + DO(IsLambdaClass) \ + DO(GetQualifiedName) \ + DO(GetVariableOffset) \ + DO(IsPublicVariable) \ + DO(IsProtectedVariable) \ + DO(IsPrivateVariable) \ + DO(IsStaticVariable) \ + DO(IsConstVariable) \ + DO(GetDimensions) \ + DO(GetEnumConstants) \ + DO(GetEnumConstantType) \ + DO(GetEnumConstantValue) \ + DO(DumpScope) \ + DO(AddSearchPath) \ + DO(Evaluate) \ + DO(IsDebugOutputEnabled) \ + DO(EnableDebugOutput) + +namespace CppDispatch { +// Forward all type aliases +using TCppIndex_t = ::Cpp::TCppIndex_t; +using TCppScope_t = ::Cpp::TCppScope_t; +using TCppConstScope_t = ::Cpp::TCppConstScope_t; +using TCppType_t = ::Cpp::TCppType_t; +using TCppFunction_t = ::Cpp::TCppFunction_t; +using TCppConstFunction_t = ::Cpp::TCppConstFunction_t; +using TCppFuncAddr_t = ::Cpp::TCppFuncAddr_t; +using TInterp_t = ::Cpp::TInterp_t; +using TCppObject_t = ::Cpp::TCppObject_t; + +using Operator = ::Cpp::Operator; +using OperatorArity = ::Cpp::OperatorArity; +using QualKind = ::Cpp::QualKind; +using TemplateArgInfo = ::Cpp::TemplateArgInfo; +using ValueKind = ::Cpp::ValueKind; + +using JitCall = ::Cpp::JitCall; +} // end namespace CppDispatch + +namespace CppAPIType { + +using GetVersion = std::string (*)(); + +using Demangle = std::string (*)(const std::string& mangled_name); + +using EnableDebugOutput = void (*)(bool value); + +using IsDebugOutputEnabled = bool (*)(); + +using IsAggregate = bool (*)(Cpp::TCppScope_t scope); + +using IsNamespace = bool (*)(Cpp::TCppScope_t scope); + +using IsClass = bool (*)(Cpp::TCppScope_t scope); + +using IsFunction = bool (*)(Cpp::TCppScope_t scope); + +using IsFunctionPointerType = bool (*)(Cpp::TCppType_t type); + +using IsClassPolymorphic = bool (*)(Cpp::TCppScope_t klass); + +using IsComplete = bool (*)(Cpp::TCppScope_t scope); + +using SizeOf = size_t (*)(Cpp::TCppScope_t scope); + +using IsBuiltin = bool (*)(Cpp::TCppType_t type); + +using IsTemplate = bool (*)(Cpp::TCppScope_t handle); + +using IsTemplateSpecialization = bool (*)(Cpp::TCppScope_t handle); + +using IsTypedefed = bool (*)(Cpp::TCppScope_t handle); + +using IsAbstract = bool (*)(Cpp::TCppType_t klass); + +using IsEnumScope = bool (*)(Cpp::TCppScope_t handle); + +using IsEnumConstant = bool (*)(Cpp::TCppScope_t handle); + +using IsEnumType = bool (*)(Cpp::TCppType_t type); + +using HasTypeQualifier = bool (*)(Cpp::TCppType_t type, Cpp::QualKind qual); + +using RemoveTypeQualifier = Cpp::TCppType_t (*)(Cpp::TCppType_t type, + Cpp::QualKind qual); + +using AddTypeQualifier = Cpp::TCppType_t (*)(Cpp::TCppType_t type, + Cpp::QualKind qual); + +using GetEnums = void (*)(Cpp::TCppScope_t scope, + std::vector& Result); + +using IsSmartPtrType = bool (*)(Cpp::TCppType_t type); + +using GetIntegerTypeFromEnumScope = + Cpp::TCppType_t (*)(Cpp::TCppScope_t handle); + +using GetIntegerTypeFromEnumType = Cpp::TCppType_t (*)(Cpp::TCppType_t handle); + +using GetEnumConstants = + std::vector (*)(Cpp::TCppScope_t scope); + +using GetEnumConstantType = Cpp::TCppType_t (*)(Cpp::TCppScope_t scope); + +using GetEnumConstantValue = Cpp::TCppIndex_t (*)(Cpp::TCppScope_t scope); + +using GetSizeOfType = size_t (*)(Cpp::TCppType_t type); + +using IsVariable = bool (*)(Cpp::TCppScope_t scope); + +using GetName = std::string (*)(Cpp::TCppScope_t klass); + +using GetCompleteName = std::string (*)(Cpp::TCppScope_t klass); + +using GetQualifiedName = std::string (*)(Cpp::TCppScope_t klass); + +using GetQualifiedCompleteName = std::string (*)(Cpp::TCppScope_t klass); + +using GetUsingNamespaces = + std::vector (*)(Cpp::TCppScope_t scope); + +using GetGlobalScope = Cpp::TCppScope_t (*)(); + +using GetUnderlyingScope = Cpp::TCppScope_t (*)(Cpp::TCppScope_t scope); + +using GetScope = Cpp::TCppScope_t (*)(const std::string& name, + Cpp::TCppScope_t parent); + +using GetScopeFromCompleteName = Cpp::TCppScope_t (*)(const std::string& name); + +using GetNamed = Cpp::TCppScope_t (*)(const std::string& name, + Cpp::TCppScope_t parent); + +using GetParentScope = Cpp::TCppScope_t (*)(Cpp::TCppScope_t scope); + +using GetScopeFromType = Cpp::TCppScope_t (*)(Cpp::TCppType_t type); + +using GetNumBases = Cpp::TCppIndex_t (*)(Cpp::TCppScope_t klass); + +using GetBaseClass = Cpp::TCppScope_t (*)(Cpp::TCppScope_t klass, + Cpp::TCppIndex_t ibase); + +using IsSubclass = bool (*)(Cpp::TCppScope_t derived, Cpp::TCppScope_t base); + +using GetBaseClassOffset = int64_t (*)(Cpp::TCppScope_t derived, + Cpp::TCppScope_t base); + +using GetClassMethods = void (*)(Cpp::TCppScope_t klass, + std::vector& methods); + +using GetFunctionTemplatedDecls = + void (*)(Cpp::TCppScope_t klass, std::vector& methods); + +using HasDefaultConstructor = bool (*)(Cpp::TCppScope_t scope); + +using GetDefaultConstructor = Cpp::TCppFunction_t (*)(Cpp::TCppScope_t scope); + +using GetDestructor = Cpp::TCppFunction_t (*)(Cpp::TCppScope_t scope); + +using GetFunctionsUsingName = std::vector (*)( + Cpp::TCppScope_t scope, const std::string& name); + +using GetFunctionReturnType = Cpp::TCppType_t (*)(Cpp::TCppFunction_t func); + +using GetFunctionNumArgs = Cpp::TCppIndex_t (*)(Cpp::TCppFunction_t func); + +using GetFunctionRequiredArgs = + Cpp::TCppIndex_t (*)(Cpp::TCppConstFunction_t func); + +using GetFunctionArgType = Cpp::TCppType_t (*)(Cpp::TCppFunction_t func, + Cpp::TCppIndex_t iarg); + +using GetFunctionSignature = std::string (*)(Cpp::TCppFunction_t func); + +using IsFunctionDeleted = bool (*)(Cpp::TCppConstFunction_t function); + +using IsTemplatedFunction = bool (*)(Cpp::TCppFunction_t func); + +using ExistsFunctionTemplate = bool (*)(const std::string& name, + Cpp::TCppScope_t parent); + +using GetClassTemplatedMethods = + bool (*)(const std::string& name, Cpp::TCppScope_t parent, + std::vector& funcs); + +using IsMethod = bool (*)(Cpp::TCppConstFunction_t method); + +using IsPublicMethod = bool (*)(Cpp::TCppFunction_t method); + +using IsProtectedMethod = bool (*)(Cpp::TCppFunction_t method); + +using IsPrivateMethod = bool (*)(Cpp::TCppFunction_t method); + +using IsConstructor = bool (*)(Cpp::TCppConstFunction_t method); + +using IsDestructor = bool (*)(Cpp::TCppConstFunction_t method); + +using IsStaticMethod = bool (*)(Cpp::TCppConstFunction_t method); + +using GetFunctionAddressFromName = + Cpp::TCppFuncAddr_t (*)(const char* mangled_name); + +using GetFunctionAddressFromMethod = + Cpp::TCppFuncAddr_t (*)(Cpp::TCppFunction_t method); + +using IsVirtualMethod = bool (*)(Cpp::TCppFunction_t method); + +using GetDatamembers = void (*)(Cpp::TCppScope_t scope, + std::vector& datamembers); + +using GetStaticDatamembers = void (*)( + Cpp::TCppScope_t scope, std::vector& datamembers); + +using GetEnumConstantDatamembers = + void (*)(Cpp::TCppScope_t scope, std::vector& datamembers, + bool include_enum_class); + +using LookupDatamember = Cpp::TCppScope_t (*)(const std::string& name, + Cpp::TCppScope_t parent); + +using IsLambdaClass = bool (*)(Cpp::TCppType_t type); + +using GetVariableType = Cpp::TCppType_t (*)(Cpp::TCppScope_t var); + +using GetVariableOffset = intptr_t (*)(Cpp::TCppScope_t var, + Cpp::TCppScope_t parent); + +using IsPublicVariable = bool (*)(Cpp::TCppScope_t var); + +using IsProtectedVariable = bool (*)(Cpp::TCppScope_t var); + +using IsPrivateVariable = bool (*)(Cpp::TCppScope_t var); + +using IsStaticVariable = bool (*)(Cpp::TCppScope_t var); + +using IsConstVariable = bool (*)(Cpp::TCppScope_t var); + +using IsRecordType = bool (*)(Cpp::TCppType_t type); + +using IsPODType = bool (*)(Cpp::TCppType_t type); + +using IsPointerType = bool (*)(Cpp::TCppType_t type); + +using GetPointeeType = Cpp::TCppType_t (*)(Cpp::TCppType_t type); + +using IsReferenceType = bool (*)(Cpp::TCppType_t type); + +using GetValueKind = Cpp::ValueKind (*)(Cpp::TCppType_t type); + +using IsRValueReferenceType = bool (*)(Cpp::TCppType_t type); + +using GetPointerType = Cpp::TCppType_t (*)(Cpp::TCppType_t type); + +using GetReferencedType = Cpp::TCppType_t (*)(Cpp::TCppType_t type, + bool rvalue); + +using GetNonReferenceType = Cpp::TCppType_t (*)(Cpp::TCppType_t type); + +using GetTypeAsString = std::string (*)(Cpp::TCppType_t type); + +using GetCanonicalType = Cpp::TCppType_t (*)(Cpp::TCppType_t type); + +using JitCallMakeFunctionCallable = + Cpp::JitCall (*)(Cpp::TCppConstFunction_t func); + +using IsConstMethod = bool (*)(Cpp::TCppFunction_t method); + +using GetFunctionArgDefault = std::string (*)(Cpp::TCppFunction_t func, + Cpp::TCppIndex_t param_index); + +using GetFunctionArgName = std::string (*)(Cpp::TCppFunction_t func, + Cpp::TCppIndex_t param_index); + +using GetSpellingFromOperator = std::string (*)(Cpp::Operator op); + +using GetOperatorFromSpelling = Cpp::Operator (*)(const std::string& op); + +using GetOperatorArity = Cpp::OperatorArity (*)(Cpp::TCppFunction_t op); + +using GetOperator = void (*)(Cpp::TCppScope_t scope, Cpp::Operator op, + std::vector& operators, + Cpp::OperatorArity kind); + +using CreateInterpreter = + Cpp::TInterp_t (*)(const std::vector& Args, + const std::vector& GpuArgs); + +using DeleteInterpreter = bool (*)(Cpp::TInterp_t interp); + +using ActivateInterpreter = bool (*)(Cpp::TInterp_t interp); + +using GetInterpreter = Cpp::TInterp_t (*)(); + +using UseExternalInterpreter = void (*)(Cpp::TInterp_t interp); + +using AddSearchPath = void (*)(const char* dir, bool isUser, bool prepend); + +using GetResourceDir = const char* (*)(); + +using DetectResourceDir = std::string (*)(const char* ClangBinaryName); + +using DetectSystemCompilerIncludePaths = + void (*)(std::vector& Paths, const char* CompilerName); + +using AddIncludePath = void (*)(const char* dir); + +using GetIncludePaths = void (*)(std::vector& IncludePaths, + bool withSystem, bool withFlags); + +using Declare = int (*)(const char* code, bool silent); + +using Process = int (*)(const char* code); + +using Evaluate = intptr_t (*)(const char* code, bool* HadError); + +using LookupLibrary = std::string (*)(const char* lib_name); + +using LoadLibrary = bool (*)(const char* lib_stem, bool lookup); + +using UnloadLibrary = void (*)(const char* lib_stem); + +using SearchLibrariesForSymbol = std::string (*)(const char* mangled_name, + bool search_system); + +using InsertOrReplaceJitSymbol = bool (*)(const char* linker_mangled_name, + uint64_t address); + +using ObjToString = std::string (*)(const char* type, void* obj); + +using GetUnderlyingType = Cpp::TCppType_t (*)(Cpp::TCppType_t type); + +using BestOverloadFunctionMatch = Cpp::TCppFunction_t (*)( + const std::vector& candidates, + const std::vector& explicit_types, + const std::vector& arg_types); + +using GetDimensions = std::vector (*)(Cpp::TCppType_t var); + +using DumpScope = void (*)(Cpp::TCppScope_t scope); + +using GetClassTemplateInstantiationArgs = + void (*)(Cpp::TCppScope_t klass, std::vector& args); + +using GetAllCppNames = void (*)(Cpp::TCppScope_t scope, + std::set& names); + +using Deallocate = void (*)(Cpp::TCppScope_t scope, Cpp::TCppObject_t address, + Cpp::TCppIndex_t count); + +using Allocate = Cpp::TCppObject_t (*)(Cpp::TCppScope_t scope, + Cpp::TCppIndex_t count); + +using InstantiateTemplate = Cpp::TCppScope_t (*)( + Cpp::TCppScope_t tmpl, const Cpp::TemplateArgInfo* template_args, + size_t template_args_size, bool instantiate_body); + +using GetComplexType = Cpp::TCppType_t (*)(Cpp::TCppType_t type); + +using GetTypeFromScope = Cpp::TCppType_t (*)(Cpp::TCppScope_t klass); + +using GetType = Cpp::TCppType_t (*)(const std::string& type); + +using Construct = Cpp::TCppObject_t (*)(Cpp::TCppScope_t scope, + Cpp::TCppObject_t arena, + Cpp::TCppIndex_t count); + +using Destruct = bool (*)(Cpp::TCppObject_t This, Cpp::TCppScope_t scope, + bool withFree, Cpp::TCppIndex_t count); + +using MakeFunctionCallable = Cpp::JitCall (*)(Cpp::TCppConstFunction_t func); +using GetFunctionAddress = + Cpp::TCppFuncAddr_t (*)(Cpp::TCppConstFunction_t func); +} // end namespace CppAPIType + +// TODO: implement overload that takes an existing opened DL handle +inline void* dlGetProcAddress(const char* name, + const char* customLibPath = nullptr) { + if (!name) + return nullptr; + + static std::once_flag loaded; + static void* handle = nullptr; + static void* (*getCppProcAddress)(const char*) = nullptr; + + std::call_once(loaded, [customLibPath]() { + // priority order: 1) custom path argument, or CPPINTEROP_LIBRARY_PATH via + // 2) cmake configured path 3) env vars + const char* libPath = customLibPath; + if (!libPath) { + libPath = std::getenv("CPPINTEROP_LIBRARY_PATH"); + } + if (!libPath || libPath[0] == '\0') { + libPath = CPPINTEROP_LIBRARY_PATH; + } + + handle = dlopen(libPath, RTLD_LOCAL | RTLD_NOW); + if (!handle) { + std::cerr << "[CppInterOp] Failed to load library from " << libPath + << ": " << dlerror() << '\n'; + return; + } + + getCppProcAddress = reinterpret_cast( + dlsym(handle, "CppGetProcAddress")); + if (!getCppProcAddress) { + std::cerr << "[CppInterOp] Failed to find CppGetProcAddress: " + << dlerror() << '\n'; + dlclose(handle); + handle = nullptr; + } + }); + + return getCppProcAddress ? getCppProcAddress(name) : nullptr; +} +namespace CppDispatch { +FOR_EACH_CPP_FUNCTION(EXTERN_CPP_FUNC); +/// Initialize all CppInterOp API from the dynamically loaded library +/// (RTLD_LOCAL) \param[in] customLibPath Optional custom path to +/// libclangCppInterOp.so \returns true if initialization succeeded, false +/// otherwise +inline bool init_functions(const char* customLibPath = nullptr) { + // trigger library loading if custom path provided + if (customLibPath) { + void* test = dlGetProcAddress("GetInterpreter", customLibPath); + if (!test) { + std::cerr << "[CppInterOp] Failed to initialize with custom path: " + << customLibPath << '\n'; + return false; + } + } + + FOR_EACH_CPP_FUNCTION(LOAD_CPP_FUNCTION); + + // test to verify that critical (and consequently all) functions loaded + if (!GetInterpreter || !CreateInterpreter) { + std::cerr << "[CppInterOp] Failed to load critical functions" << std::endl; + return false; + } + + return true; +} +} // namespace CppDispatch + +#endif // CPPINTEROP_CPPINTEROPDISPATCH_H diff --git a/lib/CppInterOp/CMakeLists.txt b/lib/CppInterOp/CMakeLists.txt index 5f5cbf1d1..2b353d81b 100644 --- a/lib/CppInterOp/CMakeLists.txt +++ b/lib/CppInterOp/CMakeLists.txt @@ -107,6 +107,7 @@ endif(LLVM_LINK_LLVM_DYLIB) add_llvm_library(clangCppInterOp DISABLE_LLVM_LINK_LLVM_DYLIB CppInterOp.cpp + CppInterOpDispatch.cpp CXCppInterOp.cpp ${DLM} LINK_LIBS diff --git a/lib/CppInterOp/CppInterOpDispatch.cpp b/lib/CppInterOp/CppInterOpDispatch.cpp new file mode 100644 index 000000000..fc5bb2d9a --- /dev/null +++ b/lib/CppInterOp/CppInterOpDispatch.cpp @@ -0,0 +1,148 @@ +//------------------------------------------------------------------------------ +// CppInterOp Dispatch Implementation +// author: Aaron Jomy +//------------------------------------------------------------------------------ + +#include +#include + +#include + +static const std::unordered_map + INTEROP_FUNCTIONS = { + {"GetInterpreter", (__CPP_FUNC)Cpp::GetInterpreter}, + {"CreateInterpreter", (__CPP_FUNC)Cpp::CreateInterpreter}, + {"Process", (__CPP_FUNC)Cpp::Process}, + {"GetResourceDir", (__CPP_FUNC)Cpp::GetResourceDir}, + {"AddIncludePath", (__CPP_FUNC)Cpp::AddIncludePath}, + {"LoadLibrary", (__CPP_FUNC)Cpp::LoadLibrary}, + {"Declare", (__CPP_FUNC)Cpp::Declare}, + {"DeleteInterpreter", (__CPP_FUNC)Cpp::DeleteInterpreter}, + {"IsNamespace", (__CPP_FUNC)Cpp::IsNamespace}, + {"ObjToString", (__CPP_FUNC)Cpp::ObjToString}, + {"GetQualifiedCompleteName", (__CPP_FUNC)Cpp::GetQualifiedCompleteName}, + {"GetValueKind", (__CPP_FUNC)Cpp::GetValueKind}, + {"GetNonReferenceType", (__CPP_FUNC)Cpp::GetNonReferenceType}, + {"IsEnumType", (__CPP_FUNC)Cpp::IsEnumType}, + {"GetIntegerTypeFromEnumType", + (__CPP_FUNC)Cpp::GetIntegerTypeFromEnumType}, + {"GetReferencedType", (__CPP_FUNC)Cpp::GetReferencedType}, + {"IsPointerType", (__CPP_FUNC)Cpp::IsPointerType}, + {"GetPointeeType", (__CPP_FUNC)Cpp::GetPointeeType}, + {"GetPointerType", (__CPP_FUNC)Cpp::GetPointerType}, + {"IsReferenceType", (__CPP_FUNC)Cpp::IsReferenceType}, + {"GetTypeAsString", (__CPP_FUNC)Cpp::GetTypeAsString}, + {"GetCanonicalType", (__CPP_FUNC)Cpp::GetCanonicalType}, + {"HasTypeQualifier", (__CPP_FUNC)Cpp::HasTypeQualifier}, + {"RemoveTypeQualifier", (__CPP_FUNC)Cpp::RemoveTypeQualifier}, + {"GetUnderlyingType", (__CPP_FUNC)Cpp::GetUnderlyingType}, + {"IsRecordType", (__CPP_FUNC)Cpp::IsRecordType}, + {"IsFunctionPointerType", (__CPP_FUNC)Cpp::IsFunctionPointerType}, + {"GetVariableType", (__CPP_FUNC)Cpp::GetVariableType}, + {"GetNamed", (__CPP_FUNC)Cpp::GetNamed}, + {"GetScopeFromType", (__CPP_FUNC)Cpp::GetScopeFromType}, + {"GetClassTemplateInstantiationArgs", + (__CPP_FUNC)Cpp::GetClassTemplateInstantiationArgs}, + {"IsClass", (__CPP_FUNC)Cpp::IsClass}, + {"GetType", (__CPP_FUNC)Cpp::GetType}, + {"GetTypeFromScope", (__CPP_FUNC)Cpp::GetTypeFromScope}, + {"GetComplexType", (__CPP_FUNC)Cpp::GetComplexType}, + {"GetIntegerTypeFromEnumScope", + (__CPP_FUNC)Cpp::GetIntegerTypeFromEnumScope}, + {"GetUnderlyingScope", (__CPP_FUNC)Cpp::GetUnderlyingScope}, + {"GetScope", (__CPP_FUNC)Cpp::GetScope}, + {"GetGlobalScope", (__CPP_FUNC)Cpp::GetGlobalScope}, + {"GetScopeFromCompleteName", (__CPP_FUNC)Cpp::GetScopeFromCompleteName}, + {"InstantiateTemplate", (__CPP_FUNC)Cpp::InstantiateTemplate}, + {"GetParentScope", (__CPP_FUNC)Cpp::GetParentScope}, + {"IsTemplate", (__CPP_FUNC)Cpp::IsTemplate}, + {"IsTemplateSpecialization", (__CPP_FUNC)Cpp::IsTemplateSpecialization}, + {"IsTypedefed", (__CPP_FUNC)Cpp::IsTypedefed}, + {"IsClassPolymorphic", (__CPP_FUNC)Cpp::IsClassPolymorphic}, + {"Demangle", (__CPP_FUNC)Cpp::Demangle}, + {"SizeOf", (__CPP_FUNC)Cpp::SizeOf}, + {"GetSizeOfType", (__CPP_FUNC)Cpp::GetSizeOfType}, + {"IsBuiltin", (__CPP_FUNC)Cpp::IsBuiltin}, + {"IsComplete", (__CPP_FUNC)Cpp::IsComplete}, + {"Allocate", (__CPP_FUNC)Cpp::Allocate}, + {"Deallocate", (__CPP_FUNC)Cpp::Deallocate}, + {"Construct", (__CPP_FUNC)Cpp::Construct}, + {"Destruct", (__CPP_FUNC)Cpp::Destruct}, + {"MakeFunctionCallable", + (__CPP_FUNC) static_cast( + &Cpp::MakeFunctionCallable)}, + {"GetFunctionAddress", + (__CPP_FUNC) static_cast( + &Cpp::GetFunctionAddress)}, + {"IsAbstract", (__CPP_FUNC)Cpp::IsAbstract}, + {"IsEnumScope", (__CPP_FUNC)Cpp::IsEnumScope}, + {"IsEnumConstant", (__CPP_FUNC)Cpp::IsEnumConstant}, + {"IsAggregate", (__CPP_FUNC)Cpp::IsAggregate}, + {"HasDefaultConstructor", (__CPP_FUNC)Cpp::HasDefaultConstructor}, + {"IsVariable", (__CPP_FUNC)Cpp::IsVariable}, + {"GetAllCppNames", (__CPP_FUNC)Cpp::GetAllCppNames}, + {"GetUsingNamespaces", (__CPP_FUNC)Cpp::GetUsingNamespaces}, + {"GetCompleteName", (__CPP_FUNC)Cpp::GetCompleteName}, + {"GetDestructor", (__CPP_FUNC)Cpp::GetDestructor}, + {"IsVirtualMethod", (__CPP_FUNC)Cpp::IsVirtualMethod}, + {"GetNumBases", (__CPP_FUNC)Cpp::GetNumBases}, + {"GetName", (__CPP_FUNC)Cpp::GetName}, + {"GetBaseClass", (__CPP_FUNC)Cpp::GetBaseClass}, + {"IsSubclass", (__CPP_FUNC)Cpp::IsSubclass}, + {"GetOperator", (__CPP_FUNC)Cpp::GetOperator}, + {"GetFunctionReturnType", (__CPP_FUNC)Cpp::GetFunctionReturnType}, + {"GetBaseClassOffset", (__CPP_FUNC)Cpp::GetBaseClassOffset}, + {"GetClassMethods", (__CPP_FUNC)Cpp::GetClassMethods}, + {"GetFunctionsUsingName", (__CPP_FUNC)Cpp::GetFunctionsUsingName}, + {"GetFunctionNumArgs", (__CPP_FUNC)Cpp::GetFunctionNumArgs}, + {"GetFunctionRequiredArgs", (__CPP_FUNC)Cpp::GetFunctionRequiredArgs}, + {"GetFunctionArgName", (__CPP_FUNC)Cpp::GetFunctionArgName}, + {"GetFunctionArgType", (__CPP_FUNC)Cpp::GetFunctionArgType}, + {"GetFunctionArgDefault", (__CPP_FUNC)Cpp::GetFunctionArgDefault}, + {"IsConstMethod", (__CPP_FUNC)Cpp::IsConstMethod}, + {"GetFunctionTemplatedDecls", + (__CPP_FUNC)Cpp::GetFunctionTemplatedDecls}, + {"ExistsFunctionTemplate", (__CPP_FUNC)Cpp::ExistsFunctionTemplate}, + {"IsTemplatedFunction", (__CPP_FUNC)Cpp::IsTemplatedFunction}, + {"IsStaticMethod", (__CPP_FUNC)Cpp::IsStaticMethod}, + {"GetClassTemplatedMethods", (__CPP_FUNC)Cpp::GetClassTemplatedMethods}, + {"BestOverloadFunctionMatch", + (__CPP_FUNC)Cpp::BestOverloadFunctionMatch}, + {"GetOperatorFromSpelling", (__CPP_FUNC)Cpp::GetOperatorFromSpelling}, + {"IsFunctionDeleted", (__CPP_FUNC)Cpp::IsFunctionDeleted}, + {"IsPublicMethod", (__CPP_FUNC)Cpp::IsPublicMethod}, + {"IsProtectedMethod", (__CPP_FUNC)Cpp::IsProtectedMethod}, + {"IsPrivateMethod", (__CPP_FUNC)Cpp::IsPrivateMethod}, + {"IsConstructor", (__CPP_FUNC)Cpp::IsConstructor}, + {"IsDestructor", (__CPP_FUNC)Cpp::IsDestructor}, + {"GetDatamembers", (__CPP_FUNC)Cpp::GetDatamembers}, + {"GetStaticDatamembers", (__CPP_FUNC)Cpp::GetStaticDatamembers}, + {"GetEnumConstantDatamembers", + (__CPP_FUNC)Cpp::GetEnumConstantDatamembers}, + {"LookupDatamember", (__CPP_FUNC)Cpp::LookupDatamember}, + {"IsLambdaClass", (__CPP_FUNC)Cpp::IsLambdaClass}, + {"GetQualifiedName", (__CPP_FUNC)Cpp::GetQualifiedName}, + {"GetVariableOffset", (__CPP_FUNC)Cpp::GetVariableOffset}, + {"IsPublicVariable", (__CPP_FUNC)Cpp::IsPublicVariable}, + {"IsProtectedVariable", (__CPP_FUNC)Cpp::IsProtectedVariable}, + {"IsPrivateVariable", (__CPP_FUNC)Cpp::IsPrivateVariable}, + {"IsStaticVariable", (__CPP_FUNC)Cpp::IsStaticVariable}, + {"IsConstVariable", (__CPP_FUNC)Cpp::IsConstVariable}, + {"GetDimensions", (__CPP_FUNC)Cpp::GetDimensions}, + {"GetEnumConstants", (__CPP_FUNC)Cpp::GetEnumConstants}, + {"GetEnumConstantType", (__CPP_FUNC)Cpp::GetEnumConstantType}, + {"GetEnumConstantValue", (__CPP_FUNC)Cpp::GetEnumConstantValue}, + {"DumpScope", (__CPP_FUNC)Cpp::DumpScope}, + {"AddSearchPath", (__CPP_FUNC)Cpp::AddSearchPath}, + {"Evaluate", (__CPP_FUNC)Cpp::Evaluate}, + {"IsDebugOutputEnabled", (__CPP_FUNC)Cpp::IsDebugOutputEnabled}, + {"EnableDebugOutput", (__CPP_FUNC)Cpp::EnableDebugOutput}}; + +static inline __CPP_FUNC _cppinterop_get_proc_address(const char* funcName) { + auto it = INTEROP_FUNCTIONS.find(funcName); + return (it != INTEROP_FUNCTIONS.end()) ? it->second : nullptr; +} + +void (*CppGetProcAddress(const unsigned char* procName))(void) { + return _cppinterop_get_proc_address(reinterpret_cast(procName)); +} diff --git a/unittests/CppInterOp/CMakeLists.txt b/unittests/CppInterOp/CMakeLists.txt index 6e28633c1..3a14c9f41 100644 --- a/unittests/CppInterOp/CMakeLists.txt +++ b/unittests/CppInterOp/CMakeLists.txt @@ -11,6 +11,14 @@ else() set(EXTRA_PATH_TEST_BINARIES /CppInterOpTests/unittests/bin/$/) endif() +# Add the DispatchAPITest only when building shared libraries +if (BUILD_SHARED_LIBS) + set_source_files_properties(DispatchAPITest.cpp PROPERTIES COMPILE_DEFINITIONS + "CPPINTEROP_LIB_DIR=\"${CMAKE_BINARY_DIR}/lib/libclangCppInterOp${CMAKE_SHARED_LIBRARY_SUFFIX}\"" + ) + list(APPEND EXTRA_TEST_SOURCE_FILES DispatchAPITest.cpp) +endif() + add_cppinterop_unittest(CppInterOpTests EnumReflectionTest.cpp FunctionReflectionTest.cpp diff --git a/unittests/CppInterOp/DispatchAPITest.cpp b/unittests/CppInterOp/DispatchAPITest.cpp new file mode 100644 index 000000000..d8171ed74 --- /dev/null +++ b/unittests/CppInterOp/DispatchAPITest.cpp @@ -0,0 +1,57 @@ +#include "Utils.h" + +#include "CppInterOp/CppInterOpDispatch.h" + +#include "gtest/gtest.h" + +#include + +using namespace TestUtils; +using namespace llvm; +using namespace clang; + +TEST(DispatchAPITestTest, IsClassSymbolLookup) { + CppAPIType::IsClass IsClassFn = reinterpret_cast( + dlGetProcAddress("IsClass", CPPINTEROP_LIB_DIR)); + ASSERT_NE(IsClassFn, nullptr) << "failed to locate symbol: " << dlerror(); + std::vector Decls; + GetAllTopLevelDecls("namespace N {} class C{}; int I;", Decls); + EXPECT_FALSE(IsClassFn(Decls[0])); + EXPECT_TRUE(IsClassFn(Decls[1])); + EXPECT_FALSE(IsClassFn(Decls[2])); +} + +TEST(DispatchAPITestTest, Demangle) { + + std::string code = R"( + int add(int x, int y) { return x + y; } + int add(double x, double y) { return x + y; } + )"; + + std::vector Decls; + GetAllTopLevelDecls(code, Decls); + EXPECT_EQ(Decls.size(), 2); + + auto Add_int = clang::GlobalDecl(static_cast(Decls[0])); + auto Add_double = clang::GlobalDecl(static_cast(Decls[1])); + + std::string mangled_add_int; + std::string mangled_add_double; + compat::maybeMangleDeclName(Add_int, mangled_add_int); + compat::maybeMangleDeclName(Add_double, mangled_add_double); + + // CppAPIType:: gives us the specific function pointer types + CppAPIType::Demangle DemangleFn = reinterpret_cast( + dlGetProcAddress("Demangle", CPPINTEROP_LIB_DIR)); + CppAPIType::GetQualifiedCompleteName GetQualifiedCompleteNameFn = + reinterpret_cast( + dlGetProcAddress("GetQualifiedCompleteName")); + + std::string demangled_add_int = DemangleFn(mangled_add_int); + std::string demangled_add_double = DemangleFn(mangled_add_double); + + EXPECT_NE(demangled_add_int.find(GetQualifiedCompleteNameFn(Decls[0])), + std::string::npos); + EXPECT_NE(demangled_add_double.find(GetQualifiedCompleteNameFn(Decls[1])), + std::string::npos); +} From 1a589bafd198723f0b22726fc084969b330319cd Mon Sep 17 00:00:00 2001 From: Aaron Jomy Date: Mon, 15 Dec 2025 20:18:19 +0100 Subject: [PATCH 2/9] Use X macros to generate funcptrs and symbol-address dispatch table Rename CppInterOpDispatch -> CppDispatch, Address more review comments and drop `DECLARE_CPP` style macros --- include/CppInterOp/CppDispatch.h | 260 ++++++++++ include/CppInterOp/CppInterOpDispatch.h | 597 ---------------------- lib/CppInterOp/CMakeLists.txt | 2 +- lib/CppInterOp/CppDispatch.cpp | 28 + lib/CppInterOp/CppInterOpDispatch.cpp | 148 ------ unittests/CppInterOp/CMakeLists.txt | 1 + unittests/CppInterOp/DispatchAPITest.cpp | 8 +- unittests/CppInterOp/DyldDispatchTest.cpp | 55 ++ 8 files changed, 348 insertions(+), 751 deletions(-) create mode 100644 include/CppInterOp/CppDispatch.h delete mode 100644 include/CppInterOp/CppInterOpDispatch.h create mode 100644 lib/CppInterOp/CppDispatch.cpp delete mode 100644 lib/CppInterOp/CppInterOpDispatch.cpp create mode 100644 unittests/CppInterOp/DyldDispatchTest.cpp diff --git a/include/CppInterOp/CppDispatch.h b/include/CppInterOp/CppDispatch.h new file mode 100644 index 000000000..305b2469a --- /dev/null +++ b/include/CppInterOp/CppDispatch.h @@ -0,0 +1,260 @@ +//--------------------------------------------------------------------*- C++ -*- +// CppInterOp Dispatch Mechanism +// author: Aaron Jomy +//===----------------------------------------------------------------------===// +// +// Defines the mechanism which enables dispatching of the CppInterOp API +// without linking to it, preventing any LLVM or Clang symbols from being leaked +// into the client application. +// +//===----------------------------------------------------------------------===// +#ifndef CPPINTEROP_CPPINTEROPDISPATCH_H +#define CPPINTEROP_CPPINTEROPDISPATCH_H + +#include +#include +#include +#include +#include + +#include + +using __CPP_FUNC = void (*)(); + +///\param[in] procname - the name of the FunctionEntry in the symbol lookup +/// table. +/// +///\returns the function address of the requested API, or nullptr if not found +extern "C" CPPINTEROP_API void ( + *CppGetProcAddress(const unsigned char* procname))(void); + +// macro that allows declaration and loading of all CppInterOp API functions in +// a consistent way. This is used as our dispatched API list, along with the +// name-address pair table +#define CPPINTEROP_API_MAP \ + X(CreateInterpreter, decltype(&Cpp::CreateInterpreter)) \ + X(GetInterpreter, decltype(&Cpp::GetInterpreter)) \ + X(Process, decltype(&Cpp::Process)) \ + X(GetResourceDir, decltype(&Cpp::GetResourceDir)) \ + X(AddIncludePath, decltype(&Cpp::AddIncludePath)) \ + X(LoadLibrary, decltype(&Cpp::LoadLibrary)) \ + X(Declare, decltype(&Cpp::Declare)) \ + X(DeleteInterpreter, decltype(&Cpp::DeleteInterpreter)) \ + X(IsNamespace, decltype(&Cpp::IsNamespace)) \ + X(ObjToString, decltype(&Cpp::ObjToString)) \ + X(GetQualifiedCompleteName, decltype(&Cpp::GetQualifiedCompleteName)) \ + X(GetValueKind, decltype(&Cpp::GetValueKind)) \ + X(GetNonReferenceType, decltype(&Cpp::GetNonReferenceType)) \ + X(IsEnumType, decltype(&Cpp::IsEnumType)) \ + X(GetIntegerTypeFromEnumType, decltype(&Cpp::GetIntegerTypeFromEnumType)) \ + X(GetReferencedType, decltype(&Cpp::GetReferencedType)) \ + X(IsPointerType, decltype(&Cpp::IsPointerType)) \ + X(GetPointeeType, decltype(&Cpp::GetPointeeType)) \ + X(GetPointerType, decltype(&Cpp::GetPointerType)) \ + X(IsReferenceType, decltype(&Cpp::IsReferenceType)) \ + X(GetTypeAsString, decltype(&Cpp::GetTypeAsString)) \ + X(GetCanonicalType, decltype(&Cpp::GetCanonicalType)) \ + X(HasTypeQualifier, decltype(&Cpp::HasTypeQualifier)) \ + X(RemoveTypeQualifier, decltype(&Cpp::RemoveTypeQualifier)) \ + X(GetUnderlyingType, decltype(&Cpp::GetUnderlyingType)) \ + X(IsRecordType, decltype(&Cpp::IsRecordType)) \ + X(IsFunctionPointerType, decltype(&Cpp::IsFunctionPointerType)) \ + X(GetVariableType, decltype(&Cpp::GetVariableType)) \ + X(GetNamed, decltype(&Cpp::GetNamed)) \ + X(GetScopeFromType, decltype(&Cpp::GetScopeFromType)) \ + X(GetClassTemplateInstantiationArgs, \ + decltype(&Cpp::GetClassTemplateInstantiationArgs)) \ + X(IsClass, decltype(&Cpp::IsClass)) \ + X(GetType, decltype(&Cpp::GetType)) \ + X(GetTypeFromScope, decltype(&Cpp::GetTypeFromScope)) \ + X(GetComplexType, decltype(&Cpp::GetComplexType)) \ + X(GetIntegerTypeFromEnumScope, decltype(&Cpp::GetIntegerTypeFromEnumScope)) \ + X(GetUnderlyingScope, decltype(&Cpp::GetUnderlyingScope)) \ + X(GetScope, decltype(&Cpp::GetScope)) \ + X(GetGlobalScope, decltype(&Cpp::GetGlobalScope)) \ + X(GetScopeFromCompleteName, decltype(&Cpp::GetScopeFromCompleteName)) \ + X(InstantiateTemplate, decltype(&Cpp::InstantiateTemplate)) \ + X(GetParentScope, decltype(&Cpp::GetParentScope)) \ + X(IsTemplate, decltype(&Cpp::IsTemplate)) \ + X(IsTemplateSpecialization, decltype(&Cpp::IsTemplateSpecialization)) \ + X(IsTypedefed, decltype(&Cpp::IsTypedefed)) \ + X(IsClassPolymorphic, decltype(&Cpp::IsClassPolymorphic)) \ + X(Demangle, decltype(&Cpp::Demangle)) \ + X(SizeOf, decltype(&Cpp::SizeOf)) \ + X(GetSizeOfType, decltype(&Cpp::GetSizeOfType)) \ + X(IsBuiltin, decltype(&Cpp::IsBuiltin)) \ + X(IsComplete, decltype(&Cpp::IsComplete)) \ + X(Allocate, decltype(&Cpp::Allocate)) \ + X(Deallocate, decltype(&Cpp::Deallocate)) \ + X(Construct, decltype(&Cpp::Construct)) \ + X(Destruct, decltype(&Cpp::Destruct)) \ + X(IsAbstract, decltype(&Cpp::IsAbstract)) \ + X(IsEnumScope, decltype(&Cpp::IsEnumScope)) \ + X(IsEnumConstant, decltype(&Cpp::IsEnumConstant)) \ + X(IsAggregate, decltype(&Cpp::IsAggregate)) \ + X(HasDefaultConstructor, decltype(&Cpp::HasDefaultConstructor)) \ + X(IsVariable, decltype(&Cpp::IsVariable)) \ + X(GetAllCppNames, decltype(&Cpp::GetAllCppNames)) \ + X(GetUsingNamespaces, decltype(&Cpp::GetUsingNamespaces)) \ + X(GetCompleteName, decltype(&Cpp::GetCompleteName)) \ + X(GetDestructor, decltype(&Cpp::GetDestructor)) \ + X(IsVirtualMethod, decltype(&Cpp::IsVirtualMethod)) \ + X(GetNumBases, decltype(&Cpp::GetNumBases)) \ + X(GetName, decltype(&Cpp::GetName)) \ + X(GetBaseClass, decltype(&Cpp::GetBaseClass)) \ + X(IsSubclass, decltype(&Cpp::IsSubclass)) \ + X(GetOperator, decltype(&Cpp::GetOperator)) \ + X(GetFunctionReturnType, decltype(&Cpp::GetFunctionReturnType)) \ + X(GetBaseClassOffset, decltype(&Cpp::GetBaseClassOffset)) \ + X(GetClassMethods, decltype(&Cpp::GetClassMethods)) \ + X(GetFunctionsUsingName, decltype(&Cpp::GetFunctionsUsingName)) \ + X(GetFunctionNumArgs, decltype(&Cpp::GetFunctionNumArgs)) \ + X(GetFunctionRequiredArgs, decltype(&Cpp::GetFunctionRequiredArgs)) \ + X(GetFunctionArgName, decltype(&Cpp::GetFunctionArgName)) \ + X(GetFunctionArgType, decltype(&Cpp::GetFunctionArgType)) \ + X(GetFunctionArgDefault, decltype(&Cpp::GetFunctionArgDefault)) \ + X(IsConstMethod, decltype(&Cpp::IsConstMethod)) \ + X(GetFunctionTemplatedDecls, decltype(&Cpp::GetFunctionTemplatedDecls)) \ + X(ExistsFunctionTemplate, decltype(&Cpp::ExistsFunctionTemplate)) \ + X(IsTemplatedFunction, decltype(&Cpp::IsTemplatedFunction)) \ + X(IsStaticMethod, decltype(&Cpp::IsStaticMethod)) \ + X(GetClassTemplatedMethods, decltype(&Cpp::GetClassTemplatedMethods)) \ + X(BestOverloadFunctionMatch, decltype(&Cpp::BestOverloadFunctionMatch)) \ + X(GetOperatorFromSpelling, decltype(&Cpp::GetOperatorFromSpelling)) \ + X(IsFunctionDeleted, decltype(&Cpp::IsFunctionDeleted)) \ + X(IsPublicMethod, decltype(&Cpp::IsPublicMethod)) \ + X(IsProtectedMethod, decltype(&Cpp::IsProtectedMethod)) \ + X(IsPrivateMethod, decltype(&Cpp::IsPrivateMethod)) \ + X(IsConstructor, decltype(&Cpp::IsConstructor)) \ + X(IsDestructor, decltype(&Cpp::IsDestructor)) \ + X(GetDatamembers, decltype(&Cpp::GetDatamembers)) \ + X(GetStaticDatamembers, decltype(&Cpp::GetStaticDatamembers)) \ + X(GetEnumConstantDatamembers, decltype(&Cpp::GetEnumConstantDatamembers)) \ + X(LookupDatamember, decltype(&Cpp::LookupDatamember)) \ + X(IsLambdaClass, decltype(&Cpp::IsLambdaClass)) \ + X(GetQualifiedName, decltype(&Cpp::GetQualifiedName)) \ + X(GetVariableOffset, decltype(&Cpp::GetVariableOffset)) \ + X(IsPublicVariable, decltype(&Cpp::IsPublicVariable)) \ + X(IsProtectedVariable, decltype(&Cpp::IsProtectedVariable)) \ + X(IsPrivateVariable, decltype(&Cpp::IsPrivateVariable)) \ + X(IsStaticVariable, decltype(&Cpp::IsStaticVariable)) \ + X(IsConstVariable, decltype(&Cpp::IsConstVariable)) \ + X(GetDimensions, decltype(&Cpp::GetDimensions)) \ + X(GetEnumConstants, decltype(&Cpp::GetEnumConstants)) \ + X(GetEnumConstantType, decltype(&Cpp::GetEnumConstantType)) \ + X(GetEnumConstantValue, decltype(&Cpp::GetEnumConstantValue)) \ + X(DumpScope, decltype(&Cpp::DumpScope)) \ + X(AddSearchPath, decltype(&Cpp::AddSearchPath)) \ + X(Evaluate, decltype(&Cpp::Evaluate)) \ + X(IsDebugOutputEnabled, decltype(&Cpp::IsDebugOutputEnabled)) \ + X(EnableDebugOutput, decltype(&Cpp::EnableDebugOutput)) \ + X(MakeFunctionCallable, Cpp::JitCall (*)(Cpp::TCppConstFunction_t)) \ + X(GetFunctionAddress, Cpp::TCppFuncAddr_t (*)(Cpp::TCppFunction_t)) \ + /*X(API_name, fnptr_ty)*/ +namespace CppDispatch { +// forward all type aliases +using TCppIndex_t = ::Cpp::TCppIndex_t; +using TCppScope_t = ::Cpp::TCppScope_t; +using TCppConstScope_t = ::Cpp::TCppConstScope_t; +using TCppType_t = ::Cpp::TCppType_t; +using TCppFunction_t = ::Cpp::TCppFunction_t; +using TCppConstFunction_t = ::Cpp::TCppConstFunction_t; +using TCppFuncAddr_t = ::Cpp::TCppFuncAddr_t; +using TInterp_t = ::Cpp::TInterp_t; +using TCppObject_t = ::Cpp::TCppObject_t; + +using Operator = ::Cpp::Operator; +using OperatorArity = ::Cpp::OperatorArity; +using QualKind = ::Cpp::QualKind; +using TemplateArgInfo = ::Cpp::TemplateArgInfo; +using ValueKind = ::Cpp::ValueKind; + +using JitCall = ::Cpp::JitCall; +} // end namespace CppDispatch + +// TODO: implement overload that takes an existing opened DL handle +inline void* dlGetProcAddress(const char* name, + const char* customLibPath = nullptr) { + if (!name) + return nullptr; + + static std::once_flag loaded; + static void* handle = nullptr; + static void* (*getCppProcAddress)(const char*) = nullptr; + + std::call_once(loaded, [customLibPath]() { + // priority order: 1) custom path argument, or CPPINTEROP_LIBRARY_PATH via + // 2) cmake configured path 3) env vars + const char* libPath = customLibPath; + if (!libPath) { + libPath = std::getenv("CPPINTEROP_LIBRARY_PATH"); + } + + handle = dlopen(libPath, RTLD_LOCAL | RTLD_NOW); + if (!handle) { + std::cerr << "[CppInterOp] Failed to load library from " << libPath + << ": " << dlerror() << '\n'; + return; + } + + getCppProcAddress = reinterpret_cast( + dlsym(handle, "CppGetProcAddress")); + if (!getCppProcAddress) { + std::cerr << "[CppInterOp] Failed to find CppGetProcAddress: " + << dlerror() << '\n'; + dlclose(handle); + handle = nullptr; + } + }); + + return getCppProcAddress ? getCppProcAddress(name) : nullptr; +} + +// Used for the extern clauses below +// FIXME: drop the using clauses +namespace CppAPIType { +#define X(name, type) using name = type; +CPPINTEROP_API_MAP +#undef X +} // end namespace CppAPIType + +namespace CppDispatch { + +#define X(name, type) extern CppAPIType::name name; +CPPINTEROP_API_MAP +#undef X + +/// Initialize all CppInterOp API from the dynamically loaded library +/// (RTLD_LOCAL) \param[in] customLibPath Optional custom path to +/// libclangCppInterOp.so \returns true if initialization succeeded, false +/// otherwise +inline bool init_functions(const char* customLibPath = nullptr) { + // trigger library loading if custom path provided + std::cout << "[CppInterOp] Initializing CppInterOp API functions from " + << (customLibPath ? customLibPath + : "default library path") << '\n'; + if (customLibPath) { + void* test = dlGetProcAddress("GetInterpreter", customLibPath); + if (!test) { + std::cerr << "[CppInterOp] Failed to initialize with custom path: " + << customLibPath << '\n'; + return false; + } + } + +#define X(name, type) \ + name = reinterpret_cast(dlGetProcAddress(#name)); + CPPINTEROP_API_MAP +#undef X + + // test to verify that critical (and consequently all) functions loaded + if (!GetInterpreter || !CreateInterpreter) { + std::cerr << "[CppInterOp] Failed to load critical functions" << std::endl; + return false; + } + + return true; +} +} // namespace CppDispatch + +#endif // CPPINTEROP_CPPINTEROPDISPATCH_H diff --git a/include/CppInterOp/CppInterOpDispatch.h b/include/CppInterOp/CppInterOpDispatch.h deleted file mode 100644 index b7db9cd95..000000000 --- a/include/CppInterOp/CppInterOpDispatch.h +++ /dev/null @@ -1,597 +0,0 @@ -//--------------------------------------------------------------------*- C++ -*- -// CppInterOp Dispatch Mechanism -// author: Aaron Jomy -//===----------------------------------------------------------------------===// -// -// This defines the mechanism which enables dispatching of the CppInterOp API -// without linking to it, preventing any LLVM or Clang symbols from being leaked -// into the client application. -// -//===----------------------------------------------------------------------===// -#ifndef CPPINTEROP_CPPINTEROPDISPATCH_H -#define CPPINTEROP_CPPINTEROPDISPATCH_H - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -// Configured by CMake, can be overridden by defining before including this -// header -#ifndef CPPINTEROP_LIBRARY_PATH -#define CPPINTEROP_LIBRARY_PATH "@CPPINTEROP_LIBRARY_PATH@" -#endif - -using __CPP_FUNC = void (*)(); - -///\param[in] procname - the name of the FunctionEntry in the symbol lookup -/// table. -/// -///\returns the function address of the requested API, or nullptr if not found -extern "C" CPPINTEROP_API void ( - *CppGetProcAddress(const unsigned char* procname))(void); - -#define DECLARE_CPP_NULL(func_name) CppAPIType::func_name func_name = nullptr; - -#define EXTERN_CPP_FUNC(func_name) extern CppAPIType::func_name func_name; - -#define LOAD_CPP_FUNCTION(func_name) \ - func_name = \ - reinterpret_cast(dlGetProcAddress(#func_name)); - -// macro that allows declaration and loading of all CppInterOp API functions in -// a consistent way. This is used as our dispatched API list, along with the -// name-address pair table -#define FOR_EACH_CPP_FUNCTION(DO) \ - DO(CreateInterpreter) \ - DO(GetInterpreter) \ - DO(Process) \ - DO(GetResourceDir) \ - DO(AddIncludePath) \ - DO(LoadLibrary) \ - DO(Declare) \ - DO(DeleteInterpreter) \ - DO(IsNamespace) \ - DO(ObjToString) \ - DO(GetQualifiedCompleteName) \ - DO(GetValueKind) \ - DO(GetNonReferenceType) \ - DO(IsEnumType) \ - DO(GetIntegerTypeFromEnumType) \ - DO(GetReferencedType) \ - DO(IsPointerType) \ - DO(GetPointeeType) \ - DO(GetPointerType) \ - DO(IsReferenceType) \ - DO(GetTypeAsString) \ - DO(GetCanonicalType) \ - DO(HasTypeQualifier) \ - DO(RemoveTypeQualifier) \ - DO(GetUnderlyingType) \ - DO(IsRecordType) \ - DO(IsFunctionPointerType) \ - DO(GetVariableType) \ - DO(GetNamed) \ - DO(GetScopeFromType) \ - DO(GetClassTemplateInstantiationArgs) \ - DO(IsClass) \ - DO(GetType) \ - DO(GetTypeFromScope) \ - DO(GetComplexType) \ - DO(GetIntegerTypeFromEnumScope) \ - DO(GetUnderlyingScope) \ - DO(GetScope) \ - DO(GetGlobalScope) \ - DO(GetScopeFromCompleteName) \ - DO(InstantiateTemplate) \ - DO(GetParentScope) \ - DO(IsTemplate) \ - DO(IsTemplateSpecialization) \ - DO(IsTypedefed) \ - DO(IsClassPolymorphic) \ - DO(Demangle) \ - DO(SizeOf) \ - DO(GetSizeOfType) \ - DO(IsBuiltin) \ - DO(IsComplete) \ - DO(Allocate) \ - DO(Deallocate) \ - DO(Construct) \ - DO(Destruct) \ - DO(MakeFunctionCallable) \ - DO(GetFunctionAddress) \ - DO(IsAbstract) \ - DO(IsEnumScope) \ - DO(IsEnumConstant) \ - DO(IsAggregate) \ - DO(HasDefaultConstructor) \ - DO(IsVariable) \ - DO(GetAllCppNames) \ - DO(GetUsingNamespaces) \ - DO(GetCompleteName) \ - DO(GetDestructor) \ - DO(IsVirtualMethod) \ - DO(GetNumBases) \ - DO(GetName) \ - DO(GetBaseClass) \ - DO(IsSubclass) \ - DO(GetOperator) \ - DO(GetFunctionReturnType) \ - DO(GetBaseClassOffset) \ - DO(GetClassMethods) \ - DO(GetFunctionsUsingName) \ - DO(GetFunctionNumArgs) \ - DO(GetFunctionRequiredArgs) \ - DO(GetFunctionArgName) \ - DO(GetFunctionArgType) \ - DO(GetFunctionArgDefault) \ - DO(IsConstMethod) \ - DO(GetFunctionTemplatedDecls) \ - DO(ExistsFunctionTemplate) \ - DO(IsTemplatedFunction) \ - DO(IsStaticMethod) \ - DO(GetClassTemplatedMethods) \ - DO(BestOverloadFunctionMatch) \ - DO(GetOperatorFromSpelling) \ - DO(IsFunctionDeleted) \ - DO(IsPublicMethod) \ - DO(IsProtectedMethod) \ - DO(IsPrivateMethod) \ - DO(IsConstructor) \ - DO(IsDestructor) \ - DO(GetDatamembers) \ - DO(GetStaticDatamembers) \ - DO(GetEnumConstantDatamembers) \ - DO(LookupDatamember) \ - DO(IsLambdaClass) \ - DO(GetQualifiedName) \ - DO(GetVariableOffset) \ - DO(IsPublicVariable) \ - DO(IsProtectedVariable) \ - DO(IsPrivateVariable) \ - DO(IsStaticVariable) \ - DO(IsConstVariable) \ - DO(GetDimensions) \ - DO(GetEnumConstants) \ - DO(GetEnumConstantType) \ - DO(GetEnumConstantValue) \ - DO(DumpScope) \ - DO(AddSearchPath) \ - DO(Evaluate) \ - DO(IsDebugOutputEnabled) \ - DO(EnableDebugOutput) - -namespace CppDispatch { -// Forward all type aliases -using TCppIndex_t = ::Cpp::TCppIndex_t; -using TCppScope_t = ::Cpp::TCppScope_t; -using TCppConstScope_t = ::Cpp::TCppConstScope_t; -using TCppType_t = ::Cpp::TCppType_t; -using TCppFunction_t = ::Cpp::TCppFunction_t; -using TCppConstFunction_t = ::Cpp::TCppConstFunction_t; -using TCppFuncAddr_t = ::Cpp::TCppFuncAddr_t; -using TInterp_t = ::Cpp::TInterp_t; -using TCppObject_t = ::Cpp::TCppObject_t; - -using Operator = ::Cpp::Operator; -using OperatorArity = ::Cpp::OperatorArity; -using QualKind = ::Cpp::QualKind; -using TemplateArgInfo = ::Cpp::TemplateArgInfo; -using ValueKind = ::Cpp::ValueKind; - -using JitCall = ::Cpp::JitCall; -} // end namespace CppDispatch - -namespace CppAPIType { - -using GetVersion = std::string (*)(); - -using Demangle = std::string (*)(const std::string& mangled_name); - -using EnableDebugOutput = void (*)(bool value); - -using IsDebugOutputEnabled = bool (*)(); - -using IsAggregate = bool (*)(Cpp::TCppScope_t scope); - -using IsNamespace = bool (*)(Cpp::TCppScope_t scope); - -using IsClass = bool (*)(Cpp::TCppScope_t scope); - -using IsFunction = bool (*)(Cpp::TCppScope_t scope); - -using IsFunctionPointerType = bool (*)(Cpp::TCppType_t type); - -using IsClassPolymorphic = bool (*)(Cpp::TCppScope_t klass); - -using IsComplete = bool (*)(Cpp::TCppScope_t scope); - -using SizeOf = size_t (*)(Cpp::TCppScope_t scope); - -using IsBuiltin = bool (*)(Cpp::TCppType_t type); - -using IsTemplate = bool (*)(Cpp::TCppScope_t handle); - -using IsTemplateSpecialization = bool (*)(Cpp::TCppScope_t handle); - -using IsTypedefed = bool (*)(Cpp::TCppScope_t handle); - -using IsAbstract = bool (*)(Cpp::TCppType_t klass); - -using IsEnumScope = bool (*)(Cpp::TCppScope_t handle); - -using IsEnumConstant = bool (*)(Cpp::TCppScope_t handle); - -using IsEnumType = bool (*)(Cpp::TCppType_t type); - -using HasTypeQualifier = bool (*)(Cpp::TCppType_t type, Cpp::QualKind qual); - -using RemoveTypeQualifier = Cpp::TCppType_t (*)(Cpp::TCppType_t type, - Cpp::QualKind qual); - -using AddTypeQualifier = Cpp::TCppType_t (*)(Cpp::TCppType_t type, - Cpp::QualKind qual); - -using GetEnums = void (*)(Cpp::TCppScope_t scope, - std::vector& Result); - -using IsSmartPtrType = bool (*)(Cpp::TCppType_t type); - -using GetIntegerTypeFromEnumScope = - Cpp::TCppType_t (*)(Cpp::TCppScope_t handle); - -using GetIntegerTypeFromEnumType = Cpp::TCppType_t (*)(Cpp::TCppType_t handle); - -using GetEnumConstants = - std::vector (*)(Cpp::TCppScope_t scope); - -using GetEnumConstantType = Cpp::TCppType_t (*)(Cpp::TCppScope_t scope); - -using GetEnumConstantValue = Cpp::TCppIndex_t (*)(Cpp::TCppScope_t scope); - -using GetSizeOfType = size_t (*)(Cpp::TCppType_t type); - -using IsVariable = bool (*)(Cpp::TCppScope_t scope); - -using GetName = std::string (*)(Cpp::TCppScope_t klass); - -using GetCompleteName = std::string (*)(Cpp::TCppScope_t klass); - -using GetQualifiedName = std::string (*)(Cpp::TCppScope_t klass); - -using GetQualifiedCompleteName = std::string (*)(Cpp::TCppScope_t klass); - -using GetUsingNamespaces = - std::vector (*)(Cpp::TCppScope_t scope); - -using GetGlobalScope = Cpp::TCppScope_t (*)(); - -using GetUnderlyingScope = Cpp::TCppScope_t (*)(Cpp::TCppScope_t scope); - -using GetScope = Cpp::TCppScope_t (*)(const std::string& name, - Cpp::TCppScope_t parent); - -using GetScopeFromCompleteName = Cpp::TCppScope_t (*)(const std::string& name); - -using GetNamed = Cpp::TCppScope_t (*)(const std::string& name, - Cpp::TCppScope_t parent); - -using GetParentScope = Cpp::TCppScope_t (*)(Cpp::TCppScope_t scope); - -using GetScopeFromType = Cpp::TCppScope_t (*)(Cpp::TCppType_t type); - -using GetNumBases = Cpp::TCppIndex_t (*)(Cpp::TCppScope_t klass); - -using GetBaseClass = Cpp::TCppScope_t (*)(Cpp::TCppScope_t klass, - Cpp::TCppIndex_t ibase); - -using IsSubclass = bool (*)(Cpp::TCppScope_t derived, Cpp::TCppScope_t base); - -using GetBaseClassOffset = int64_t (*)(Cpp::TCppScope_t derived, - Cpp::TCppScope_t base); - -using GetClassMethods = void (*)(Cpp::TCppScope_t klass, - std::vector& methods); - -using GetFunctionTemplatedDecls = - void (*)(Cpp::TCppScope_t klass, std::vector& methods); - -using HasDefaultConstructor = bool (*)(Cpp::TCppScope_t scope); - -using GetDefaultConstructor = Cpp::TCppFunction_t (*)(Cpp::TCppScope_t scope); - -using GetDestructor = Cpp::TCppFunction_t (*)(Cpp::TCppScope_t scope); - -using GetFunctionsUsingName = std::vector (*)( - Cpp::TCppScope_t scope, const std::string& name); - -using GetFunctionReturnType = Cpp::TCppType_t (*)(Cpp::TCppFunction_t func); - -using GetFunctionNumArgs = Cpp::TCppIndex_t (*)(Cpp::TCppFunction_t func); - -using GetFunctionRequiredArgs = - Cpp::TCppIndex_t (*)(Cpp::TCppConstFunction_t func); - -using GetFunctionArgType = Cpp::TCppType_t (*)(Cpp::TCppFunction_t func, - Cpp::TCppIndex_t iarg); - -using GetFunctionSignature = std::string (*)(Cpp::TCppFunction_t func); - -using IsFunctionDeleted = bool (*)(Cpp::TCppConstFunction_t function); - -using IsTemplatedFunction = bool (*)(Cpp::TCppFunction_t func); - -using ExistsFunctionTemplate = bool (*)(const std::string& name, - Cpp::TCppScope_t parent); - -using GetClassTemplatedMethods = - bool (*)(const std::string& name, Cpp::TCppScope_t parent, - std::vector& funcs); - -using IsMethod = bool (*)(Cpp::TCppConstFunction_t method); - -using IsPublicMethod = bool (*)(Cpp::TCppFunction_t method); - -using IsProtectedMethod = bool (*)(Cpp::TCppFunction_t method); - -using IsPrivateMethod = bool (*)(Cpp::TCppFunction_t method); - -using IsConstructor = bool (*)(Cpp::TCppConstFunction_t method); - -using IsDestructor = bool (*)(Cpp::TCppConstFunction_t method); - -using IsStaticMethod = bool (*)(Cpp::TCppConstFunction_t method); - -using GetFunctionAddressFromName = - Cpp::TCppFuncAddr_t (*)(const char* mangled_name); - -using GetFunctionAddressFromMethod = - Cpp::TCppFuncAddr_t (*)(Cpp::TCppFunction_t method); - -using IsVirtualMethod = bool (*)(Cpp::TCppFunction_t method); - -using GetDatamembers = void (*)(Cpp::TCppScope_t scope, - std::vector& datamembers); - -using GetStaticDatamembers = void (*)( - Cpp::TCppScope_t scope, std::vector& datamembers); - -using GetEnumConstantDatamembers = - void (*)(Cpp::TCppScope_t scope, std::vector& datamembers, - bool include_enum_class); - -using LookupDatamember = Cpp::TCppScope_t (*)(const std::string& name, - Cpp::TCppScope_t parent); - -using IsLambdaClass = bool (*)(Cpp::TCppType_t type); - -using GetVariableType = Cpp::TCppType_t (*)(Cpp::TCppScope_t var); - -using GetVariableOffset = intptr_t (*)(Cpp::TCppScope_t var, - Cpp::TCppScope_t parent); - -using IsPublicVariable = bool (*)(Cpp::TCppScope_t var); - -using IsProtectedVariable = bool (*)(Cpp::TCppScope_t var); - -using IsPrivateVariable = bool (*)(Cpp::TCppScope_t var); - -using IsStaticVariable = bool (*)(Cpp::TCppScope_t var); - -using IsConstVariable = bool (*)(Cpp::TCppScope_t var); - -using IsRecordType = bool (*)(Cpp::TCppType_t type); - -using IsPODType = bool (*)(Cpp::TCppType_t type); - -using IsPointerType = bool (*)(Cpp::TCppType_t type); - -using GetPointeeType = Cpp::TCppType_t (*)(Cpp::TCppType_t type); - -using IsReferenceType = bool (*)(Cpp::TCppType_t type); - -using GetValueKind = Cpp::ValueKind (*)(Cpp::TCppType_t type); - -using IsRValueReferenceType = bool (*)(Cpp::TCppType_t type); - -using GetPointerType = Cpp::TCppType_t (*)(Cpp::TCppType_t type); - -using GetReferencedType = Cpp::TCppType_t (*)(Cpp::TCppType_t type, - bool rvalue); - -using GetNonReferenceType = Cpp::TCppType_t (*)(Cpp::TCppType_t type); - -using GetTypeAsString = std::string (*)(Cpp::TCppType_t type); - -using GetCanonicalType = Cpp::TCppType_t (*)(Cpp::TCppType_t type); - -using JitCallMakeFunctionCallable = - Cpp::JitCall (*)(Cpp::TCppConstFunction_t func); - -using IsConstMethod = bool (*)(Cpp::TCppFunction_t method); - -using GetFunctionArgDefault = std::string (*)(Cpp::TCppFunction_t func, - Cpp::TCppIndex_t param_index); - -using GetFunctionArgName = std::string (*)(Cpp::TCppFunction_t func, - Cpp::TCppIndex_t param_index); - -using GetSpellingFromOperator = std::string (*)(Cpp::Operator op); - -using GetOperatorFromSpelling = Cpp::Operator (*)(const std::string& op); - -using GetOperatorArity = Cpp::OperatorArity (*)(Cpp::TCppFunction_t op); - -using GetOperator = void (*)(Cpp::TCppScope_t scope, Cpp::Operator op, - std::vector& operators, - Cpp::OperatorArity kind); - -using CreateInterpreter = - Cpp::TInterp_t (*)(const std::vector& Args, - const std::vector& GpuArgs); - -using DeleteInterpreter = bool (*)(Cpp::TInterp_t interp); - -using ActivateInterpreter = bool (*)(Cpp::TInterp_t interp); - -using GetInterpreter = Cpp::TInterp_t (*)(); - -using UseExternalInterpreter = void (*)(Cpp::TInterp_t interp); - -using AddSearchPath = void (*)(const char* dir, bool isUser, bool prepend); - -using GetResourceDir = const char* (*)(); - -using DetectResourceDir = std::string (*)(const char* ClangBinaryName); - -using DetectSystemCompilerIncludePaths = - void (*)(std::vector& Paths, const char* CompilerName); - -using AddIncludePath = void (*)(const char* dir); - -using GetIncludePaths = void (*)(std::vector& IncludePaths, - bool withSystem, bool withFlags); - -using Declare = int (*)(const char* code, bool silent); - -using Process = int (*)(const char* code); - -using Evaluate = intptr_t (*)(const char* code, bool* HadError); - -using LookupLibrary = std::string (*)(const char* lib_name); - -using LoadLibrary = bool (*)(const char* lib_stem, bool lookup); - -using UnloadLibrary = void (*)(const char* lib_stem); - -using SearchLibrariesForSymbol = std::string (*)(const char* mangled_name, - bool search_system); - -using InsertOrReplaceJitSymbol = bool (*)(const char* linker_mangled_name, - uint64_t address); - -using ObjToString = std::string (*)(const char* type, void* obj); - -using GetUnderlyingType = Cpp::TCppType_t (*)(Cpp::TCppType_t type); - -using BestOverloadFunctionMatch = Cpp::TCppFunction_t (*)( - const std::vector& candidates, - const std::vector& explicit_types, - const std::vector& arg_types); - -using GetDimensions = std::vector (*)(Cpp::TCppType_t var); - -using DumpScope = void (*)(Cpp::TCppScope_t scope); - -using GetClassTemplateInstantiationArgs = - void (*)(Cpp::TCppScope_t klass, std::vector& args); - -using GetAllCppNames = void (*)(Cpp::TCppScope_t scope, - std::set& names); - -using Deallocate = void (*)(Cpp::TCppScope_t scope, Cpp::TCppObject_t address, - Cpp::TCppIndex_t count); - -using Allocate = Cpp::TCppObject_t (*)(Cpp::TCppScope_t scope, - Cpp::TCppIndex_t count); - -using InstantiateTemplate = Cpp::TCppScope_t (*)( - Cpp::TCppScope_t tmpl, const Cpp::TemplateArgInfo* template_args, - size_t template_args_size, bool instantiate_body); - -using GetComplexType = Cpp::TCppType_t (*)(Cpp::TCppType_t type); - -using GetTypeFromScope = Cpp::TCppType_t (*)(Cpp::TCppScope_t klass); - -using GetType = Cpp::TCppType_t (*)(const std::string& type); - -using Construct = Cpp::TCppObject_t (*)(Cpp::TCppScope_t scope, - Cpp::TCppObject_t arena, - Cpp::TCppIndex_t count); - -using Destruct = bool (*)(Cpp::TCppObject_t This, Cpp::TCppScope_t scope, - bool withFree, Cpp::TCppIndex_t count); - -using MakeFunctionCallable = Cpp::JitCall (*)(Cpp::TCppConstFunction_t func); -using GetFunctionAddress = - Cpp::TCppFuncAddr_t (*)(Cpp::TCppConstFunction_t func); -} // end namespace CppAPIType - -// TODO: implement overload that takes an existing opened DL handle -inline void* dlGetProcAddress(const char* name, - const char* customLibPath = nullptr) { - if (!name) - return nullptr; - - static std::once_flag loaded; - static void* handle = nullptr; - static void* (*getCppProcAddress)(const char*) = nullptr; - - std::call_once(loaded, [customLibPath]() { - // priority order: 1) custom path argument, or CPPINTEROP_LIBRARY_PATH via - // 2) cmake configured path 3) env vars - const char* libPath = customLibPath; - if (!libPath) { - libPath = std::getenv("CPPINTEROP_LIBRARY_PATH"); - } - if (!libPath || libPath[0] == '\0') { - libPath = CPPINTEROP_LIBRARY_PATH; - } - - handle = dlopen(libPath, RTLD_LOCAL | RTLD_NOW); - if (!handle) { - std::cerr << "[CppInterOp] Failed to load library from " << libPath - << ": " << dlerror() << '\n'; - return; - } - - getCppProcAddress = reinterpret_cast( - dlsym(handle, "CppGetProcAddress")); - if (!getCppProcAddress) { - std::cerr << "[CppInterOp] Failed to find CppGetProcAddress: " - << dlerror() << '\n'; - dlclose(handle); - handle = nullptr; - } - }); - - return getCppProcAddress ? getCppProcAddress(name) : nullptr; -} -namespace CppDispatch { -FOR_EACH_CPP_FUNCTION(EXTERN_CPP_FUNC); -/// Initialize all CppInterOp API from the dynamically loaded library -/// (RTLD_LOCAL) \param[in] customLibPath Optional custom path to -/// libclangCppInterOp.so \returns true if initialization succeeded, false -/// otherwise -inline bool init_functions(const char* customLibPath = nullptr) { - // trigger library loading if custom path provided - if (customLibPath) { - void* test = dlGetProcAddress("GetInterpreter", customLibPath); - if (!test) { - std::cerr << "[CppInterOp] Failed to initialize with custom path: " - << customLibPath << '\n'; - return false; - } - } - - FOR_EACH_CPP_FUNCTION(LOAD_CPP_FUNCTION); - - // test to verify that critical (and consequently all) functions loaded - if (!GetInterpreter || !CreateInterpreter) { - std::cerr << "[CppInterOp] Failed to load critical functions" << std::endl; - return false; - } - - return true; -} -} // namespace CppDispatch - -#endif // CPPINTEROP_CPPINTEROPDISPATCH_H diff --git a/lib/CppInterOp/CMakeLists.txt b/lib/CppInterOp/CMakeLists.txt index 2b353d81b..bbd27d7d5 100644 --- a/lib/CppInterOp/CMakeLists.txt +++ b/lib/CppInterOp/CMakeLists.txt @@ -107,7 +107,7 @@ endif(LLVM_LINK_LLVM_DYLIB) add_llvm_library(clangCppInterOp DISABLE_LLVM_LINK_LLVM_DYLIB CppInterOp.cpp - CppInterOpDispatch.cpp + CppDispatch.cpp CXCppInterOp.cpp ${DLM} LINK_LIBS diff --git a/lib/CppInterOp/CppDispatch.cpp b/lib/CppInterOp/CppDispatch.cpp new file mode 100644 index 000000000..20ed856e8 --- /dev/null +++ b/lib/CppInterOp/CppDispatch.cpp @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// CppInterOp Dispatch Implementation +// author: Aaron Jomy +//------------------------------------------------------------------------------ + +#include + +#include + +static const std::unordered_map + INTEROP_FUNCTIONS = { +#define X(name, type) {#name, (__CPP_FUNC) static_cast(&Cpp::name)}, + CPPINTEROP_API_MAP +#undef X +}; + +#undef MAP_ENTRY_SIMPLE +#undef MAP_ENTRY_OVERLOADED + +static inline __CPP_FUNC _cppinterop_get_proc_address(const char* funcName) { + auto it = INTEROP_FUNCTIONS.find(funcName); + return (it != INTEROP_FUNCTIONS.end()) ? it->second : nullptr; +} + +void (*CppGetProcAddress(const unsigned char* procName))(void) { + return _cppinterop_get_proc_address(reinterpret_cast(procName)); +} + diff --git a/lib/CppInterOp/CppInterOpDispatch.cpp b/lib/CppInterOp/CppInterOpDispatch.cpp deleted file mode 100644 index fc5bb2d9a..000000000 --- a/lib/CppInterOp/CppInterOpDispatch.cpp +++ /dev/null @@ -1,148 +0,0 @@ -//------------------------------------------------------------------------------ -// CppInterOp Dispatch Implementation -// author: Aaron Jomy -//------------------------------------------------------------------------------ - -#include -#include - -#include - -static const std::unordered_map - INTEROP_FUNCTIONS = { - {"GetInterpreter", (__CPP_FUNC)Cpp::GetInterpreter}, - {"CreateInterpreter", (__CPP_FUNC)Cpp::CreateInterpreter}, - {"Process", (__CPP_FUNC)Cpp::Process}, - {"GetResourceDir", (__CPP_FUNC)Cpp::GetResourceDir}, - {"AddIncludePath", (__CPP_FUNC)Cpp::AddIncludePath}, - {"LoadLibrary", (__CPP_FUNC)Cpp::LoadLibrary}, - {"Declare", (__CPP_FUNC)Cpp::Declare}, - {"DeleteInterpreter", (__CPP_FUNC)Cpp::DeleteInterpreter}, - {"IsNamespace", (__CPP_FUNC)Cpp::IsNamespace}, - {"ObjToString", (__CPP_FUNC)Cpp::ObjToString}, - {"GetQualifiedCompleteName", (__CPP_FUNC)Cpp::GetQualifiedCompleteName}, - {"GetValueKind", (__CPP_FUNC)Cpp::GetValueKind}, - {"GetNonReferenceType", (__CPP_FUNC)Cpp::GetNonReferenceType}, - {"IsEnumType", (__CPP_FUNC)Cpp::IsEnumType}, - {"GetIntegerTypeFromEnumType", - (__CPP_FUNC)Cpp::GetIntegerTypeFromEnumType}, - {"GetReferencedType", (__CPP_FUNC)Cpp::GetReferencedType}, - {"IsPointerType", (__CPP_FUNC)Cpp::IsPointerType}, - {"GetPointeeType", (__CPP_FUNC)Cpp::GetPointeeType}, - {"GetPointerType", (__CPP_FUNC)Cpp::GetPointerType}, - {"IsReferenceType", (__CPP_FUNC)Cpp::IsReferenceType}, - {"GetTypeAsString", (__CPP_FUNC)Cpp::GetTypeAsString}, - {"GetCanonicalType", (__CPP_FUNC)Cpp::GetCanonicalType}, - {"HasTypeQualifier", (__CPP_FUNC)Cpp::HasTypeQualifier}, - {"RemoveTypeQualifier", (__CPP_FUNC)Cpp::RemoveTypeQualifier}, - {"GetUnderlyingType", (__CPP_FUNC)Cpp::GetUnderlyingType}, - {"IsRecordType", (__CPP_FUNC)Cpp::IsRecordType}, - {"IsFunctionPointerType", (__CPP_FUNC)Cpp::IsFunctionPointerType}, - {"GetVariableType", (__CPP_FUNC)Cpp::GetVariableType}, - {"GetNamed", (__CPP_FUNC)Cpp::GetNamed}, - {"GetScopeFromType", (__CPP_FUNC)Cpp::GetScopeFromType}, - {"GetClassTemplateInstantiationArgs", - (__CPP_FUNC)Cpp::GetClassTemplateInstantiationArgs}, - {"IsClass", (__CPP_FUNC)Cpp::IsClass}, - {"GetType", (__CPP_FUNC)Cpp::GetType}, - {"GetTypeFromScope", (__CPP_FUNC)Cpp::GetTypeFromScope}, - {"GetComplexType", (__CPP_FUNC)Cpp::GetComplexType}, - {"GetIntegerTypeFromEnumScope", - (__CPP_FUNC)Cpp::GetIntegerTypeFromEnumScope}, - {"GetUnderlyingScope", (__CPP_FUNC)Cpp::GetUnderlyingScope}, - {"GetScope", (__CPP_FUNC)Cpp::GetScope}, - {"GetGlobalScope", (__CPP_FUNC)Cpp::GetGlobalScope}, - {"GetScopeFromCompleteName", (__CPP_FUNC)Cpp::GetScopeFromCompleteName}, - {"InstantiateTemplate", (__CPP_FUNC)Cpp::InstantiateTemplate}, - {"GetParentScope", (__CPP_FUNC)Cpp::GetParentScope}, - {"IsTemplate", (__CPP_FUNC)Cpp::IsTemplate}, - {"IsTemplateSpecialization", (__CPP_FUNC)Cpp::IsTemplateSpecialization}, - {"IsTypedefed", (__CPP_FUNC)Cpp::IsTypedefed}, - {"IsClassPolymorphic", (__CPP_FUNC)Cpp::IsClassPolymorphic}, - {"Demangle", (__CPP_FUNC)Cpp::Demangle}, - {"SizeOf", (__CPP_FUNC)Cpp::SizeOf}, - {"GetSizeOfType", (__CPP_FUNC)Cpp::GetSizeOfType}, - {"IsBuiltin", (__CPP_FUNC)Cpp::IsBuiltin}, - {"IsComplete", (__CPP_FUNC)Cpp::IsComplete}, - {"Allocate", (__CPP_FUNC)Cpp::Allocate}, - {"Deallocate", (__CPP_FUNC)Cpp::Deallocate}, - {"Construct", (__CPP_FUNC)Cpp::Construct}, - {"Destruct", (__CPP_FUNC)Cpp::Destruct}, - {"MakeFunctionCallable", - (__CPP_FUNC) static_cast( - &Cpp::MakeFunctionCallable)}, - {"GetFunctionAddress", - (__CPP_FUNC) static_cast( - &Cpp::GetFunctionAddress)}, - {"IsAbstract", (__CPP_FUNC)Cpp::IsAbstract}, - {"IsEnumScope", (__CPP_FUNC)Cpp::IsEnumScope}, - {"IsEnumConstant", (__CPP_FUNC)Cpp::IsEnumConstant}, - {"IsAggregate", (__CPP_FUNC)Cpp::IsAggregate}, - {"HasDefaultConstructor", (__CPP_FUNC)Cpp::HasDefaultConstructor}, - {"IsVariable", (__CPP_FUNC)Cpp::IsVariable}, - {"GetAllCppNames", (__CPP_FUNC)Cpp::GetAllCppNames}, - {"GetUsingNamespaces", (__CPP_FUNC)Cpp::GetUsingNamespaces}, - {"GetCompleteName", (__CPP_FUNC)Cpp::GetCompleteName}, - {"GetDestructor", (__CPP_FUNC)Cpp::GetDestructor}, - {"IsVirtualMethod", (__CPP_FUNC)Cpp::IsVirtualMethod}, - {"GetNumBases", (__CPP_FUNC)Cpp::GetNumBases}, - {"GetName", (__CPP_FUNC)Cpp::GetName}, - {"GetBaseClass", (__CPP_FUNC)Cpp::GetBaseClass}, - {"IsSubclass", (__CPP_FUNC)Cpp::IsSubclass}, - {"GetOperator", (__CPP_FUNC)Cpp::GetOperator}, - {"GetFunctionReturnType", (__CPP_FUNC)Cpp::GetFunctionReturnType}, - {"GetBaseClassOffset", (__CPP_FUNC)Cpp::GetBaseClassOffset}, - {"GetClassMethods", (__CPP_FUNC)Cpp::GetClassMethods}, - {"GetFunctionsUsingName", (__CPP_FUNC)Cpp::GetFunctionsUsingName}, - {"GetFunctionNumArgs", (__CPP_FUNC)Cpp::GetFunctionNumArgs}, - {"GetFunctionRequiredArgs", (__CPP_FUNC)Cpp::GetFunctionRequiredArgs}, - {"GetFunctionArgName", (__CPP_FUNC)Cpp::GetFunctionArgName}, - {"GetFunctionArgType", (__CPP_FUNC)Cpp::GetFunctionArgType}, - {"GetFunctionArgDefault", (__CPP_FUNC)Cpp::GetFunctionArgDefault}, - {"IsConstMethod", (__CPP_FUNC)Cpp::IsConstMethod}, - {"GetFunctionTemplatedDecls", - (__CPP_FUNC)Cpp::GetFunctionTemplatedDecls}, - {"ExistsFunctionTemplate", (__CPP_FUNC)Cpp::ExistsFunctionTemplate}, - {"IsTemplatedFunction", (__CPP_FUNC)Cpp::IsTemplatedFunction}, - {"IsStaticMethod", (__CPP_FUNC)Cpp::IsStaticMethod}, - {"GetClassTemplatedMethods", (__CPP_FUNC)Cpp::GetClassTemplatedMethods}, - {"BestOverloadFunctionMatch", - (__CPP_FUNC)Cpp::BestOverloadFunctionMatch}, - {"GetOperatorFromSpelling", (__CPP_FUNC)Cpp::GetOperatorFromSpelling}, - {"IsFunctionDeleted", (__CPP_FUNC)Cpp::IsFunctionDeleted}, - {"IsPublicMethod", (__CPP_FUNC)Cpp::IsPublicMethod}, - {"IsProtectedMethod", (__CPP_FUNC)Cpp::IsProtectedMethod}, - {"IsPrivateMethod", (__CPP_FUNC)Cpp::IsPrivateMethod}, - {"IsConstructor", (__CPP_FUNC)Cpp::IsConstructor}, - {"IsDestructor", (__CPP_FUNC)Cpp::IsDestructor}, - {"GetDatamembers", (__CPP_FUNC)Cpp::GetDatamembers}, - {"GetStaticDatamembers", (__CPP_FUNC)Cpp::GetStaticDatamembers}, - {"GetEnumConstantDatamembers", - (__CPP_FUNC)Cpp::GetEnumConstantDatamembers}, - {"LookupDatamember", (__CPP_FUNC)Cpp::LookupDatamember}, - {"IsLambdaClass", (__CPP_FUNC)Cpp::IsLambdaClass}, - {"GetQualifiedName", (__CPP_FUNC)Cpp::GetQualifiedName}, - {"GetVariableOffset", (__CPP_FUNC)Cpp::GetVariableOffset}, - {"IsPublicVariable", (__CPP_FUNC)Cpp::IsPublicVariable}, - {"IsProtectedVariable", (__CPP_FUNC)Cpp::IsProtectedVariable}, - {"IsPrivateVariable", (__CPP_FUNC)Cpp::IsPrivateVariable}, - {"IsStaticVariable", (__CPP_FUNC)Cpp::IsStaticVariable}, - {"IsConstVariable", (__CPP_FUNC)Cpp::IsConstVariable}, - {"GetDimensions", (__CPP_FUNC)Cpp::GetDimensions}, - {"GetEnumConstants", (__CPP_FUNC)Cpp::GetEnumConstants}, - {"GetEnumConstantType", (__CPP_FUNC)Cpp::GetEnumConstantType}, - {"GetEnumConstantValue", (__CPP_FUNC)Cpp::GetEnumConstantValue}, - {"DumpScope", (__CPP_FUNC)Cpp::DumpScope}, - {"AddSearchPath", (__CPP_FUNC)Cpp::AddSearchPath}, - {"Evaluate", (__CPP_FUNC)Cpp::Evaluate}, - {"IsDebugOutputEnabled", (__CPP_FUNC)Cpp::IsDebugOutputEnabled}, - {"EnableDebugOutput", (__CPP_FUNC)Cpp::EnableDebugOutput}}; - -static inline __CPP_FUNC _cppinterop_get_proc_address(const char* funcName) { - auto it = INTEROP_FUNCTIONS.find(funcName); - return (it != INTEROP_FUNCTIONS.end()) ? it->second : nullptr; -} - -void (*CppGetProcAddress(const unsigned char* procName))(void) { - return _cppinterop_get_proc_address(reinterpret_cast(procName)); -} diff --git a/unittests/CppInterOp/CMakeLists.txt b/unittests/CppInterOp/CMakeLists.txt index 3a14c9f41..24b68b071 100644 --- a/unittests/CppInterOp/CMakeLists.txt +++ b/unittests/CppInterOp/CMakeLists.txt @@ -28,6 +28,7 @@ add_cppinterop_unittest(CppInterOpTests TypeReflectionTest.cpp Utils.cpp VariableReflectionTest.cpp + DispatchAPITest.cpp ${EXTRA_TEST_SOURCE_FILES} ) diff --git a/unittests/CppInterOp/DispatchAPITest.cpp b/unittests/CppInterOp/DispatchAPITest.cpp index d8171ed74..fbd8a8554 100644 --- a/unittests/CppInterOp/DispatchAPITest.cpp +++ b/unittests/CppInterOp/DispatchAPITest.cpp @@ -1,16 +1,14 @@ #include "Utils.h" -#include "CppInterOp/CppInterOpDispatch.h" +#include "CppInterOp/CppDispatch.h" #include "gtest/gtest.h" -#include - using namespace TestUtils; using namespace llvm; using namespace clang; -TEST(DispatchAPITestTest, IsClassSymbolLookup) { +TEST(DispatchAPITestTest, Basic_IsClassSymbolLookup) { CppAPIType::IsClass IsClassFn = reinterpret_cast( dlGetProcAddress("IsClass", CPPINTEROP_LIB_DIR)); ASSERT_NE(IsClassFn, nullptr) << "failed to locate symbol: " << dlerror(); @@ -21,7 +19,7 @@ TEST(DispatchAPITestTest, IsClassSymbolLookup) { EXPECT_FALSE(IsClassFn(Decls[2])); } -TEST(DispatchAPITestTest, Demangle) { +TEST(DispatchAPITestTest, Basic_Demangle) { std::string code = R"( int add(int x, int y) { return x + y; } diff --git a/unittests/CppInterOp/DyldDispatchTest.cpp b/unittests/CppInterOp/DyldDispatchTest.cpp new file mode 100644 index 000000000..58c3cf56a --- /dev/null +++ b/unittests/CppInterOp/DyldDispatchTest.cpp @@ -0,0 +1,55 @@ +#include "Utils.h" + +#include "CppInterOp/CppInterOpDispatch.h" + +#include "gtest/gtest.h" + +using namespace TestUtils; +using namespace llvm; +using namespace clang; + +TEST(DispatchAPITestTest, Basic_IsClassSymbolLookup) { + CppAPIType::IsClass IsClassFn = reinterpret_cast( + dlGetProcAddress("IsClass", CPPINTEROP_LIB_DIR)); + ASSERT_NE(IsClassFn, nullptr) << "failed to locate symbol: " << dlerror(); + std::vector Decls; + GetAllTopLevelDecls("namespace N {} class C{}; int I;", Decls); + EXPECT_FALSE(IsClassFn(Decls[0])); + EXPECT_TRUE(IsClassFn(Decls[1])); + EXPECT_FALSE(IsClassFn(Decls[2])); +} + +TEST(DispatchAPITestTest, Basic_Demangle) { + + std::string code = R"( + int add(int x, int y) { return x + y; } + int add(double x, double y) { return x + y; } + )"; + + std::vector Decls; + GetAllTopLevelDecls(code, Decls); + EXPECT_EQ(Decls.size(), 2); + + auto Add_int = clang::GlobalDecl(static_cast(Decls[0])); + auto Add_double = clang::GlobalDecl(static_cast(Decls[1])); + + std::string mangled_add_int; + std::string mangled_add_double; + compat::maybeMangleDeclName(Add_int, mangled_add_int); + compat::maybeMangleDeclName(Add_double, mangled_add_double); + + // CppAPIType:: gives us the specific function pointer types + CppAPIType::Demangle DemangleFn = reinterpret_cast( + dlGetProcAddress("Demangle", CPPINTEROP_LIB_DIR)); + CppAPIType::GetQualifiedCompleteName GetQualifiedCompleteNameFn = + reinterpret_cast( + dlGetProcAddress("GetQualifiedCompleteName")); + + std::string demangled_add_int = DemangleFn(mangled_add_int); + std::string demangled_add_double = DemangleFn(mangled_add_double); + + EXPECT_NE(demangled_add_int.find(GetQualifiedCompleteNameFn(Decls[0])), + std::string::npos); + EXPECT_NE(demangled_add_double.find(GetQualifiedCompleteNameFn(Decls[1])), + std::string::npos); +} From 265d4697c025ff1133e2c2cf5db37a21df012478 Mon Sep 17 00:00:00 2001 From: Aaron Jomy Date: Tue, 6 Jan 2026 19:49:23 +0100 Subject: [PATCH 3/9] Ensure `Cpp` namespace is consistent between CppInterOp.h and CppDispatch.h With the introduction of the CppStatic namespace we conditionally alias `Cpp` to the implementation provided by CppInterOp.h (link to clangCppInterOp.so) or CppDispatch (dlopen the dylib with RTLD_LOCAL) This is an intentional ODR violation but remains consistent with our API model. --- include/CppInterOp/CppDispatch.h | 272 ++++++++++++----------- include/CppInterOp/CppInterOp.h | 7 +- lib/CppInterOp/CXCppInterOp.cpp | 20 +- lib/CppInterOp/CppDispatch.cpp | 2 +- lib/CppInterOp/CppInterOp.cpp | 8 +- unittests/CppInterOp/DispatchAPITest.cpp | 4 +- 6 files changed, 162 insertions(+), 151 deletions(-) diff --git a/include/CppInterOp/CppDispatch.h b/include/CppInterOp/CppDispatch.h index 305b2469a..fbd7a29de 100644 --- a/include/CppInterOp/CppDispatch.h +++ b/include/CppInterOp/CppDispatch.h @@ -32,144 +32,151 @@ extern "C" CPPINTEROP_API void ( // a consistent way. This is used as our dispatched API list, along with the // name-address pair table #define CPPINTEROP_API_MAP \ - X(CreateInterpreter, decltype(&Cpp::CreateInterpreter)) \ - X(GetInterpreter, decltype(&Cpp::GetInterpreter)) \ - X(Process, decltype(&Cpp::Process)) \ - X(GetResourceDir, decltype(&Cpp::GetResourceDir)) \ - X(AddIncludePath, decltype(&Cpp::AddIncludePath)) \ - X(LoadLibrary, decltype(&Cpp::LoadLibrary)) \ - X(Declare, decltype(&Cpp::Declare)) \ - X(DeleteInterpreter, decltype(&Cpp::DeleteInterpreter)) \ - X(IsNamespace, decltype(&Cpp::IsNamespace)) \ - X(ObjToString, decltype(&Cpp::ObjToString)) \ - X(GetQualifiedCompleteName, decltype(&Cpp::GetQualifiedCompleteName)) \ - X(GetValueKind, decltype(&Cpp::GetValueKind)) \ - X(GetNonReferenceType, decltype(&Cpp::GetNonReferenceType)) \ - X(IsEnumType, decltype(&Cpp::IsEnumType)) \ - X(GetIntegerTypeFromEnumType, decltype(&Cpp::GetIntegerTypeFromEnumType)) \ - X(GetReferencedType, decltype(&Cpp::GetReferencedType)) \ - X(IsPointerType, decltype(&Cpp::IsPointerType)) \ - X(GetPointeeType, decltype(&Cpp::GetPointeeType)) \ - X(GetPointerType, decltype(&Cpp::GetPointerType)) \ - X(IsReferenceType, decltype(&Cpp::IsReferenceType)) \ - X(GetTypeAsString, decltype(&Cpp::GetTypeAsString)) \ - X(GetCanonicalType, decltype(&Cpp::GetCanonicalType)) \ - X(HasTypeQualifier, decltype(&Cpp::HasTypeQualifier)) \ - X(RemoveTypeQualifier, decltype(&Cpp::RemoveTypeQualifier)) \ - X(GetUnderlyingType, decltype(&Cpp::GetUnderlyingType)) \ - X(IsRecordType, decltype(&Cpp::IsRecordType)) \ - X(IsFunctionPointerType, decltype(&Cpp::IsFunctionPointerType)) \ - X(GetVariableType, decltype(&Cpp::GetVariableType)) \ - X(GetNamed, decltype(&Cpp::GetNamed)) \ - X(GetScopeFromType, decltype(&Cpp::GetScopeFromType)) \ + X(CreateInterpreter, decltype(&CppStatic::CreateInterpreter)) \ + X(GetInterpreter, decltype(&CppStatic::GetInterpreter)) \ + X(Process, decltype(&CppStatic::Process)) \ + X(GetResourceDir, decltype(&CppStatic::GetResourceDir)) \ + X(AddIncludePath, decltype(&CppStatic::AddIncludePath)) \ + X(LoadLibrary, decltype(&CppStatic::LoadLibrary)) \ + X(Declare, decltype(&CppStatic::Declare)) \ + X(DeleteInterpreter, decltype(&CppStatic::DeleteInterpreter)) \ + X(IsNamespace, decltype(&CppStatic::IsNamespace)) \ + X(ObjToString, decltype(&CppStatic::ObjToString)) \ + X(GetQualifiedCompleteName, decltype(&CppStatic::GetQualifiedCompleteName)) \ + X(GetValueKind, decltype(&CppStatic::GetValueKind)) \ + X(GetNonReferenceType, decltype(&CppStatic::GetNonReferenceType)) \ + X(IsEnumType, decltype(&CppStatic::IsEnumType)) \ + X(GetIntegerTypeFromEnumType, \ + decltype(&CppStatic::GetIntegerTypeFromEnumType)) \ + X(GetReferencedType, decltype(&CppStatic::GetReferencedType)) \ + X(IsPointerType, decltype(&CppStatic::IsPointerType)) \ + X(GetPointeeType, decltype(&CppStatic::GetPointeeType)) \ + X(GetPointerType, decltype(&CppStatic::GetPointerType)) \ + X(IsReferenceType, decltype(&CppStatic::IsReferenceType)) \ + X(GetTypeAsString, decltype(&CppStatic::GetTypeAsString)) \ + X(GetCanonicalType, decltype(&CppStatic::GetCanonicalType)) \ + X(HasTypeQualifier, decltype(&CppStatic::HasTypeQualifier)) \ + X(RemoveTypeQualifier, decltype(&CppStatic::RemoveTypeQualifier)) \ + X(GetUnderlyingType, decltype(&CppStatic::GetUnderlyingType)) \ + X(IsRecordType, decltype(&CppStatic::IsRecordType)) \ + X(IsFunctionPointerType, decltype(&CppStatic::IsFunctionPointerType)) \ + X(GetVariableType, decltype(&CppStatic::GetVariableType)) \ + X(GetNamed, decltype(&CppStatic::GetNamed)) \ + X(GetScopeFromType, decltype(&CppStatic::GetScopeFromType)) \ X(GetClassTemplateInstantiationArgs, \ - decltype(&Cpp::GetClassTemplateInstantiationArgs)) \ - X(IsClass, decltype(&Cpp::IsClass)) \ - X(GetType, decltype(&Cpp::GetType)) \ - X(GetTypeFromScope, decltype(&Cpp::GetTypeFromScope)) \ - X(GetComplexType, decltype(&Cpp::GetComplexType)) \ - X(GetIntegerTypeFromEnumScope, decltype(&Cpp::GetIntegerTypeFromEnumScope)) \ - X(GetUnderlyingScope, decltype(&Cpp::GetUnderlyingScope)) \ - X(GetScope, decltype(&Cpp::GetScope)) \ - X(GetGlobalScope, decltype(&Cpp::GetGlobalScope)) \ - X(GetScopeFromCompleteName, decltype(&Cpp::GetScopeFromCompleteName)) \ - X(InstantiateTemplate, decltype(&Cpp::InstantiateTemplate)) \ - X(GetParentScope, decltype(&Cpp::GetParentScope)) \ - X(IsTemplate, decltype(&Cpp::IsTemplate)) \ - X(IsTemplateSpecialization, decltype(&Cpp::IsTemplateSpecialization)) \ - X(IsTypedefed, decltype(&Cpp::IsTypedefed)) \ - X(IsClassPolymorphic, decltype(&Cpp::IsClassPolymorphic)) \ - X(Demangle, decltype(&Cpp::Demangle)) \ - X(SizeOf, decltype(&Cpp::SizeOf)) \ - X(GetSizeOfType, decltype(&Cpp::GetSizeOfType)) \ - X(IsBuiltin, decltype(&Cpp::IsBuiltin)) \ - X(IsComplete, decltype(&Cpp::IsComplete)) \ - X(Allocate, decltype(&Cpp::Allocate)) \ - X(Deallocate, decltype(&Cpp::Deallocate)) \ - X(Construct, decltype(&Cpp::Construct)) \ - X(Destruct, decltype(&Cpp::Destruct)) \ - X(IsAbstract, decltype(&Cpp::IsAbstract)) \ - X(IsEnumScope, decltype(&Cpp::IsEnumScope)) \ - X(IsEnumConstant, decltype(&Cpp::IsEnumConstant)) \ - X(IsAggregate, decltype(&Cpp::IsAggregate)) \ - X(HasDefaultConstructor, decltype(&Cpp::HasDefaultConstructor)) \ - X(IsVariable, decltype(&Cpp::IsVariable)) \ - X(GetAllCppNames, decltype(&Cpp::GetAllCppNames)) \ - X(GetUsingNamespaces, decltype(&Cpp::GetUsingNamespaces)) \ - X(GetCompleteName, decltype(&Cpp::GetCompleteName)) \ - X(GetDestructor, decltype(&Cpp::GetDestructor)) \ - X(IsVirtualMethod, decltype(&Cpp::IsVirtualMethod)) \ - X(GetNumBases, decltype(&Cpp::GetNumBases)) \ - X(GetName, decltype(&Cpp::GetName)) \ - X(GetBaseClass, decltype(&Cpp::GetBaseClass)) \ - X(IsSubclass, decltype(&Cpp::IsSubclass)) \ - X(GetOperator, decltype(&Cpp::GetOperator)) \ - X(GetFunctionReturnType, decltype(&Cpp::GetFunctionReturnType)) \ - X(GetBaseClassOffset, decltype(&Cpp::GetBaseClassOffset)) \ - X(GetClassMethods, decltype(&Cpp::GetClassMethods)) \ - X(GetFunctionsUsingName, decltype(&Cpp::GetFunctionsUsingName)) \ - X(GetFunctionNumArgs, decltype(&Cpp::GetFunctionNumArgs)) \ - X(GetFunctionRequiredArgs, decltype(&Cpp::GetFunctionRequiredArgs)) \ - X(GetFunctionArgName, decltype(&Cpp::GetFunctionArgName)) \ - X(GetFunctionArgType, decltype(&Cpp::GetFunctionArgType)) \ - X(GetFunctionArgDefault, decltype(&Cpp::GetFunctionArgDefault)) \ - X(IsConstMethod, decltype(&Cpp::IsConstMethod)) \ - X(GetFunctionTemplatedDecls, decltype(&Cpp::GetFunctionTemplatedDecls)) \ - X(ExistsFunctionTemplate, decltype(&Cpp::ExistsFunctionTemplate)) \ - X(IsTemplatedFunction, decltype(&Cpp::IsTemplatedFunction)) \ - X(IsStaticMethod, decltype(&Cpp::IsStaticMethod)) \ - X(GetClassTemplatedMethods, decltype(&Cpp::GetClassTemplatedMethods)) \ - X(BestOverloadFunctionMatch, decltype(&Cpp::BestOverloadFunctionMatch)) \ - X(GetOperatorFromSpelling, decltype(&Cpp::GetOperatorFromSpelling)) \ - X(IsFunctionDeleted, decltype(&Cpp::IsFunctionDeleted)) \ - X(IsPublicMethod, decltype(&Cpp::IsPublicMethod)) \ - X(IsProtectedMethod, decltype(&Cpp::IsProtectedMethod)) \ - X(IsPrivateMethod, decltype(&Cpp::IsPrivateMethod)) \ - X(IsConstructor, decltype(&Cpp::IsConstructor)) \ - X(IsDestructor, decltype(&Cpp::IsDestructor)) \ - X(GetDatamembers, decltype(&Cpp::GetDatamembers)) \ - X(GetStaticDatamembers, decltype(&Cpp::GetStaticDatamembers)) \ - X(GetEnumConstantDatamembers, decltype(&Cpp::GetEnumConstantDatamembers)) \ - X(LookupDatamember, decltype(&Cpp::LookupDatamember)) \ - X(IsLambdaClass, decltype(&Cpp::IsLambdaClass)) \ - X(GetQualifiedName, decltype(&Cpp::GetQualifiedName)) \ - X(GetVariableOffset, decltype(&Cpp::GetVariableOffset)) \ - X(IsPublicVariable, decltype(&Cpp::IsPublicVariable)) \ - X(IsProtectedVariable, decltype(&Cpp::IsProtectedVariable)) \ - X(IsPrivateVariable, decltype(&Cpp::IsPrivateVariable)) \ - X(IsStaticVariable, decltype(&Cpp::IsStaticVariable)) \ - X(IsConstVariable, decltype(&Cpp::IsConstVariable)) \ - X(GetDimensions, decltype(&Cpp::GetDimensions)) \ - X(GetEnumConstants, decltype(&Cpp::GetEnumConstants)) \ - X(GetEnumConstantType, decltype(&Cpp::GetEnumConstantType)) \ - X(GetEnumConstantValue, decltype(&Cpp::GetEnumConstantValue)) \ - X(DumpScope, decltype(&Cpp::DumpScope)) \ - X(AddSearchPath, decltype(&Cpp::AddSearchPath)) \ - X(Evaluate, decltype(&Cpp::Evaluate)) \ - X(IsDebugOutputEnabled, decltype(&Cpp::IsDebugOutputEnabled)) \ - X(EnableDebugOutput, decltype(&Cpp::EnableDebugOutput)) \ - X(MakeFunctionCallable, Cpp::JitCall (*)(Cpp::TCppConstFunction_t)) \ - X(GetFunctionAddress, Cpp::TCppFuncAddr_t (*)(Cpp::TCppFunction_t)) \ + decltype(&CppStatic::GetClassTemplateInstantiationArgs)) \ + X(IsClass, decltype(&CppStatic::IsClass)) \ + X(GetType, decltype(&CppStatic::GetType)) \ + X(GetTypeFromScope, decltype(&CppStatic::GetTypeFromScope)) \ + X(GetComplexType, decltype(&CppStatic::GetComplexType)) \ + X(GetIntegerTypeFromEnumScope, \ + decltype(&CppStatic::GetIntegerTypeFromEnumScope)) \ + X(GetUnderlyingScope, decltype(&CppStatic::GetUnderlyingScope)) \ + X(GetScope, decltype(&CppStatic::GetScope)) \ + X(GetGlobalScope, decltype(&CppStatic::GetGlobalScope)) \ + X(GetScopeFromCompleteName, decltype(&CppStatic::GetScopeFromCompleteName)) \ + X(InstantiateTemplate, decltype(&CppStatic::InstantiateTemplate)) \ + X(GetParentScope, decltype(&CppStatic::GetParentScope)) \ + X(IsTemplate, decltype(&CppStatic::IsTemplate)) \ + X(IsTemplateSpecialization, decltype(&CppStatic::IsTemplateSpecialization)) \ + X(IsTypedefed, decltype(&CppStatic::IsTypedefed)) \ + X(IsClassPolymorphic, decltype(&CppStatic::IsClassPolymorphic)) \ + X(Demangle, decltype(&CppStatic::Demangle)) \ + X(SizeOf, decltype(&CppStatic::SizeOf)) \ + X(GetSizeOfType, decltype(&CppStatic::GetSizeOfType)) \ + X(IsBuiltin, decltype(&CppStatic::IsBuiltin)) \ + X(IsComplete, decltype(&CppStatic::IsComplete)) \ + X(Allocate, decltype(&CppStatic::Allocate)) \ + X(Deallocate, decltype(&CppStatic::Deallocate)) \ + X(Construct, decltype(&CppStatic::Construct)) \ + X(Destruct, decltype(&CppStatic::Destruct)) \ + X(IsAbstract, decltype(&CppStatic::IsAbstract)) \ + X(IsEnumScope, decltype(&CppStatic::IsEnumScope)) \ + X(IsEnumConstant, decltype(&CppStatic::IsEnumConstant)) \ + X(IsAggregate, decltype(&CppStatic::IsAggregate)) \ + X(HasDefaultConstructor, decltype(&CppStatic::HasDefaultConstructor)) \ + X(IsVariable, decltype(&CppStatic::IsVariable)) \ + X(GetAllCppNames, decltype(&CppStatic::GetAllCppNames)) \ + X(GetUsingNamespaces, decltype(&CppStatic::GetUsingNamespaces)) \ + X(GetCompleteName, decltype(&CppStatic::GetCompleteName)) \ + X(GetDestructor, decltype(&CppStatic::GetDestructor)) \ + X(IsVirtualMethod, decltype(&CppStatic::IsVirtualMethod)) \ + X(GetNumBases, decltype(&CppStatic::GetNumBases)) \ + X(GetName, decltype(&CppStatic::GetName)) \ + X(GetBaseClass, decltype(&CppStatic::GetBaseClass)) \ + X(IsSubclass, decltype(&CppStatic::IsSubclass)) \ + X(GetOperator, decltype(&CppStatic::GetOperator)) \ + X(GetFunctionReturnType, decltype(&CppStatic::GetFunctionReturnType)) \ + X(GetBaseClassOffset, decltype(&CppStatic::GetBaseClassOffset)) \ + X(GetClassMethods, decltype(&CppStatic::GetClassMethods)) \ + X(GetFunctionsUsingName, decltype(&CppStatic::GetFunctionsUsingName)) \ + X(GetFunctionNumArgs, decltype(&CppStatic::GetFunctionNumArgs)) \ + X(GetFunctionRequiredArgs, decltype(&CppStatic::GetFunctionRequiredArgs)) \ + X(GetFunctionArgName, decltype(&CppStatic::GetFunctionArgName)) \ + X(GetFunctionArgType, decltype(&CppStatic::GetFunctionArgType)) \ + X(GetFunctionArgDefault, decltype(&CppStatic::GetFunctionArgDefault)) \ + X(IsConstMethod, decltype(&CppStatic::IsConstMethod)) \ + X(GetFunctionTemplatedDecls, \ + decltype(&CppStatic::GetFunctionTemplatedDecls)) \ + X(ExistsFunctionTemplate, decltype(&CppStatic::ExistsFunctionTemplate)) \ + X(IsTemplatedFunction, decltype(&CppStatic::IsTemplatedFunction)) \ + X(IsStaticMethod, decltype(&CppStatic::IsStaticMethod)) \ + X(GetClassTemplatedMethods, decltype(&CppStatic::GetClassTemplatedMethods)) \ + X(BestOverloadFunctionMatch, \ + decltype(&CppStatic::BestOverloadFunctionMatch)) \ + X(GetOperatorFromSpelling, decltype(&CppStatic::GetOperatorFromSpelling)) \ + X(IsFunctionDeleted, decltype(&CppStatic::IsFunctionDeleted)) \ + X(IsPublicMethod, decltype(&CppStatic::IsPublicMethod)) \ + X(IsProtectedMethod, decltype(&CppStatic::IsProtectedMethod)) \ + X(IsPrivateMethod, decltype(&CppStatic::IsPrivateMethod)) \ + X(IsConstructor, decltype(&CppStatic::IsConstructor)) \ + X(IsDestructor, decltype(&CppStatic::IsDestructor)) \ + X(GetDatamembers, decltype(&CppStatic::GetDatamembers)) \ + X(GetStaticDatamembers, decltype(&CppStatic::GetStaticDatamembers)) \ + X(GetEnumConstantDatamembers, \ + decltype(&CppStatic::GetEnumConstantDatamembers)) \ + X(LookupDatamember, decltype(&CppStatic::LookupDatamember)) \ + X(IsLambdaClass, decltype(&CppStatic::IsLambdaClass)) \ + X(GetQualifiedName, decltype(&CppStatic::GetQualifiedName)) \ + X(GetVariableOffset, decltype(&CppStatic::GetVariableOffset)) \ + X(IsPublicVariable, decltype(&CppStatic::IsPublicVariable)) \ + X(IsProtectedVariable, decltype(&CppStatic::IsProtectedVariable)) \ + X(IsPrivateVariable, decltype(&CppStatic::IsPrivateVariable)) \ + X(IsStaticVariable, decltype(&CppStatic::IsStaticVariable)) \ + X(IsConstVariable, decltype(&CppStatic::IsConstVariable)) \ + X(GetDimensions, decltype(&CppStatic::GetDimensions)) \ + X(GetEnumConstants, decltype(&CppStatic::GetEnumConstants)) \ + X(GetEnumConstantType, decltype(&CppStatic::GetEnumConstantType)) \ + X(GetEnumConstantValue, decltype(&CppStatic::GetEnumConstantValue)) \ + X(DumpScope, decltype(&CppStatic::DumpScope)) \ + X(AddSearchPath, decltype(&CppStatic::AddSearchPath)) \ + X(Evaluate, decltype(&CppStatic::Evaluate)) \ + X(IsDebugOutputEnabled, decltype(&CppStatic::IsDebugOutputEnabled)) \ + X(EnableDebugOutput, decltype(&CppStatic::EnableDebugOutput)) \ + X(MakeFunctionCallable, \ + CppStatic::JitCall (*)(CppStatic::TCppConstFunction_t)) \ + X(GetFunctionAddress, \ + CppStatic::TCppFuncAddr_t (*)(CppStatic::TCppFunction_t)) \ /*X(API_name, fnptr_ty)*/ namespace CppDispatch { // forward all type aliases -using TCppIndex_t = ::Cpp::TCppIndex_t; -using TCppScope_t = ::Cpp::TCppScope_t; -using TCppConstScope_t = ::Cpp::TCppConstScope_t; -using TCppType_t = ::Cpp::TCppType_t; -using TCppFunction_t = ::Cpp::TCppFunction_t; -using TCppConstFunction_t = ::Cpp::TCppConstFunction_t; -using TCppFuncAddr_t = ::Cpp::TCppFuncAddr_t; -using TInterp_t = ::Cpp::TInterp_t; -using TCppObject_t = ::Cpp::TCppObject_t; +using TCppIndex_t = ::CppStatic::TCppIndex_t; +using TCppScope_t = ::CppStatic::TCppScope_t; +using TCppConstScope_t = ::CppStatic::TCppConstScope_t; +using TCppType_t = ::CppStatic::TCppType_t; +using TCppFunction_t = ::CppStatic::TCppFunction_t; +using TCppConstFunction_t = ::CppStatic::TCppConstFunction_t; +using TCppFuncAddr_t = ::CppStatic::TCppFuncAddr_t; +using TInterp_t = ::CppStatic::TInterp_t; +using TCppObject_t = ::CppStatic::TCppObject_t; -using Operator = ::Cpp::Operator; -using OperatorArity = ::Cpp::OperatorArity; -using QualKind = ::Cpp::QualKind; -using TemplateArgInfo = ::Cpp::TemplateArgInfo; -using ValueKind = ::Cpp::ValueKind; +using Operator = ::CppStatic::Operator; +using OperatorArity = ::CppStatic::OperatorArity; +using QualKind = ::CppStatic::QualKind; +using TemplateArgInfo = ::CppStatic::TemplateArgInfo; +using ValueKind = ::CppStatic::ValueKind; -using JitCall = ::Cpp::JitCall; +using JitCall = ::CppStatic::JitCall; } // end namespace CppDispatch // TODO: implement overload that takes an existing opened DL handle @@ -257,4 +264,5 @@ inline bool init_functions(const char* customLibPath = nullptr) { } } // namespace CppDispatch +namespace Cpp = CppDispatch; #endif // CPPINTEROP_CPPINTEROPDISPATCH_H diff --git a/include/CppInterOp/CppInterOp.h b/include/CppInterOp/CppInterOp.h index 1d85df305..98447b98a 100644 --- a/include/CppInterOp/CppInterOp.h +++ b/include/CppInterOp/CppInterOp.h @@ -33,7 +33,7 @@ #endif #endif -namespace Cpp { +namespace CppStatic { using TCppIndex_t = size_t; using TCppScope_t = void*; using TCppConstScope_t = const void*; @@ -945,6 +945,9 @@ CPPINTEROP_API int Undo(unsigned N = 1); CPPINTEROP_API pid_t GetExecutorPID(); #endif -} // end namespace Cpp +} // namespace CppStatic +#ifndef CPPINTEROP_CPPINTEROPDISPATCH_H +namespace Cpp = CppStatic; +#endif #endif // CPPINTEROP_CPPINTEROP_H diff --git a/lib/CppInterOp/CXCppInterOp.cpp b/lib/CppInterOp/CXCppInterOp.cpp index 7f35f431b..423459492 100644 --- a/lib/CppInterOp/CXCppInterOp.cpp +++ b/lib/CppInterOp/CXCppInterOp.cpp @@ -323,9 +323,9 @@ void clang_Interpreter_addIncludePath(CXInterpreter I, const char* dir) { getInterpreter(I)->AddIncludePath(dir); } -namespace Cpp { +namespace CppStatic { int Declare(compat::Interpreter& interp, const char* code, bool silent); -} // namespace Cpp +} // namespace CppStatic enum CXErrorCode clang_Interpreter_declare(CXInterpreter I, const char* code, bool silent) { @@ -406,11 +406,11 @@ CXString clang_Interpreter_searchLibrariesForSymbol(CXInterpreter I, mangled_name, search_system)); } -namespace Cpp { +namespace CppStatic { bool InsertOrReplaceJitSymbol(compat::Interpreter& I, const char* linker_mangled_name, uint64_t address); -} // namespace Cpp +} // namespace CppStatic bool clang_Interpreter_insertOrReplaceJitSymbol(CXInterpreter I, const char* linker_mangled_name, @@ -556,12 +556,12 @@ bool clang_existsFunctionTemplate(const char* name, CXScope parent) { return true; } -namespace Cpp { +namespace CppStatic { TCppScope_t InstantiateTemplate(compat::Interpreter& I, TCppScope_t tmpl, const TemplateArgInfo* template_args, size_t template_args_size, bool instantiate_body = false); -} // namespace Cpp +} // namespace CppStatic CXScope clang_instantiateTemplate(CXScope tmpl, CXTemplateArgInfo* template_args, @@ -584,10 +584,10 @@ CXObject clang_allocate(unsigned int n) { return ::operator new(n); } void clang_deallocate(CXObject address) { ::operator delete(address); } -namespace Cpp { +namespace CppStatic { void* Construct(compat::Interpreter& interp, TCppScope_t scope, void* arena /*=nullptr*/, TCppIndex_t count); -} // namespace Cpp +} // namespace CppStatic CXObject clang_construct(CXScope scope, void* arena, size_t count) { return Cpp::Construct(*getInterpreter(scope), @@ -600,10 +600,10 @@ void clang_invoke(CXScope func, void* result, void** args, size_t n, .Invoke(result, {args, n}, self); } -namespace Cpp { +namespace CppStatic { bool Destruct(compat::Interpreter& interp, TCppObject_t This, const clang::Decl* Class, bool withFree, size_t nary); -} // namespace Cpp +} // namespace CppStatic bool clang_destruct(CXObject This, CXScope S, bool withFree, size_t nary) { return Cpp::Destruct(*getInterpreter(S), This, getDecl(S), withFree, nary); diff --git a/lib/CppInterOp/CppDispatch.cpp b/lib/CppInterOp/CppDispatch.cpp index 20ed856e8..ec1cdea33 100644 --- a/lib/CppInterOp/CppDispatch.cpp +++ b/lib/CppInterOp/CppDispatch.cpp @@ -9,7 +9,7 @@ static const std::unordered_map INTEROP_FUNCTIONS = { -#define X(name, type) {#name, (__CPP_FUNC) static_cast(&Cpp::name)}, +#define X(name, type) {#name, (__CPP_FUNC) static_cast(&CppStatic::name)}, CPPINTEROP_API_MAP #undef X }; diff --git a/lib/CppInterOp/CppInterOp.cpp b/lib/CppInterOp/CppInterOp.cpp index 20a4ce0ed..d7dd767ef 100755 --- a/lib/CppInterOp/CppInterOp.cpp +++ b/lib/CppInterOp/CppInterOp.cpp @@ -97,8 +97,8 @@ #include #endif // WIN32 -// Runtime symbols required if the library using JIT (Cpp::Evaluate) does not -// link to llvm +// Runtime symbols required if the library using JIT (Cpp::Evaluate) does +// not link to llvm #if !defined(CPPINTEROP_USE_CLING) && !defined(EMSCRIPTEN) struct __clang_Interpreter_NewTag { } __ci_newtag; @@ -125,7 +125,7 @@ void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, #endif #endif // CPPINTEROP_USE_CLING -namespace Cpp { +namespace CppStatic { using namespace clang; using namespace llvm; @@ -4290,4 +4290,4 @@ pid_t GetExecutorPID() { #endif -} // end namespace Cpp +} // namespace CppStatic diff --git a/unittests/CppInterOp/DispatchAPITest.cpp b/unittests/CppInterOp/DispatchAPITest.cpp index fbd8a8554..260ed4bfd 100644 --- a/unittests/CppInterOp/DispatchAPITest.cpp +++ b/unittests/CppInterOp/DispatchAPITest.cpp @@ -1,7 +1,7 @@ -#include "Utils.h" - #include "CppInterOp/CppDispatch.h" +#include "Utils.h" + #include "gtest/gtest.h" using namespace TestUtils; From 9abe8999d2c2667adee4ee04382ff17e68f65f78 Mon Sep 17 00:00:00 2001 From: Aaron Jomy Date: Wed, 7 Jan 2026 14:32:04 +0100 Subject: [PATCH 4/9] Rename `CppDispatch` -> `Dispatch` and `CppStatic` -> `CppImpl` --- include/CppInterOp/CppDispatch.h | 268 ------------------ include/CppInterOp/CppInterOp.h | 8 +- include/CppInterOp/Dispatch.h | 252 ++++++++++++++++ lib/CppInterOp/CMakeLists.txt | 2 +- lib/CppInterOp/CXCppInterOp.cpp | 20 +- lib/CppInterOp/CppInterOp.cpp | 6 +- .../{CppDispatch.cpp => Dispatch.cpp} | 9 +- unittests/CppInterOp/DispatchAPITest.cpp | 2 +- 8 files changed, 275 insertions(+), 292 deletions(-) delete mode 100644 include/CppInterOp/CppDispatch.h create mode 100644 include/CppInterOp/Dispatch.h rename lib/CppInterOp/{CppDispatch.cpp => Dispatch.cpp} (81%) diff --git a/include/CppInterOp/CppDispatch.h b/include/CppInterOp/CppDispatch.h deleted file mode 100644 index fbd7a29de..000000000 --- a/include/CppInterOp/CppDispatch.h +++ /dev/null @@ -1,268 +0,0 @@ -//--------------------------------------------------------------------*- C++ -*- -// CppInterOp Dispatch Mechanism -// author: Aaron Jomy -//===----------------------------------------------------------------------===// -// -// Defines the mechanism which enables dispatching of the CppInterOp API -// without linking to it, preventing any LLVM or Clang symbols from being leaked -// into the client application. -// -//===----------------------------------------------------------------------===// -#ifndef CPPINTEROP_CPPINTEROPDISPATCH_H -#define CPPINTEROP_CPPINTEROPDISPATCH_H - -#include -#include -#include -#include -#include - -#include - -using __CPP_FUNC = void (*)(); - -///\param[in] procname - the name of the FunctionEntry in the symbol lookup -/// table. -/// -///\returns the function address of the requested API, or nullptr if not found -extern "C" CPPINTEROP_API void ( - *CppGetProcAddress(const unsigned char* procname))(void); - -// macro that allows declaration and loading of all CppInterOp API functions in -// a consistent way. This is used as our dispatched API list, along with the -// name-address pair table -#define CPPINTEROP_API_MAP \ - X(CreateInterpreter, decltype(&CppStatic::CreateInterpreter)) \ - X(GetInterpreter, decltype(&CppStatic::GetInterpreter)) \ - X(Process, decltype(&CppStatic::Process)) \ - X(GetResourceDir, decltype(&CppStatic::GetResourceDir)) \ - X(AddIncludePath, decltype(&CppStatic::AddIncludePath)) \ - X(LoadLibrary, decltype(&CppStatic::LoadLibrary)) \ - X(Declare, decltype(&CppStatic::Declare)) \ - X(DeleteInterpreter, decltype(&CppStatic::DeleteInterpreter)) \ - X(IsNamespace, decltype(&CppStatic::IsNamespace)) \ - X(ObjToString, decltype(&CppStatic::ObjToString)) \ - X(GetQualifiedCompleteName, decltype(&CppStatic::GetQualifiedCompleteName)) \ - X(GetValueKind, decltype(&CppStatic::GetValueKind)) \ - X(GetNonReferenceType, decltype(&CppStatic::GetNonReferenceType)) \ - X(IsEnumType, decltype(&CppStatic::IsEnumType)) \ - X(GetIntegerTypeFromEnumType, \ - decltype(&CppStatic::GetIntegerTypeFromEnumType)) \ - X(GetReferencedType, decltype(&CppStatic::GetReferencedType)) \ - X(IsPointerType, decltype(&CppStatic::IsPointerType)) \ - X(GetPointeeType, decltype(&CppStatic::GetPointeeType)) \ - X(GetPointerType, decltype(&CppStatic::GetPointerType)) \ - X(IsReferenceType, decltype(&CppStatic::IsReferenceType)) \ - X(GetTypeAsString, decltype(&CppStatic::GetTypeAsString)) \ - X(GetCanonicalType, decltype(&CppStatic::GetCanonicalType)) \ - X(HasTypeQualifier, decltype(&CppStatic::HasTypeQualifier)) \ - X(RemoveTypeQualifier, decltype(&CppStatic::RemoveTypeQualifier)) \ - X(GetUnderlyingType, decltype(&CppStatic::GetUnderlyingType)) \ - X(IsRecordType, decltype(&CppStatic::IsRecordType)) \ - X(IsFunctionPointerType, decltype(&CppStatic::IsFunctionPointerType)) \ - X(GetVariableType, decltype(&CppStatic::GetVariableType)) \ - X(GetNamed, decltype(&CppStatic::GetNamed)) \ - X(GetScopeFromType, decltype(&CppStatic::GetScopeFromType)) \ - X(GetClassTemplateInstantiationArgs, \ - decltype(&CppStatic::GetClassTemplateInstantiationArgs)) \ - X(IsClass, decltype(&CppStatic::IsClass)) \ - X(GetType, decltype(&CppStatic::GetType)) \ - X(GetTypeFromScope, decltype(&CppStatic::GetTypeFromScope)) \ - X(GetComplexType, decltype(&CppStatic::GetComplexType)) \ - X(GetIntegerTypeFromEnumScope, \ - decltype(&CppStatic::GetIntegerTypeFromEnumScope)) \ - X(GetUnderlyingScope, decltype(&CppStatic::GetUnderlyingScope)) \ - X(GetScope, decltype(&CppStatic::GetScope)) \ - X(GetGlobalScope, decltype(&CppStatic::GetGlobalScope)) \ - X(GetScopeFromCompleteName, decltype(&CppStatic::GetScopeFromCompleteName)) \ - X(InstantiateTemplate, decltype(&CppStatic::InstantiateTemplate)) \ - X(GetParentScope, decltype(&CppStatic::GetParentScope)) \ - X(IsTemplate, decltype(&CppStatic::IsTemplate)) \ - X(IsTemplateSpecialization, decltype(&CppStatic::IsTemplateSpecialization)) \ - X(IsTypedefed, decltype(&CppStatic::IsTypedefed)) \ - X(IsClassPolymorphic, decltype(&CppStatic::IsClassPolymorphic)) \ - X(Demangle, decltype(&CppStatic::Demangle)) \ - X(SizeOf, decltype(&CppStatic::SizeOf)) \ - X(GetSizeOfType, decltype(&CppStatic::GetSizeOfType)) \ - X(IsBuiltin, decltype(&CppStatic::IsBuiltin)) \ - X(IsComplete, decltype(&CppStatic::IsComplete)) \ - X(Allocate, decltype(&CppStatic::Allocate)) \ - X(Deallocate, decltype(&CppStatic::Deallocate)) \ - X(Construct, decltype(&CppStatic::Construct)) \ - X(Destruct, decltype(&CppStatic::Destruct)) \ - X(IsAbstract, decltype(&CppStatic::IsAbstract)) \ - X(IsEnumScope, decltype(&CppStatic::IsEnumScope)) \ - X(IsEnumConstant, decltype(&CppStatic::IsEnumConstant)) \ - X(IsAggregate, decltype(&CppStatic::IsAggregate)) \ - X(HasDefaultConstructor, decltype(&CppStatic::HasDefaultConstructor)) \ - X(IsVariable, decltype(&CppStatic::IsVariable)) \ - X(GetAllCppNames, decltype(&CppStatic::GetAllCppNames)) \ - X(GetUsingNamespaces, decltype(&CppStatic::GetUsingNamespaces)) \ - X(GetCompleteName, decltype(&CppStatic::GetCompleteName)) \ - X(GetDestructor, decltype(&CppStatic::GetDestructor)) \ - X(IsVirtualMethod, decltype(&CppStatic::IsVirtualMethod)) \ - X(GetNumBases, decltype(&CppStatic::GetNumBases)) \ - X(GetName, decltype(&CppStatic::GetName)) \ - X(GetBaseClass, decltype(&CppStatic::GetBaseClass)) \ - X(IsSubclass, decltype(&CppStatic::IsSubclass)) \ - X(GetOperator, decltype(&CppStatic::GetOperator)) \ - X(GetFunctionReturnType, decltype(&CppStatic::GetFunctionReturnType)) \ - X(GetBaseClassOffset, decltype(&CppStatic::GetBaseClassOffset)) \ - X(GetClassMethods, decltype(&CppStatic::GetClassMethods)) \ - X(GetFunctionsUsingName, decltype(&CppStatic::GetFunctionsUsingName)) \ - X(GetFunctionNumArgs, decltype(&CppStatic::GetFunctionNumArgs)) \ - X(GetFunctionRequiredArgs, decltype(&CppStatic::GetFunctionRequiredArgs)) \ - X(GetFunctionArgName, decltype(&CppStatic::GetFunctionArgName)) \ - X(GetFunctionArgType, decltype(&CppStatic::GetFunctionArgType)) \ - X(GetFunctionArgDefault, decltype(&CppStatic::GetFunctionArgDefault)) \ - X(IsConstMethod, decltype(&CppStatic::IsConstMethod)) \ - X(GetFunctionTemplatedDecls, \ - decltype(&CppStatic::GetFunctionTemplatedDecls)) \ - X(ExistsFunctionTemplate, decltype(&CppStatic::ExistsFunctionTemplate)) \ - X(IsTemplatedFunction, decltype(&CppStatic::IsTemplatedFunction)) \ - X(IsStaticMethod, decltype(&CppStatic::IsStaticMethod)) \ - X(GetClassTemplatedMethods, decltype(&CppStatic::GetClassTemplatedMethods)) \ - X(BestOverloadFunctionMatch, \ - decltype(&CppStatic::BestOverloadFunctionMatch)) \ - X(GetOperatorFromSpelling, decltype(&CppStatic::GetOperatorFromSpelling)) \ - X(IsFunctionDeleted, decltype(&CppStatic::IsFunctionDeleted)) \ - X(IsPublicMethod, decltype(&CppStatic::IsPublicMethod)) \ - X(IsProtectedMethod, decltype(&CppStatic::IsProtectedMethod)) \ - X(IsPrivateMethod, decltype(&CppStatic::IsPrivateMethod)) \ - X(IsConstructor, decltype(&CppStatic::IsConstructor)) \ - X(IsDestructor, decltype(&CppStatic::IsDestructor)) \ - X(GetDatamembers, decltype(&CppStatic::GetDatamembers)) \ - X(GetStaticDatamembers, decltype(&CppStatic::GetStaticDatamembers)) \ - X(GetEnumConstantDatamembers, \ - decltype(&CppStatic::GetEnumConstantDatamembers)) \ - X(LookupDatamember, decltype(&CppStatic::LookupDatamember)) \ - X(IsLambdaClass, decltype(&CppStatic::IsLambdaClass)) \ - X(GetQualifiedName, decltype(&CppStatic::GetQualifiedName)) \ - X(GetVariableOffset, decltype(&CppStatic::GetVariableOffset)) \ - X(IsPublicVariable, decltype(&CppStatic::IsPublicVariable)) \ - X(IsProtectedVariable, decltype(&CppStatic::IsProtectedVariable)) \ - X(IsPrivateVariable, decltype(&CppStatic::IsPrivateVariable)) \ - X(IsStaticVariable, decltype(&CppStatic::IsStaticVariable)) \ - X(IsConstVariable, decltype(&CppStatic::IsConstVariable)) \ - X(GetDimensions, decltype(&CppStatic::GetDimensions)) \ - X(GetEnumConstants, decltype(&CppStatic::GetEnumConstants)) \ - X(GetEnumConstantType, decltype(&CppStatic::GetEnumConstantType)) \ - X(GetEnumConstantValue, decltype(&CppStatic::GetEnumConstantValue)) \ - X(DumpScope, decltype(&CppStatic::DumpScope)) \ - X(AddSearchPath, decltype(&CppStatic::AddSearchPath)) \ - X(Evaluate, decltype(&CppStatic::Evaluate)) \ - X(IsDebugOutputEnabled, decltype(&CppStatic::IsDebugOutputEnabled)) \ - X(EnableDebugOutput, decltype(&CppStatic::EnableDebugOutput)) \ - X(MakeFunctionCallable, \ - CppStatic::JitCall (*)(CppStatic::TCppConstFunction_t)) \ - X(GetFunctionAddress, \ - CppStatic::TCppFuncAddr_t (*)(CppStatic::TCppFunction_t)) \ - /*X(API_name, fnptr_ty)*/ -namespace CppDispatch { -// forward all type aliases -using TCppIndex_t = ::CppStatic::TCppIndex_t; -using TCppScope_t = ::CppStatic::TCppScope_t; -using TCppConstScope_t = ::CppStatic::TCppConstScope_t; -using TCppType_t = ::CppStatic::TCppType_t; -using TCppFunction_t = ::CppStatic::TCppFunction_t; -using TCppConstFunction_t = ::CppStatic::TCppConstFunction_t; -using TCppFuncAddr_t = ::CppStatic::TCppFuncAddr_t; -using TInterp_t = ::CppStatic::TInterp_t; -using TCppObject_t = ::CppStatic::TCppObject_t; - -using Operator = ::CppStatic::Operator; -using OperatorArity = ::CppStatic::OperatorArity; -using QualKind = ::CppStatic::QualKind; -using TemplateArgInfo = ::CppStatic::TemplateArgInfo; -using ValueKind = ::CppStatic::ValueKind; - -using JitCall = ::CppStatic::JitCall; -} // end namespace CppDispatch - -// TODO: implement overload that takes an existing opened DL handle -inline void* dlGetProcAddress(const char* name, - const char* customLibPath = nullptr) { - if (!name) - return nullptr; - - static std::once_flag loaded; - static void* handle = nullptr; - static void* (*getCppProcAddress)(const char*) = nullptr; - - std::call_once(loaded, [customLibPath]() { - // priority order: 1) custom path argument, or CPPINTEROP_LIBRARY_PATH via - // 2) cmake configured path 3) env vars - const char* libPath = customLibPath; - if (!libPath) { - libPath = std::getenv("CPPINTEROP_LIBRARY_PATH"); - } - - handle = dlopen(libPath, RTLD_LOCAL | RTLD_NOW); - if (!handle) { - std::cerr << "[CppInterOp] Failed to load library from " << libPath - << ": " << dlerror() << '\n'; - return; - } - - getCppProcAddress = reinterpret_cast( - dlsym(handle, "CppGetProcAddress")); - if (!getCppProcAddress) { - std::cerr << "[CppInterOp] Failed to find CppGetProcAddress: " - << dlerror() << '\n'; - dlclose(handle); - handle = nullptr; - } - }); - - return getCppProcAddress ? getCppProcAddress(name) : nullptr; -} - -// Used for the extern clauses below -// FIXME: drop the using clauses -namespace CppAPIType { -#define X(name, type) using name = type; -CPPINTEROP_API_MAP -#undef X -} // end namespace CppAPIType - -namespace CppDispatch { - -#define X(name, type) extern CppAPIType::name name; -CPPINTEROP_API_MAP -#undef X - -/// Initialize all CppInterOp API from the dynamically loaded library -/// (RTLD_LOCAL) \param[in] customLibPath Optional custom path to -/// libclangCppInterOp.so \returns true if initialization succeeded, false -/// otherwise -inline bool init_functions(const char* customLibPath = nullptr) { - // trigger library loading if custom path provided - std::cout << "[CppInterOp] Initializing CppInterOp API functions from " - << (customLibPath ? customLibPath - : "default library path") << '\n'; - if (customLibPath) { - void* test = dlGetProcAddress("GetInterpreter", customLibPath); - if (!test) { - std::cerr << "[CppInterOp] Failed to initialize with custom path: " - << customLibPath << '\n'; - return false; - } - } - -#define X(name, type) \ - name = reinterpret_cast(dlGetProcAddress(#name)); - CPPINTEROP_API_MAP -#undef X - - // test to verify that critical (and consequently all) functions loaded - if (!GetInterpreter || !CreateInterpreter) { - std::cerr << "[CppInterOp] Failed to load critical functions" << std::endl; - return false; - } - - return true; -} -} // namespace CppDispatch - -namespace Cpp = CppDispatch; -#endif // CPPINTEROP_CPPINTEROPDISPATCH_H diff --git a/include/CppInterOp/CppInterOp.h b/include/CppInterOp/CppInterOp.h index 98447b98a..19cb81b1d 100644 --- a/include/CppInterOp/CppInterOp.h +++ b/include/CppInterOp/CppInterOp.h @@ -33,7 +33,7 @@ #endif #endif -namespace CppStatic { +namespace CppImpl { using TCppIndex_t = size_t; using TCppScope_t = void*; using TCppConstScope_t = const void*; @@ -945,9 +945,9 @@ CPPINTEROP_API int Undo(unsigned N = 1); CPPINTEROP_API pid_t GetExecutorPID(); #endif -} // namespace CppStatic +} // namespace CppImpl -#ifndef CPPINTEROP_CPPINTEROPDISPATCH_H -namespace Cpp = CppStatic; +#ifndef CPPINTEROP_DISPATCH_H +namespace Cpp = CppImpl; #endif #endif // CPPINTEROP_CPPINTEROP_H diff --git a/include/CppInterOp/Dispatch.h b/include/CppInterOp/Dispatch.h new file mode 100644 index 000000000..8fa45b70e --- /dev/null +++ b/include/CppInterOp/Dispatch.h @@ -0,0 +1,252 @@ +//--------------------------------------------------------------------*- C++ -*- +// CppInterOp Dispatch Mechanism +// author: Aaron Jomy +//===----------------------------------------------------------------------===// +// +// Defines the mechanism which enables dispatching of the CppInterOp API +// without linking to it, preventing any LLVM or Clang symbols from being leaked +// into the client application. +// +//===----------------------------------------------------------------------===// +#ifndef CPPINTEROP_DISPATCH_H +#define CPPINTEROP_DISPATCH_H + +#include +#include +#include +#include +#include + +#ifdef CPPINTEROP_CPPINTEROP_H +#error "To use the Dispatch mechanism, do not include CppInterOp.h" +#endif + +#include + +using __CPP_FUNC = void (*)(); + +///\param[in] procname - the name of the FunctionEntry in the symbol lookup +/// table. +/// +///\returns the function address of the requested API, or nullptr if not found +extern "C" CPPINTEROP_API void ( + *CppGetProcAddress(const unsigned char* procname))(void); + +// macro that allows declaration and loading of all CppInterOp API functions in +// a consistent way. This is used as our dispatched API list, along with the +// name-address pair table +#define CPPINTEROP_API_MAP \ + X(CreateInterpreter, decltype(&CppImpl::CreateInterpreter)) \ + X(GetInterpreter, decltype(&CppImpl::GetInterpreter)) \ + X(Process, decltype(&CppImpl::Process)) \ + X(GetResourceDir, decltype(&CppImpl::GetResourceDir)) \ + X(AddIncludePath, decltype(&CppImpl::AddIncludePath)) \ + X(LoadLibrary, decltype(&CppImpl::LoadLibrary)) \ + X(Declare, decltype(&CppImpl::Declare)) \ + X(DeleteInterpreter, decltype(&CppImpl::DeleteInterpreter)) \ + X(IsNamespace, decltype(&CppImpl::IsNamespace)) \ + X(ObjToString, decltype(&CppImpl::ObjToString)) \ + X(GetQualifiedCompleteName, decltype(&CppImpl::GetQualifiedCompleteName)) \ + X(GetValueKind, decltype(&CppImpl::GetValueKind)) \ + X(GetNonReferenceType, decltype(&CppImpl::GetNonReferenceType)) \ + X(IsEnumType, decltype(&CppImpl::IsEnumType)) \ + X(GetIntegerTypeFromEnumType, \ + decltype(&CppImpl::GetIntegerTypeFromEnumType)) \ + X(GetReferencedType, decltype(&CppImpl::GetReferencedType)) \ + X(IsPointerType, decltype(&CppImpl::IsPointerType)) \ + X(GetPointeeType, decltype(&CppImpl::GetPointeeType)) \ + X(GetPointerType, decltype(&CppImpl::GetPointerType)) \ + X(IsReferenceType, decltype(&CppImpl::IsReferenceType)) \ + X(GetTypeAsString, decltype(&CppImpl::GetTypeAsString)) \ + X(GetCanonicalType, decltype(&CppImpl::GetCanonicalType)) \ + X(HasTypeQualifier, decltype(&CppImpl::HasTypeQualifier)) \ + X(RemoveTypeQualifier, decltype(&CppImpl::RemoveTypeQualifier)) \ + X(GetUnderlyingType, decltype(&CppImpl::GetUnderlyingType)) \ + X(IsRecordType, decltype(&CppImpl::IsRecordType)) \ + X(IsFunctionPointerType, decltype(&CppImpl::IsFunctionPointerType)) \ + X(GetVariableType, decltype(&CppImpl::GetVariableType)) \ + X(GetNamed, decltype(&CppImpl::GetNamed)) \ + X(GetScopeFromType, decltype(&CppImpl::GetScopeFromType)) \ + X(GetClassTemplateInstantiationArgs, \ + decltype(&CppImpl::GetClassTemplateInstantiationArgs)) \ + X(IsClass, decltype(&CppImpl::IsClass)) \ + X(GetType, decltype(&CppImpl::GetType)) \ + X(GetTypeFromScope, decltype(&CppImpl::GetTypeFromScope)) \ + X(GetComplexType, decltype(&CppImpl::GetComplexType)) \ + X(GetIntegerTypeFromEnumScope, \ + decltype(&CppImpl::GetIntegerTypeFromEnumScope)) \ + X(GetUnderlyingScope, decltype(&CppImpl::GetUnderlyingScope)) \ + X(GetScope, decltype(&CppImpl::GetScope)) \ + X(GetGlobalScope, decltype(&CppImpl::GetGlobalScope)) \ + X(GetScopeFromCompleteName, decltype(&CppImpl::GetScopeFromCompleteName)) \ + X(InstantiateTemplate, decltype(&CppImpl::InstantiateTemplate)) \ + X(GetParentScope, decltype(&CppImpl::GetParentScope)) \ + X(IsTemplate, decltype(&CppImpl::IsTemplate)) \ + X(IsTemplateSpecialization, decltype(&CppImpl::IsTemplateSpecialization)) \ + X(IsTypedefed, decltype(&CppImpl::IsTypedefed)) \ + X(IsClassPolymorphic, decltype(&CppImpl::IsClassPolymorphic)) \ + X(Demangle, decltype(&CppImpl::Demangle)) \ + X(SizeOf, decltype(&CppImpl::SizeOf)) \ + X(GetSizeOfType, decltype(&CppImpl::GetSizeOfType)) \ + X(IsBuiltin, decltype(&CppImpl::IsBuiltin)) \ + X(IsComplete, decltype(&CppImpl::IsComplete)) \ + X(Allocate, decltype(&CppImpl::Allocate)) \ + X(Deallocate, decltype(&CppImpl::Deallocate)) \ + X(Construct, decltype(&CppImpl::Construct)) \ + X(Destruct, decltype(&CppImpl::Destruct)) \ + X(IsAbstract, decltype(&CppImpl::IsAbstract)) \ + X(IsEnumScope, decltype(&CppImpl::IsEnumScope)) \ + X(IsEnumConstant, decltype(&CppImpl::IsEnumConstant)) \ + X(IsAggregate, decltype(&CppImpl::IsAggregate)) \ + X(HasDefaultConstructor, decltype(&CppImpl::HasDefaultConstructor)) \ + X(IsVariable, decltype(&CppImpl::IsVariable)) \ + X(GetAllCppNames, decltype(&CppImpl::GetAllCppNames)) \ + X(GetUsingNamespaces, decltype(&CppImpl::GetUsingNamespaces)) \ + X(GetCompleteName, decltype(&CppImpl::GetCompleteName)) \ + X(GetDestructor, decltype(&CppImpl::GetDestructor)) \ + X(IsVirtualMethod, decltype(&CppImpl::IsVirtualMethod)) \ + X(GetNumBases, decltype(&CppImpl::GetNumBases)) \ + X(GetName, decltype(&CppImpl::GetName)) \ + X(GetBaseClass, decltype(&CppImpl::GetBaseClass)) \ + X(IsSubclass, decltype(&CppImpl::IsSubclass)) \ + X(GetOperator, decltype(&CppImpl::GetOperator)) \ + X(GetFunctionReturnType, decltype(&CppImpl::GetFunctionReturnType)) \ + X(GetBaseClassOffset, decltype(&CppImpl::GetBaseClassOffset)) \ + X(GetClassMethods, decltype(&CppImpl::GetClassMethods)) \ + X(GetFunctionsUsingName, decltype(&CppImpl::GetFunctionsUsingName)) \ + X(GetFunctionNumArgs, decltype(&CppImpl::GetFunctionNumArgs)) \ + X(GetFunctionRequiredArgs, decltype(&CppImpl::GetFunctionRequiredArgs)) \ + X(GetFunctionArgName, decltype(&CppImpl::GetFunctionArgName)) \ + X(GetFunctionArgType, decltype(&CppImpl::GetFunctionArgType)) \ + X(GetFunctionArgDefault, decltype(&CppImpl::GetFunctionArgDefault)) \ + X(IsConstMethod, decltype(&CppImpl::IsConstMethod)) \ + X(GetFunctionTemplatedDecls, decltype(&CppImpl::GetFunctionTemplatedDecls)) \ + X(ExistsFunctionTemplate, decltype(&CppImpl::ExistsFunctionTemplate)) \ + X(IsTemplatedFunction, decltype(&CppImpl::IsTemplatedFunction)) \ + X(IsStaticMethod, decltype(&CppImpl::IsStaticMethod)) \ + X(GetClassTemplatedMethods, decltype(&CppImpl::GetClassTemplatedMethods)) \ + X(BestOverloadFunctionMatch, decltype(&CppImpl::BestOverloadFunctionMatch)) \ + X(GetOperatorFromSpelling, decltype(&CppImpl::GetOperatorFromSpelling)) \ + X(IsFunctionDeleted, decltype(&CppImpl::IsFunctionDeleted)) \ + X(IsPublicMethod, decltype(&CppImpl::IsPublicMethod)) \ + X(IsProtectedMethod, decltype(&CppImpl::IsProtectedMethod)) \ + X(IsPrivateMethod, decltype(&CppImpl::IsPrivateMethod)) \ + X(IsConstructor, decltype(&CppImpl::IsConstructor)) \ + X(IsDestructor, decltype(&CppImpl::IsDestructor)) \ + X(GetDatamembers, decltype(&CppImpl::GetDatamembers)) \ + X(GetStaticDatamembers, decltype(&CppImpl::GetStaticDatamembers)) \ + X(GetEnumConstantDatamembers, \ + decltype(&CppImpl::GetEnumConstantDatamembers)) \ + X(LookupDatamember, decltype(&CppImpl::LookupDatamember)) \ + X(IsLambdaClass, decltype(&CppImpl::IsLambdaClass)) \ + X(GetQualifiedName, decltype(&CppImpl::GetQualifiedName)) \ + X(GetVariableOffset, decltype(&CppImpl::GetVariableOffset)) \ + X(IsPublicVariable, decltype(&CppImpl::IsPublicVariable)) \ + X(IsProtectedVariable, decltype(&CppImpl::IsProtectedVariable)) \ + X(IsPrivateVariable, decltype(&CppImpl::IsPrivateVariable)) \ + X(IsStaticVariable, decltype(&CppImpl::IsStaticVariable)) \ + X(IsConstVariable, decltype(&CppImpl::IsConstVariable)) \ + X(GetDimensions, decltype(&CppImpl::GetDimensions)) \ + X(GetEnumConstants, decltype(&CppImpl::GetEnumConstants)) \ + X(GetEnumConstantType, decltype(&CppImpl::GetEnumConstantType)) \ + X(GetEnumConstantValue, decltype(&CppImpl::GetEnumConstantValue)) \ + X(DumpScope, decltype(&CppImpl::DumpScope)) \ + X(AddSearchPath, decltype(&CppImpl::AddSearchPath)) \ + X(Evaluate, decltype(&CppImpl::Evaluate)) \ + X(IsDebugOutputEnabled, decltype(&CppImpl::IsDebugOutputEnabled)) \ + X(EnableDebugOutput, decltype(&CppImpl::EnableDebugOutput)) \ + X(MakeFunctionCallable, CppImpl::JitCall (*)(CppImpl::TCppConstFunction_t)) \ + X(GetFunctionAddress, CppImpl::TCppFuncAddr_t (*)(CppImpl::TCppFunction_t)) \ + /*X(API_name, fnptr_ty)*/ + +// TODO: implement overload that takes an existing opened DL handle +inline void* dlGetProcAddress(const char* name, + const char* customLibPath = nullptr) { + if (!name) + return nullptr; + + static std::once_flag loaded; + static void* handle = nullptr; + static void* (*getCppProcAddress)(const char*) = nullptr; + + std::call_once(loaded, [customLibPath]() { + // priority order: 1) custom path argument, or CPPINTEROP_LIBRARY_PATH via + // 2) cmake configured path 3) env vars + const char* libPath = customLibPath; + if (!libPath) { + libPath = std::getenv("CPPINTEROP_LIBRARY_PATH"); + } + + handle = dlopen(libPath, RTLD_LOCAL | RTLD_NOW); + if (!handle) { + std::cerr << "[CppInterOp] Failed to load library from " << libPath + << ": " << dlerror() << '\n'; + return; + } + + getCppProcAddress = reinterpret_cast( + dlsym(handle, "CppGetProcAddress")); + if (!getCppProcAddress) { + std::cerr << "[CppInterOp] Failed to find CppGetProcAddress: " + << dlerror() << '\n'; + dlclose(handle); + handle = nullptr; + } + }); + + return getCppProcAddress ? getCppProcAddress(name) : nullptr; +} + +// Used for the extern clauses below +// FIXME: drop the using clauses +namespace CppAPIType { +#define X(name, type) using name = type; +CPPINTEROP_API_MAP +#undef X +} // end namespace CppAPIType + +namespace CppInternal { +namespace Dispatch { + +// FIXME: This is required for the types, but we should move the types +// into a separate namespace and only use that scope (CppImpl::Types) +using namespace CppImpl; + +#define X(name, type) extern CppAPIType::name name; +CPPINTEROP_API_MAP +#undef X + +/// Initialize all CppInterOp API from the dynamically loaded library +/// (RTLD_LOCAL) \param[in] customLibPath Optional custom path to +/// libclangCppInterOp.so \returns true if initialization succeeded, false +/// otherwise +inline bool init_functions(const char* customLibPath = nullptr) { + // trigger library loading if custom path provided + std::cout << "[CppInterOp] Initializing CppInterOp API functions from " + << (customLibPath ? customLibPath : "default library path") << '\n'; + if (customLibPath) { + void* test = dlGetProcAddress("GetInterpreter", customLibPath); + if (!test) { + std::cerr << "[CppInterOp] Failed to initialize with custom path: " + << customLibPath << '\n'; + return false; + } + } + +#define X(name, type) name = reinterpret_cast(dlGetProcAddress(#name)); + CPPINTEROP_API_MAP +#undef X + + // test to verify that critical (and consequently all) functions loaded + if (!GetInterpreter || !CreateInterpreter) { + std::cerr << "[CppInterOp] Failed to load critical functions" << std::endl; + return false; + } + + return true; +} +} // namespace Dispatch +} // namespace CppInternal + +namespace Cpp = CppInternal::Dispatch; +#endif // CPPINTEROP_DISPATCH_H diff --git a/lib/CppInterOp/CMakeLists.txt b/lib/CppInterOp/CMakeLists.txt index bbd27d7d5..d258fe8cd 100644 --- a/lib/CppInterOp/CMakeLists.txt +++ b/lib/CppInterOp/CMakeLists.txt @@ -107,7 +107,7 @@ endif(LLVM_LINK_LLVM_DYLIB) add_llvm_library(clangCppInterOp DISABLE_LLVM_LINK_LLVM_DYLIB CppInterOp.cpp - CppDispatch.cpp + Dispatch.cpp CXCppInterOp.cpp ${DLM} LINK_LIBS diff --git a/lib/CppInterOp/CXCppInterOp.cpp b/lib/CppInterOp/CXCppInterOp.cpp index 423459492..73d9e7d01 100644 --- a/lib/CppInterOp/CXCppInterOp.cpp +++ b/lib/CppInterOp/CXCppInterOp.cpp @@ -323,9 +323,9 @@ void clang_Interpreter_addIncludePath(CXInterpreter I, const char* dir) { getInterpreter(I)->AddIncludePath(dir); } -namespace CppStatic { +namespace CppImpl { int Declare(compat::Interpreter& interp, const char* code, bool silent); -} // namespace CppStatic +} // namespace CppImpl enum CXErrorCode clang_Interpreter_declare(CXInterpreter I, const char* code, bool silent) { @@ -406,11 +406,11 @@ CXString clang_Interpreter_searchLibrariesForSymbol(CXInterpreter I, mangled_name, search_system)); } -namespace CppStatic { +namespace CppImpl { bool InsertOrReplaceJitSymbol(compat::Interpreter& I, const char* linker_mangled_name, uint64_t address); -} // namespace CppStatic +} // namespace CppImpl bool clang_Interpreter_insertOrReplaceJitSymbol(CXInterpreter I, const char* linker_mangled_name, @@ -556,12 +556,12 @@ bool clang_existsFunctionTemplate(const char* name, CXScope parent) { return true; } -namespace CppStatic { +namespace CppImpl { TCppScope_t InstantiateTemplate(compat::Interpreter& I, TCppScope_t tmpl, const TemplateArgInfo* template_args, size_t template_args_size, bool instantiate_body = false); -} // namespace CppStatic +} // namespace CppImpl CXScope clang_instantiateTemplate(CXScope tmpl, CXTemplateArgInfo* template_args, @@ -584,10 +584,10 @@ CXObject clang_allocate(unsigned int n) { return ::operator new(n); } void clang_deallocate(CXObject address) { ::operator delete(address); } -namespace CppStatic { +namespace CppImpl { void* Construct(compat::Interpreter& interp, TCppScope_t scope, void* arena /*=nullptr*/, TCppIndex_t count); -} // namespace CppStatic +} // namespace CppImpl CXObject clang_construct(CXScope scope, void* arena, size_t count) { return Cpp::Construct(*getInterpreter(scope), @@ -600,10 +600,10 @@ void clang_invoke(CXScope func, void* result, void** args, size_t n, .Invoke(result, {args, n}, self); } -namespace CppStatic { +namespace CppImpl { bool Destruct(compat::Interpreter& interp, TCppObject_t This, const clang::Decl* Class, bool withFree, size_t nary); -} // namespace CppStatic +} // namespace CppImpl bool clang_destruct(CXObject This, CXScope S, bool withFree, size_t nary) { return Cpp::Destruct(*getInterpreter(S), This, getDecl(S), withFree, nary); diff --git a/lib/CppInterOp/CppInterOp.cpp b/lib/CppInterOp/CppInterOp.cpp index d7dd767ef..c4b5d3a29 100755 --- a/lib/CppInterOp/CppInterOp.cpp +++ b/lib/CppInterOp/CppInterOp.cpp @@ -125,7 +125,7 @@ void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, #endif #endif // CPPINTEROP_USE_CLING -namespace CppStatic { +namespace CppImpl { using namespace clang; using namespace llvm; @@ -3175,7 +3175,7 @@ static JitCall::DestructorCall make_dtor_wrapper(compat::Interpreter& interp, return (JitCall::DestructorCall)F; } #undef DEBUG_TYPE -} // namespace +} // namespace CppImpl // End of JitCall Helper Functions CPPINTEROP_API JitCall MakeFunctionCallable(TInterp_t I, @@ -4290,4 +4290,4 @@ pid_t GetExecutorPID() { #endif -} // namespace CppStatic +} // namespace CppImpl diff --git a/lib/CppInterOp/CppDispatch.cpp b/lib/CppInterOp/Dispatch.cpp similarity index 81% rename from lib/CppInterOp/CppDispatch.cpp rename to lib/CppInterOp/Dispatch.cpp index ec1cdea33..be875c65d 100644 --- a/lib/CppInterOp/CppDispatch.cpp +++ b/lib/CppInterOp/Dispatch.cpp @@ -3,13 +3,13 @@ // author: Aaron Jomy //------------------------------------------------------------------------------ -#include +#include #include static const std::unordered_map INTEROP_FUNCTIONS = { -#define X(name, type) {#name, (__CPP_FUNC) static_cast(&CppStatic::name)}, +#define X(name, type) {#name, (__CPP_FUNC) static_cast(&CppImpl::name)}, CPPINTEROP_API_MAP #undef X }; @@ -18,11 +18,10 @@ static const std::unordered_map #undef MAP_ENTRY_OVERLOADED static inline __CPP_FUNC _cppinterop_get_proc_address(const char* funcName) { - auto it = INTEROP_FUNCTIONS.find(funcName); - return (it != INTEROP_FUNCTIONS.end()) ? it->second : nullptr; + auto it = INTEROP_FUNCTIONS.find(funcName); + return (it != INTEROP_FUNCTIONS.end()) ? it->second : nullptr; } void (*CppGetProcAddress(const unsigned char* procName))(void) { return _cppinterop_get_proc_address(reinterpret_cast(procName)); } - diff --git a/unittests/CppInterOp/DispatchAPITest.cpp b/unittests/CppInterOp/DispatchAPITest.cpp index 260ed4bfd..e799c6c30 100644 --- a/unittests/CppInterOp/DispatchAPITest.cpp +++ b/unittests/CppInterOp/DispatchAPITest.cpp @@ -1,4 +1,4 @@ -#include "CppInterOp/CppDispatch.h" +#include "CppInterOp/Dispatch.h" #include "Utils.h" From a422a941095c754369630cf3e6e60b0045c8b602 Mon Sep 17 00:00:00 2001 From: Aaron Jomy Date: Thu, 8 Jan 2026 15:06:45 +0100 Subject: [PATCH 5/9] Improve tests, rename loader API, add unload API --- include/CppInterOp/Dispatch.h | 10 ++++- unittests/CppInterOp/DispatchAPITest.cpp | 43 ++++++++++-------- unittests/CppInterOp/DyldDispatchTest.cpp | 55 ----------------------- 3 files changed, 32 insertions(+), 76 deletions(-) delete mode 100644 unittests/CppInterOp/DyldDispatchTest.cpp diff --git a/include/CppInterOp/Dispatch.h b/include/CppInterOp/Dispatch.h index 8fa45b70e..e3e759502 100644 --- a/include/CppInterOp/Dispatch.h +++ b/include/CppInterOp/Dispatch.h @@ -220,7 +220,7 @@ CPPINTEROP_API_MAP /// (RTLD_LOCAL) \param[in] customLibPath Optional custom path to /// libclangCppInterOp.so \returns true if initialization succeeded, false /// otherwise -inline bool init_functions(const char* customLibPath = nullptr) { +inline bool LoadDispatchAPI(const char* customLibPath = nullptr) { // trigger library loading if custom path provided std::cout << "[CppInterOp] Initializing CppInterOp API functions from " << (customLibPath ? customLibPath : "default library path") << '\n'; @@ -237,7 +237,7 @@ inline bool init_functions(const char* customLibPath = nullptr) { CPPINTEROP_API_MAP #undef X - // test to verify that critical (and consequently all) functions loaded + // Sanity check to verify that critical (and consequently all) functions loaded if (!GetInterpreter || !CreateInterpreter) { std::cerr << "[CppInterOp] Failed to load critical functions" << std::endl; return false; @@ -245,6 +245,12 @@ inline bool init_functions(const char* customLibPath = nullptr) { return true; } +// Unload all CppInterOp API functions +inline void UnloadDispatchAPI() { +#define X(name, type) name = nullptr; + CPPINTEROP_API_MAP +#undef X +} } // namespace Dispatch } // namespace CppInternal diff --git a/unittests/CppInterOp/DispatchAPITest.cpp b/unittests/CppInterOp/DispatchAPITest.cpp index e799c6c30..a74a0798e 100644 --- a/unittests/CppInterOp/DispatchAPITest.cpp +++ b/unittests/CppInterOp/DispatchAPITest.cpp @@ -8,18 +8,30 @@ using namespace TestUtils; using namespace llvm; using namespace clang; -TEST(DispatchAPITestTest, Basic_IsClassSymbolLookup) { - CppAPIType::IsClass IsClassFn = reinterpret_cast( - dlGetProcAddress("IsClass", CPPINTEROP_LIB_DIR)); - ASSERT_NE(IsClassFn, nullptr) << "failed to locate symbol: " << dlerror(); +#define X(name, type) CppAPIType::name Cpp::name = nullptr; +CPPINTEROP_API_MAP +#undef X + +class DispatchAPITest : public ::testing::Test { +protected: + static void SetUpTestSuite() { + if (!Cpp::LoadDispatchAPI(CPPINTEROP_LIB_DIR)) + GTEST_FAIL(); + } + static void TearDownTestSuite() { + Cpp::UnloadDispatchAPI(); + } +}; + +TEST_F(DispatchAPITest, Basic_IsClassSymbolLookup) { std::vector Decls; GetAllTopLevelDecls("namespace N {} class C{}; int I;", Decls); - EXPECT_FALSE(IsClassFn(Decls[0])); - EXPECT_TRUE(IsClassFn(Decls[1])); - EXPECT_FALSE(IsClassFn(Decls[2])); + EXPECT_FALSE(Cpp::IsClass(Decls[0])); + EXPECT_TRUE(Cpp::IsClass(Decls[1])); + EXPECT_FALSE(Cpp::IsClass(Decls[2])); } -TEST(DispatchAPITestTest, Basic_Demangle) { +TEST_F(DispatchAPITest, Basic_Demangle) { std::string code = R"( int add(int x, int y) { return x + y; } @@ -38,18 +50,11 @@ TEST(DispatchAPITestTest, Basic_Demangle) { compat::maybeMangleDeclName(Add_int, mangled_add_int); compat::maybeMangleDeclName(Add_double, mangled_add_double); - // CppAPIType:: gives us the specific function pointer types - CppAPIType::Demangle DemangleFn = reinterpret_cast( - dlGetProcAddress("Demangle", CPPINTEROP_LIB_DIR)); - CppAPIType::GetQualifiedCompleteName GetQualifiedCompleteNameFn = - reinterpret_cast( - dlGetProcAddress("GetQualifiedCompleteName")); + std::string demangled_add_int = Cpp::Demangle(mangled_add_int); + std::string demangled_add_double = Cpp::Demangle(mangled_add_double); - std::string demangled_add_int = DemangleFn(mangled_add_int); - std::string demangled_add_double = DemangleFn(mangled_add_double); - - EXPECT_NE(demangled_add_int.find(GetQualifiedCompleteNameFn(Decls[0])), + EXPECT_NE(demangled_add_int.find(Cpp::GetQualifiedCompleteName(Decls[0])), std::string::npos); - EXPECT_NE(demangled_add_double.find(GetQualifiedCompleteNameFn(Decls[1])), + EXPECT_NE(demangled_add_double.find(Cpp::GetQualifiedCompleteName(Decls[1])), std::string::npos); } diff --git a/unittests/CppInterOp/DyldDispatchTest.cpp b/unittests/CppInterOp/DyldDispatchTest.cpp deleted file mode 100644 index 58c3cf56a..000000000 --- a/unittests/CppInterOp/DyldDispatchTest.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "Utils.h" - -#include "CppInterOp/CppInterOpDispatch.h" - -#include "gtest/gtest.h" - -using namespace TestUtils; -using namespace llvm; -using namespace clang; - -TEST(DispatchAPITestTest, Basic_IsClassSymbolLookup) { - CppAPIType::IsClass IsClassFn = reinterpret_cast( - dlGetProcAddress("IsClass", CPPINTEROP_LIB_DIR)); - ASSERT_NE(IsClassFn, nullptr) << "failed to locate symbol: " << dlerror(); - std::vector Decls; - GetAllTopLevelDecls("namespace N {} class C{}; int I;", Decls); - EXPECT_FALSE(IsClassFn(Decls[0])); - EXPECT_TRUE(IsClassFn(Decls[1])); - EXPECT_FALSE(IsClassFn(Decls[2])); -} - -TEST(DispatchAPITestTest, Basic_Demangle) { - - std::string code = R"( - int add(int x, int y) { return x + y; } - int add(double x, double y) { return x + y; } - )"; - - std::vector Decls; - GetAllTopLevelDecls(code, Decls); - EXPECT_EQ(Decls.size(), 2); - - auto Add_int = clang::GlobalDecl(static_cast(Decls[0])); - auto Add_double = clang::GlobalDecl(static_cast(Decls[1])); - - std::string mangled_add_int; - std::string mangled_add_double; - compat::maybeMangleDeclName(Add_int, mangled_add_int); - compat::maybeMangleDeclName(Add_double, mangled_add_double); - - // CppAPIType:: gives us the specific function pointer types - CppAPIType::Demangle DemangleFn = reinterpret_cast( - dlGetProcAddress("Demangle", CPPINTEROP_LIB_DIR)); - CppAPIType::GetQualifiedCompleteName GetQualifiedCompleteNameFn = - reinterpret_cast( - dlGetProcAddress("GetQualifiedCompleteName")); - - std::string demangled_add_int = DemangleFn(mangled_add_int); - std::string demangled_add_double = DemangleFn(mangled_add_double); - - EXPECT_NE(demangled_add_int.find(GetQualifiedCompleteNameFn(Decls[0])), - std::string::npos); - EXPECT_NE(demangled_add_double.find(GetQualifiedCompleteNameFn(Decls[1])), - std::string::npos); -} From 94b5d94a2730d2676a4d3cefec15bce8b9132807 Mon Sep 17 00:00:00 2001 From: Aaron Jomy Date: Fri, 9 Jan 2026 17:42:57 +0100 Subject: [PATCH 6/9] Review comments, code optimizations and other improvements --- include/CppInterOp/Dispatch.h | 360 +++++++++++++++++----------------- lib/CppInterOp/Dispatch.cpp | 25 +-- 2 files changed, 187 insertions(+), 198 deletions(-) diff --git a/include/CppInterOp/Dispatch.h b/include/CppInterOp/Dispatch.h index e3e759502..9ac2193a0 100644 --- a/include/CppInterOp/Dispatch.h +++ b/include/CppInterOp/Dispatch.h @@ -1,29 +1,35 @@ -//--------------------------------------------------------------------*- C++ -*- -// CppInterOp Dispatch Mechanism -// author: Aaron Jomy +//===--- Dispatch.h - CppInterOp's API Dispatch Mechanism ---*- C++ -*-===// +// +// Part of the compiler-research project, under the Apache License v2.0 with +// LLVM Exceptions. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// //===----------------------------------------------------------------------===// // // Defines the mechanism which enables dispatching of the CppInterOp API -// without linking to it, preventing any LLVM or Clang symbols from being leaked -// into the client application. +// without linking, preventing any LLVM or Clang symbols from being leaked +// into the client application. This is achieved using a symbol-address table +// and an address lookup through a C symbol allowing clients to dlopen CppInterOp +// with RTLD_LOCAL, and automatically assign the API during runtime. // //===----------------------------------------------------------------------===// + + #ifndef CPPINTEROP_DISPATCH_H #define CPPINTEROP_DISPATCH_H -#include -#include -#include -#include -#include - #ifdef CPPINTEROP_CPPINTEROP_H -#error "To use the Dispatch mechanism, do not include CppInterOp.h" +#error "To use the Dispatch mechanism, do not include CppInterOp.h directly." #endif #include -using __CPP_FUNC = void (*)(); +#include +#include +#include +#include + +using CppFnPtrTy = void (*)(); ///\param[in] procname - the name of the FunctionEntry in the symbol lookup /// table. @@ -35,174 +41,162 @@ extern "C" CPPINTEROP_API void ( // macro that allows declaration and loading of all CppInterOp API functions in // a consistent way. This is used as our dispatched API list, along with the // name-address pair table -#define CPPINTEROP_API_MAP \ - X(CreateInterpreter, decltype(&CppImpl::CreateInterpreter)) \ - X(GetInterpreter, decltype(&CppImpl::GetInterpreter)) \ - X(Process, decltype(&CppImpl::Process)) \ - X(GetResourceDir, decltype(&CppImpl::GetResourceDir)) \ - X(AddIncludePath, decltype(&CppImpl::AddIncludePath)) \ - X(LoadLibrary, decltype(&CppImpl::LoadLibrary)) \ - X(Declare, decltype(&CppImpl::Declare)) \ - X(DeleteInterpreter, decltype(&CppImpl::DeleteInterpreter)) \ - X(IsNamespace, decltype(&CppImpl::IsNamespace)) \ - X(ObjToString, decltype(&CppImpl::ObjToString)) \ - X(GetQualifiedCompleteName, decltype(&CppImpl::GetQualifiedCompleteName)) \ - X(GetValueKind, decltype(&CppImpl::GetValueKind)) \ - X(GetNonReferenceType, decltype(&CppImpl::GetNonReferenceType)) \ - X(IsEnumType, decltype(&CppImpl::IsEnumType)) \ - X(GetIntegerTypeFromEnumType, \ +#define CPPINTEROP_API_TABLE \ + DISPATCH_API(CreateInterpreter, decltype(&CppImpl::CreateInterpreter)) \ + DISPATCH_API(GetInterpreter, decltype(&CppImpl::GetInterpreter)) \ + DISPATCH_API(Process, decltype(&CppImpl::Process)) \ + DISPATCH_API(GetResourceDir, decltype(&CppImpl::GetResourceDir)) \ + DISPATCH_API(AddIncludePath, decltype(&CppImpl::AddIncludePath)) \ + DISPATCH_API(LoadLibrary, decltype(&CppImpl::LoadLibrary)) \ + DISPATCH_API(Declare, decltype(&CppImpl::Declare)) \ + DISPATCH_API(DeleteInterpreter, decltype(&CppImpl::DeleteInterpreter)) \ + DISPATCH_API(IsNamespace, decltype(&CppImpl::IsNamespace)) \ + DISPATCH_API(ObjToString, decltype(&CppImpl::ObjToString)) \ + DISPATCH_API(GetQualifiedCompleteName, decltype(&CppImpl::GetQualifiedCompleteName)) \ + DISPATCH_API(GetValueKind, decltype(&CppImpl::GetValueKind)) \ + DISPATCH_API(GetNonReferenceType, decltype(&CppImpl::GetNonReferenceType)) \ + DISPATCH_API(IsEnumType, decltype(&CppImpl::IsEnumType)) \ + DISPATCH_API(GetIntegerTypeFromEnumType, \ decltype(&CppImpl::GetIntegerTypeFromEnumType)) \ - X(GetReferencedType, decltype(&CppImpl::GetReferencedType)) \ - X(IsPointerType, decltype(&CppImpl::IsPointerType)) \ - X(GetPointeeType, decltype(&CppImpl::GetPointeeType)) \ - X(GetPointerType, decltype(&CppImpl::GetPointerType)) \ - X(IsReferenceType, decltype(&CppImpl::IsReferenceType)) \ - X(GetTypeAsString, decltype(&CppImpl::GetTypeAsString)) \ - X(GetCanonicalType, decltype(&CppImpl::GetCanonicalType)) \ - X(HasTypeQualifier, decltype(&CppImpl::HasTypeQualifier)) \ - X(RemoveTypeQualifier, decltype(&CppImpl::RemoveTypeQualifier)) \ - X(GetUnderlyingType, decltype(&CppImpl::GetUnderlyingType)) \ - X(IsRecordType, decltype(&CppImpl::IsRecordType)) \ - X(IsFunctionPointerType, decltype(&CppImpl::IsFunctionPointerType)) \ - X(GetVariableType, decltype(&CppImpl::GetVariableType)) \ - X(GetNamed, decltype(&CppImpl::GetNamed)) \ - X(GetScopeFromType, decltype(&CppImpl::GetScopeFromType)) \ - X(GetClassTemplateInstantiationArgs, \ + DISPATCH_API(GetReferencedType, decltype(&CppImpl::GetReferencedType)) \ + DISPATCH_API(IsPointerType, decltype(&CppImpl::IsPointerType)) \ + DISPATCH_API(GetPointeeType, decltype(&CppImpl::GetPointeeType)) \ + DISPATCH_API(GetPointerType, decltype(&CppImpl::GetPointerType)) \ + DISPATCH_API(IsReferenceType, decltype(&CppImpl::IsReferenceType)) \ + DISPATCH_API(GetTypeAsString, decltype(&CppImpl::GetTypeAsString)) \ + DISPATCH_API(GetCanonicalType, decltype(&CppImpl::GetCanonicalType)) \ + DISPATCH_API(HasTypeQualifier, decltype(&CppImpl::HasTypeQualifier)) \ + DISPATCH_API(RemoveTypeQualifier, decltype(&CppImpl::RemoveTypeQualifier)) \ + DISPATCH_API(GetUnderlyingType, decltype(&CppImpl::GetUnderlyingType)) \ + DISPATCH_API(IsRecordType, decltype(&CppImpl::IsRecordType)) \ + DISPATCH_API(IsFunctionPointerType, decltype(&CppImpl::IsFunctionPointerType)) \ + DISPATCH_API(GetVariableType, decltype(&CppImpl::GetVariableType)) \ + DISPATCH_API(GetNamed, decltype(&CppImpl::GetNamed)) \ + DISPATCH_API(GetScopeFromType, decltype(&CppImpl::GetScopeFromType)) \ + DISPATCH_API(GetClassTemplateInstantiationArgs, \ decltype(&CppImpl::GetClassTemplateInstantiationArgs)) \ - X(IsClass, decltype(&CppImpl::IsClass)) \ - X(GetType, decltype(&CppImpl::GetType)) \ - X(GetTypeFromScope, decltype(&CppImpl::GetTypeFromScope)) \ - X(GetComplexType, decltype(&CppImpl::GetComplexType)) \ - X(GetIntegerTypeFromEnumScope, \ + DISPATCH_API(IsClass, decltype(&CppImpl::IsClass)) \ + DISPATCH_API(GetType, decltype(&CppImpl::GetType)) \ + DISPATCH_API(GetTypeFromScope, decltype(&CppImpl::GetTypeFromScope)) \ + DISPATCH_API(GetComplexType, decltype(&CppImpl::GetComplexType)) \ + DISPATCH_API(GetIntegerTypeFromEnumScope, \ decltype(&CppImpl::GetIntegerTypeFromEnumScope)) \ - X(GetUnderlyingScope, decltype(&CppImpl::GetUnderlyingScope)) \ - X(GetScope, decltype(&CppImpl::GetScope)) \ - X(GetGlobalScope, decltype(&CppImpl::GetGlobalScope)) \ - X(GetScopeFromCompleteName, decltype(&CppImpl::GetScopeFromCompleteName)) \ - X(InstantiateTemplate, decltype(&CppImpl::InstantiateTemplate)) \ - X(GetParentScope, decltype(&CppImpl::GetParentScope)) \ - X(IsTemplate, decltype(&CppImpl::IsTemplate)) \ - X(IsTemplateSpecialization, decltype(&CppImpl::IsTemplateSpecialization)) \ - X(IsTypedefed, decltype(&CppImpl::IsTypedefed)) \ - X(IsClassPolymorphic, decltype(&CppImpl::IsClassPolymorphic)) \ - X(Demangle, decltype(&CppImpl::Demangle)) \ - X(SizeOf, decltype(&CppImpl::SizeOf)) \ - X(GetSizeOfType, decltype(&CppImpl::GetSizeOfType)) \ - X(IsBuiltin, decltype(&CppImpl::IsBuiltin)) \ - X(IsComplete, decltype(&CppImpl::IsComplete)) \ - X(Allocate, decltype(&CppImpl::Allocate)) \ - X(Deallocate, decltype(&CppImpl::Deallocate)) \ - X(Construct, decltype(&CppImpl::Construct)) \ - X(Destruct, decltype(&CppImpl::Destruct)) \ - X(IsAbstract, decltype(&CppImpl::IsAbstract)) \ - X(IsEnumScope, decltype(&CppImpl::IsEnumScope)) \ - X(IsEnumConstant, decltype(&CppImpl::IsEnumConstant)) \ - X(IsAggregate, decltype(&CppImpl::IsAggregate)) \ - X(HasDefaultConstructor, decltype(&CppImpl::HasDefaultConstructor)) \ - X(IsVariable, decltype(&CppImpl::IsVariable)) \ - X(GetAllCppNames, decltype(&CppImpl::GetAllCppNames)) \ - X(GetUsingNamespaces, decltype(&CppImpl::GetUsingNamespaces)) \ - X(GetCompleteName, decltype(&CppImpl::GetCompleteName)) \ - X(GetDestructor, decltype(&CppImpl::GetDestructor)) \ - X(IsVirtualMethod, decltype(&CppImpl::IsVirtualMethod)) \ - X(GetNumBases, decltype(&CppImpl::GetNumBases)) \ - X(GetName, decltype(&CppImpl::GetName)) \ - X(GetBaseClass, decltype(&CppImpl::GetBaseClass)) \ - X(IsSubclass, decltype(&CppImpl::IsSubclass)) \ - X(GetOperator, decltype(&CppImpl::GetOperator)) \ - X(GetFunctionReturnType, decltype(&CppImpl::GetFunctionReturnType)) \ - X(GetBaseClassOffset, decltype(&CppImpl::GetBaseClassOffset)) \ - X(GetClassMethods, decltype(&CppImpl::GetClassMethods)) \ - X(GetFunctionsUsingName, decltype(&CppImpl::GetFunctionsUsingName)) \ - X(GetFunctionNumArgs, decltype(&CppImpl::GetFunctionNumArgs)) \ - X(GetFunctionRequiredArgs, decltype(&CppImpl::GetFunctionRequiredArgs)) \ - X(GetFunctionArgName, decltype(&CppImpl::GetFunctionArgName)) \ - X(GetFunctionArgType, decltype(&CppImpl::GetFunctionArgType)) \ - X(GetFunctionArgDefault, decltype(&CppImpl::GetFunctionArgDefault)) \ - X(IsConstMethod, decltype(&CppImpl::IsConstMethod)) \ - X(GetFunctionTemplatedDecls, decltype(&CppImpl::GetFunctionTemplatedDecls)) \ - X(ExistsFunctionTemplate, decltype(&CppImpl::ExistsFunctionTemplate)) \ - X(IsTemplatedFunction, decltype(&CppImpl::IsTemplatedFunction)) \ - X(IsStaticMethod, decltype(&CppImpl::IsStaticMethod)) \ - X(GetClassTemplatedMethods, decltype(&CppImpl::GetClassTemplatedMethods)) \ - X(BestOverloadFunctionMatch, decltype(&CppImpl::BestOverloadFunctionMatch)) \ - X(GetOperatorFromSpelling, decltype(&CppImpl::GetOperatorFromSpelling)) \ - X(IsFunctionDeleted, decltype(&CppImpl::IsFunctionDeleted)) \ - X(IsPublicMethod, decltype(&CppImpl::IsPublicMethod)) \ - X(IsProtectedMethod, decltype(&CppImpl::IsProtectedMethod)) \ - X(IsPrivateMethod, decltype(&CppImpl::IsPrivateMethod)) \ - X(IsConstructor, decltype(&CppImpl::IsConstructor)) \ - X(IsDestructor, decltype(&CppImpl::IsDestructor)) \ - X(GetDatamembers, decltype(&CppImpl::GetDatamembers)) \ - X(GetStaticDatamembers, decltype(&CppImpl::GetStaticDatamembers)) \ - X(GetEnumConstantDatamembers, \ + DISPATCH_API(GetUnderlyingScope, decltype(&CppImpl::GetUnderlyingScope)) \ + DISPATCH_API(GetScope, decltype(&CppImpl::GetScope)) \ + DISPATCH_API(GetGlobalScope, decltype(&CppImpl::GetGlobalScope)) \ + DISPATCH_API(GetScopeFromCompleteName, decltype(&CppImpl::GetScopeFromCompleteName)) \ + DISPATCH_API(InstantiateTemplate, decltype(&CppImpl::InstantiateTemplate)) \ + DISPATCH_API(GetParentScope, decltype(&CppImpl::GetParentScope)) \ + DISPATCH_API(IsTemplate, decltype(&CppImpl::IsTemplate)) \ + DISPATCH_API(IsTemplateSpecialization, decltype(&CppImpl::IsTemplateSpecialization)) \ + DISPATCH_API(IsTypedefed, decltype(&CppImpl::IsTypedefed)) \ + DISPATCH_API(IsClassPolymorphic, decltype(&CppImpl::IsClassPolymorphic)) \ + DISPATCH_API(Demangle, decltype(&CppImpl::Demangle)) \ + DISPATCH_API(SizeOf, decltype(&CppImpl::SizeOf)) \ + DISPATCH_API(GetSizeOfType, decltype(&CppImpl::GetSizeOfType)) \ + DISPATCH_API(IsBuiltin, decltype(&CppImpl::IsBuiltin)) \ + DISPATCH_API(IsComplete, decltype(&CppImpl::IsComplete)) \ + DISPATCH_API(Allocate, decltype(&CppImpl::Allocate)) \ + DISPATCH_API(Deallocate, decltype(&CppImpl::Deallocate)) \ + DISPATCH_API(Construct, decltype(&CppImpl::Construct)) \ + DISPATCH_API(Destruct, decltype(&CppImpl::Destruct)) \ + DISPATCH_API(IsAbstract, decltype(&CppImpl::IsAbstract)) \ + DISPATCH_API(IsEnumScope, decltype(&CppImpl::IsEnumScope)) \ + DISPATCH_API(IsEnumConstant, decltype(&CppImpl::IsEnumConstant)) \ + DISPATCH_API(IsAggregate, decltype(&CppImpl::IsAggregate)) \ + DISPATCH_API(HasDefaultConstructor, decltype(&CppImpl::HasDefaultConstructor)) \ + DISPATCH_API(IsVariable, decltype(&CppImpl::IsVariable)) \ + DISPATCH_API(GetAllCppNames, decltype(&CppImpl::GetAllCppNames)) \ + DISPATCH_API(GetUsingNamespaces, decltype(&CppImpl::GetUsingNamespaces)) \ + DISPATCH_API(GetCompleteName, decltype(&CppImpl::GetCompleteName)) \ + DISPATCH_API(GetDestructor, decltype(&CppImpl::GetDestructor)) \ + DISPATCH_API(IsVirtualMethod, decltype(&CppImpl::IsVirtualMethod)) \ + DISPATCH_API(GetNumBases, decltype(&CppImpl::GetNumBases)) \ + DISPATCH_API(GetName, decltype(&CppImpl::GetName)) \ + DISPATCH_API(GetBaseClass, decltype(&CppImpl::GetBaseClass)) \ + DISPATCH_API(IsSubclass, decltype(&CppImpl::IsSubclass)) \ + DISPATCH_API(GetOperator, decltype(&CppImpl::GetOperator)) \ + DISPATCH_API(GetFunctionReturnType, decltype(&CppImpl::GetFunctionReturnType)) \ + DISPATCH_API(GetBaseClassOffset, decltype(&CppImpl::GetBaseClassOffset)) \ + DISPATCH_API(GetClassMethods, decltype(&CppImpl::GetClassMethods)) \ + DISPATCH_API(GetFunctionsUsingName, decltype(&CppImpl::GetFunctionsUsingName)) \ + DISPATCH_API(GetFunctionNumArgs, decltype(&CppImpl::GetFunctionNumArgs)) \ + DISPATCH_API(GetFunctionRequiredArgs, decltype(&CppImpl::GetFunctionRequiredArgs)) \ + DISPATCH_API(GetFunctionArgName, decltype(&CppImpl::GetFunctionArgName)) \ + DISPATCH_API(GetFunctionArgType, decltype(&CppImpl::GetFunctionArgType)) \ + DISPATCH_API(GetFunctionArgDefault, decltype(&CppImpl::GetFunctionArgDefault)) \ + DISPATCH_API(IsConstMethod, decltype(&CppImpl::IsConstMethod)) \ + DISPATCH_API(GetFunctionTemplatedDecls, decltype(&CppImpl::GetFunctionTemplatedDecls)) \ + DISPATCH_API(ExistsFunctionTemplate, decltype(&CppImpl::ExistsFunctionTemplate)) \ + DISPATCH_API(IsTemplatedFunction, decltype(&CppImpl::IsTemplatedFunction)) \ + DISPATCH_API(IsStaticMethod, decltype(&CppImpl::IsStaticMethod)) \ + DISPATCH_API(GetClassTemplatedMethods, decltype(&CppImpl::GetClassTemplatedMethods)) \ + DISPATCH_API(BestOverloadFunctionMatch, decltype(&CppImpl::BestOverloadFunctionMatch)) \ + DISPATCH_API(GetOperatorFromSpelling, decltype(&CppImpl::GetOperatorFromSpelling)) \ + DISPATCH_API(IsFunctionDeleted, decltype(&CppImpl::IsFunctionDeleted)) \ + DISPATCH_API(IsPublicMethod, decltype(&CppImpl::IsPublicMethod)) \ + DISPATCH_API(IsProtectedMethod, decltype(&CppImpl::IsProtectedMethod)) \ + DISPATCH_API(IsPrivateMethod, decltype(&CppImpl::IsPrivateMethod)) \ + DISPATCH_API(IsConstructor, decltype(&CppImpl::IsConstructor)) \ + DISPATCH_API(IsDestructor, decltype(&CppImpl::IsDestructor)) \ + DISPATCH_API(GetDatamembers, decltype(&CppImpl::GetDatamembers)) \ + DISPATCH_API(GetStaticDatamembers, decltype(&CppImpl::GetStaticDatamembers)) \ + DISPATCH_API(GetEnumConstantDatamembers, \ decltype(&CppImpl::GetEnumConstantDatamembers)) \ - X(LookupDatamember, decltype(&CppImpl::LookupDatamember)) \ - X(IsLambdaClass, decltype(&CppImpl::IsLambdaClass)) \ - X(GetQualifiedName, decltype(&CppImpl::GetQualifiedName)) \ - X(GetVariableOffset, decltype(&CppImpl::GetVariableOffset)) \ - X(IsPublicVariable, decltype(&CppImpl::IsPublicVariable)) \ - X(IsProtectedVariable, decltype(&CppImpl::IsProtectedVariable)) \ - X(IsPrivateVariable, decltype(&CppImpl::IsPrivateVariable)) \ - X(IsStaticVariable, decltype(&CppImpl::IsStaticVariable)) \ - X(IsConstVariable, decltype(&CppImpl::IsConstVariable)) \ - X(GetDimensions, decltype(&CppImpl::GetDimensions)) \ - X(GetEnumConstants, decltype(&CppImpl::GetEnumConstants)) \ - X(GetEnumConstantType, decltype(&CppImpl::GetEnumConstantType)) \ - X(GetEnumConstantValue, decltype(&CppImpl::GetEnumConstantValue)) \ - X(DumpScope, decltype(&CppImpl::DumpScope)) \ - X(AddSearchPath, decltype(&CppImpl::AddSearchPath)) \ - X(Evaluate, decltype(&CppImpl::Evaluate)) \ - X(IsDebugOutputEnabled, decltype(&CppImpl::IsDebugOutputEnabled)) \ - X(EnableDebugOutput, decltype(&CppImpl::EnableDebugOutput)) \ - X(MakeFunctionCallable, CppImpl::JitCall (*)(CppImpl::TCppConstFunction_t)) \ - X(GetFunctionAddress, CppImpl::TCppFuncAddr_t (*)(CppImpl::TCppFunction_t)) \ - /*X(API_name, fnptr_ty)*/ + DISPATCH_API(LookupDatamember, decltype(&CppImpl::LookupDatamember)) \ + DISPATCH_API(IsLambdaClass, decltype(&CppImpl::IsLambdaClass)) \ + DISPATCH_API(GetQualifiedName, decltype(&CppImpl::GetQualifiedName)) \ + DISPATCH_API(GetVariableOffset, decltype(&CppImpl::GetVariableOffset)) \ + DISPATCH_API(IsPublicVariable, decltype(&CppImpl::IsPublicVariable)) \ + DISPATCH_API(IsProtectedVariable, decltype(&CppImpl::IsProtectedVariable)) \ + DISPATCH_API(IsPrivateVariable, decltype(&CppImpl::IsPrivateVariable)) \ + DISPATCH_API(IsStaticVariable, decltype(&CppImpl::IsStaticVariable)) \ + DISPATCH_API(IsConstVariable, decltype(&CppImpl::IsConstVariable)) \ + DISPATCH_API(GetDimensions, decltype(&CppImpl::GetDimensions)) \ + DISPATCH_API(GetEnumConstants, decltype(&CppImpl::GetEnumConstants)) \ + DISPATCH_API(GetEnumConstantType, decltype(&CppImpl::GetEnumConstantType)) \ + DISPATCH_API(GetEnumConstantValue, decltype(&CppImpl::GetEnumConstantValue)) \ + DISPATCH_API(DumpScope, decltype(&CppImpl::DumpScope)) \ + DISPATCH_API(AddSearchPath, decltype(&CppImpl::AddSearchPath)) \ + DISPATCH_API(Evaluate, decltype(&CppImpl::Evaluate)) \ + DISPATCH_API(IsDebugOutputEnabled, decltype(&CppImpl::IsDebugOutputEnabled)) \ + DISPATCH_API(EnableDebugOutput, decltype(&CppImpl::EnableDebugOutput)) \ + DISPATCH_API(BeginStdStreamCapture, decltype(&CppImpl::BeginStdStreamCapture)) \ + DISPATCH_API(MakeFunctionCallable, CppImpl::JitCall (*)(CppImpl::TCppConstFunction_t)) \ + DISPATCH_API(GetFunctionAddress, CppImpl::TCppFuncAddr_t (*)(CppImpl::TCppFunction_t)) \ + /*DISPATCH_API(API_name, fnptr_ty)*/ // TODO: implement overload that takes an existing opened DL handle inline void* dlGetProcAddress(const char* name, const char* customLibPath = nullptr) { - if (!name) - return nullptr; - - static std::once_flag loaded; - static void* handle = nullptr; - static void* (*getCppProcAddress)(const char*) = nullptr; - - std::call_once(loaded, [customLibPath]() { - // priority order: 1) custom path argument, or CPPINTEROP_LIBRARY_PATH via - // 2) cmake configured path 3) env vars - const char* libPath = customLibPath; - if (!libPath) { - libPath = std::getenv("CPPINTEROP_LIBRARY_PATH"); - } - - handle = dlopen(libPath, RTLD_LOCAL | RTLD_NOW); - if (!handle) { - std::cerr << "[CppInterOp] Failed to load library from " << libPath - << ": " << dlerror() << '\n'; - return; - } - - getCppProcAddress = reinterpret_cast( - dlsym(handle, "CppGetProcAddress")); - if (!getCppProcAddress) { - std::cerr << "[CppInterOp] Failed to find CppGetProcAddress: " - << dlerror() << '\n'; - dlclose(handle); - handle = nullptr; + if (!name) return nullptr; + + static std::once_flag init; + static void* (*getProc)(const char*) = nullptr; + + // this is currently not tested in a multiple thread/process setup + std::call_once(init, [customLibPath]() { + const char* path = customLibPath ? customLibPath : std::getenv("CPPINTEROP_LIBRARY_PATH"); + if (!path) return; + + void* handle = dlopen(path, RTLD_LOCAL | RTLD_NOW); + if (handle) { + //NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + getProc = reinterpret_cast( + dlsym(handle, "CppGetProcAddress")); + if (!getProc) dlclose(handle); } }); - return getCppProcAddress ? getCppProcAddress(name) : nullptr; + return getProc ? getProc(name) : nullptr; } -// Used for the extern clauses below +// CppAPIType is used for the extern clauses below // FIXME: drop the using clauses namespace CppAPIType { -#define X(name, type) using name = type; -CPPINTEROP_API_MAP -#undef X +#define DISPATCH_API(name, type) using name = type; +CPPINTEROP_API_TABLE +#undef DISPATCH_API } // end namespace CppAPIType namespace CppInternal { @@ -212,32 +206,33 @@ namespace Dispatch { // into a separate namespace and only use that scope (CppImpl::Types) using namespace CppImpl; -#define X(name, type) extern CppAPIType::name name; -CPPINTEROP_API_MAP -#undef X +// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) +#define DISPATCH_API(name, type) extern CppAPIType::name name; +CPPINTEROP_API_TABLE +#undef DISPATCH_API +// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) /// Initialize all CppInterOp API from the dynamically loaded library -/// (RTLD_LOCAL) \param[in] customLibPath Optional custom path to -/// libclangCppInterOp.so \returns true if initialization succeeded, false -/// otherwise +/// (RTLD_LOCAL) +/// \param[in] customLibPath Optional custom path to libclangCppInterOp +/// \returns true if initialization succeeded, false otherwise inline bool LoadDispatchAPI(const char* customLibPath = nullptr) { - // trigger library loading if custom path provided - std::cout << "[CppInterOp] Initializing CppInterOp API functions from " + std::cout << "[CppInterOp Dispatch] Loading CppInterOp API from " << (customLibPath ? customLibPath : "default library path") << '\n'; if (customLibPath) { void* test = dlGetProcAddress("GetInterpreter", customLibPath); if (!test) { - std::cerr << "[CppInterOp] Failed to initialize with custom path: " + std::cerr << "[CppInterOp Dispatch] Failed to load API from: " << customLibPath << '\n'; return false; } } -#define X(name, type) name = reinterpret_cast(dlGetProcAddress(#name)); - CPPINTEROP_API_MAP -#undef X +#define DISPATCH_API(name, type) name = reinterpret_cast(dlGetProcAddress(#name)); + CPPINTEROP_API_TABLE +#undef DISPATCH_API - // Sanity check to verify that critical (and consequently all) functions loaded + // Sanity check to verify that critical (and consequently all) functions are loaded if (!GetInterpreter || !CreateInterpreter) { std::cerr << "[CppInterOp] Failed to load critical functions" << std::endl; return false; @@ -245,11 +240,12 @@ inline bool LoadDispatchAPI(const char* customLibPath = nullptr) { return true; } + // Unload all CppInterOp API functions inline void UnloadDispatchAPI() { -#define X(name, type) name = nullptr; - CPPINTEROP_API_MAP -#undef X +#define DISPATCH_API(name, type) name = nullptr; + CPPINTEROP_API_TABLE +#undef DISPATCH_API } } // namespace Dispatch } // namespace CppInternal diff --git a/lib/CppInterOp/Dispatch.cpp b/lib/CppInterOp/Dispatch.cpp index be875c65d..4abbb889e 100644 --- a/lib/CppInterOp/Dispatch.cpp +++ b/lib/CppInterOp/Dispatch.cpp @@ -1,25 +1,18 @@ -//------------------------------------------------------------------------------ -// CppInterOp Dispatch Implementation -// author: Aaron Jomy -//------------------------------------------------------------------------------ - #include +#include #include -static const std::unordered_map - INTEROP_FUNCTIONS = { -#define X(name, type) {#name, (__CPP_FUNC) static_cast(&CppImpl::name)}, - CPPINTEROP_API_MAP -#undef X +static const std::unordered_map + DispatchMap = { +#define DISPATCH_API(name, type) {#name, (CppFnPtrTy) static_cast(&CppImpl::name)}, + CPPINTEROP_API_TABLE +#undef DISPATCH_API }; -#undef MAP_ENTRY_SIMPLE -#undef MAP_ENTRY_OVERLOADED - -static inline __CPP_FUNC _cppinterop_get_proc_address(const char* funcName) { - auto it = INTEROP_FUNCTIONS.find(funcName); - return (it != INTEROP_FUNCTIONS.end()) ? it->second : nullptr; +static inline CppFnPtrTy _cppinterop_get_proc_address(const char* funcName) { + auto it = DispatchMap.find(funcName); + return (it != DispatchMap.end()) ? it->second : nullptr; } void (*CppGetProcAddress(const unsigned char* procName))(void) { From 5f2350cf803ac5c928ee850d34be63140fad2249 Mon Sep 17 00:00:00 2001 From: Aaron Jomy Date: Fri, 9 Jan 2026 17:44:07 +0100 Subject: [PATCH 7/9] Make unittests Utils configureable for API Dispatch mode --- unittests/CppInterOp/Utils.cpp | 23 ++++++++++++++++++++--- unittests/CppInterOp/Utils.h | 13 ++++++++++--- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/unittests/CppInterOp/Utils.cpp b/unittests/CppInterOp/Utils.cpp index 39b9a166a..97a16905c 100644 --- a/unittests/CppInterOp/Utils.cpp +++ b/unittests/CppInterOp/Utils.cpp @@ -1,7 +1,5 @@ #include "Utils.h" -#include "CppInterOp/CppInterOp.h" - #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/Basic/Version.h" @@ -19,6 +17,25 @@ using namespace clang; using namespace llvm; +#if defined(ENABLE_DISPATCH_TESTS) +#define DISPATCH_API(name, type) CppAPIType::name Cpp::name = nullptr; +CPPINTEROP_API_TABLE +#undef DISPATCH_API +namespace { + struct DispatchInitializer { + DispatchInitializer() { + if (!Cpp::LoadDispatchAPI(CPPINTEROP_LIB_DIR)) { + std::abort(); + } + } + ~DispatchInitializer() { + Cpp::UnloadDispatchAPI(); + } + }; + static DispatchInitializer g_dispatch_init; +} +#endif + namespace TestUtils { TestConfig current_config; std::vector GetInterpreterArgs( @@ -35,7 +52,7 @@ void TestUtils::GetAllTopLevelDecls( const std::string& code, std::vector& Decls, bool filter_implicitGenerated /* = false */, const std::vector& interpreter_args /* = {} */) { - Cpp::CreateInterpreter(interpreter_args); + Cpp::CreateInterpreter(interpreter_args, {}); #ifdef CPPINTEROP_USE_CLING cling::Transaction *T = nullptr; Interp->declare(code, &T); diff --git a/unittests/CppInterOp/Utils.h b/unittests/CppInterOp/Utils.h index cb15e0ec4..154f95dcc 100644 --- a/unittests/CppInterOp/Utils.h +++ b/unittests/CppInterOp/Utils.h @@ -5,7 +5,14 @@ #include "clang-c/CXCppInterOp.h" #include "clang-c/CXString.h" -#include "CppInterOp/CppInterOp.h" + +#if defined(ENABLE_DISPATCH_TESTS) + #include "CppInterOp/Dispatch.h" + #define CPPINTEROP_TEST_MODE CppInterOpDispatchTest +#else + #include "CppInterOp/CppInterOp.h" + #define CPPINTEROP_TEST_MODE CppInterOpTest +#endif #include "llvm/Support/Valgrind.h" @@ -72,7 +79,7 @@ struct OutOfProcessJITConfig { // Define typed test fixture template -class CppInterOpTest : public ::testing::Test { +class CPPINTEROP_TEST_MODE : public ::testing::Test { protected: void SetUp() override { TestUtils::current_config = @@ -104,7 +111,7 @@ using CppInterOpTestTypes = ::testing::Types; #endif -TYPED_TEST_SUITE(CppInterOpTest, CppInterOpTestTypes, JITConfigNameGenerator); +TYPED_TEST_SUITE(CPPINTEROP_TEST_MODE, CppInterOpTestTypes, JITConfigNameGenerator); #endif // CPPINTEROP_UNITTESTS_LIBCPPINTEROP_UTILS_H From d87fc7520c96491f2090d2ff2afb4cf9170d658d Mon Sep 17 00:00:00 2001 From: Aaron Jomy Date: Fri, 9 Jan 2026 17:45:10 +0100 Subject: [PATCH 8/9] Add unittest executable that runs entirely in Dispatch mode Gives the mechanism complete coverage. Now runs CppInterOpTests and CppInterOpDispatchTests --- unittests/CMakeLists.txt | 12 ++++- unittests/CppInterOp/CMakeLists.txt | 39 +++++++++++---- unittests/CppInterOp/DispatchAPITest.cpp | 60 ------------------------ 3 files changed, 41 insertions(+), 70 deletions(-) delete mode 100644 unittests/CppInterOp/DispatchAPITest.cpp diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index af04597c6..6b9b56b1c 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -30,10 +30,20 @@ add_dependencies(CppInterOpUnitTests clangCppInterOp) set (TIMEOUT_VALUE 2400) function(add_cppinterop_unittest name) - add_executable(${name} EXCLUDE_FROM_ALL ${ARGN}) + list(REMOVE_ITEM ARGN "TEST_DISPATCH") + set(SOURCE_FILES ${ARGN}) + add_executable(${name} EXCLUDE_FROM_ALL ${SOURCE_FILES}) add_dependencies(CppInterOpUnitTests ${name}) target_include_directories(${name} PUBLIC ${CMAKE_CURRENT_BINARY_DIR} ${GTEST_INCLUDE_DIR}) set_property(TARGET ${name} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + + # Check if the test executable should run in the API dispatch mode. + if("TEST_DISPATCH" IN_LIST ARGV) + target_compile_definitions(${name} PRIVATE + ENABLE_DISPATCH_TESTS + CPPINTEROP_LIB_DIR="${CMAKE_BINARY_DIR}/lib/libclangCppInterOp${CMAKE_SHARED_LIBRARY_SUFFIX}" + ) + endif() if(WIN32) target_link_libraries(${name} PUBLIC ${ARG_LIBRARIES} ${gtest_libs}) set_property(TARGET ${name} APPEND_STRING PROPERTY LINK_FLAGS "${MSVC_EXPORTS}") diff --git a/unittests/CppInterOp/CMakeLists.txt b/unittests/CppInterOp/CMakeLists.txt index 24b68b071..4aa759f52 100644 --- a/unittests/CppInterOp/CMakeLists.txt +++ b/unittests/CppInterOp/CMakeLists.txt @@ -11,14 +11,6 @@ else() set(EXTRA_PATH_TEST_BINARIES /CppInterOpTests/unittests/bin/$/) endif() -# Add the DispatchAPITest only when building shared libraries -if (BUILD_SHARED_LIBS) - set_source_files_properties(DispatchAPITest.cpp PROPERTIES COMPILE_DEFINITIONS - "CPPINTEROP_LIB_DIR=\"${CMAKE_BINARY_DIR}/lib/libclangCppInterOp${CMAKE_SHARED_LIBRARY_SUFFIX}\"" - ) - list(APPEND EXTRA_TEST_SOURCE_FILES DispatchAPITest.cpp) -endif() - add_cppinterop_unittest(CppInterOpTests EnumReflectionTest.cpp FunctionReflectionTest.cpp @@ -28,10 +20,25 @@ add_cppinterop_unittest(CppInterOpTests TypeReflectionTest.cpp Utils.cpp VariableReflectionTest.cpp - DispatchAPITest.cpp ${EXTRA_TEST_SOURCE_FILES} ) +# Run tests with API Dispatch mode. Requires shared library build. +if(BUILD_SHARED_LIBS) + add_cppinterop_unittest(CppInterOpDispatchTests + EnumReflectionTest.cpp + FunctionReflectionTest.cpp + InterpreterTest.cpp + JitTest.cpp + ScopeReflectionTest.cpp + TypeReflectionTest.cpp + Utils.cpp + VariableReflectionTest.cpp + ${EXTRA_TEST_SOURCE_FILES} + TEST_DISPATCH + ) +endif() + if(EMSCRIPTEN) string(REPLACE "@" "@@" ESCAPED_SYSROOT_PATH "${SYSROOT_PATH}") # Explanation of Emscripten-specific link flags for CppInterOpTests: @@ -74,12 +81,23 @@ target_link_libraries(CppInterOpTests PRIVATE clangCppInterOp ) +# We only link the Dispatch tests for the necessary LLVM and Clang symbols +# referenced by CppInterOpInterpreter.h +target_link_libraries(CppInterOpDispatchTests + PRIVATE + clangCppInterOp +) set_output_directory(CppInterOpTests BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${EXTRA_PATH_TEST_BINARIES} LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${EXTRA_PATH_TEST_BINARIES} ) +set_output_directory(CppInterOpDispatchTests + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${EXTRA_PATH_TEST_BINARIES} + LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${EXTRA_PATH_TEST_BINARIES} +) + if(NOT WIN32) set_source_files_properties(VariableReflectionTest.cpp PROPERTIES COMPILE_FLAGS "-Wno-pedantic" @@ -90,6 +108,7 @@ set_source_files_properties(InterpreterTest.cpp PROPERTIES COMPILE_DEFINITIONS "LLVM_BINARY_DIR=\"${LLVM_BINARY_DIR}\"" ) export_executable_symbols(CppInterOpTests) +export_executable_symbols(CppInterOpDispatchTests) unset(LLVM_LINK_COMPONENTS) @@ -128,9 +147,11 @@ endif() if (EMSCRIPTEN) if (BUILD_SHARED_LIBS) target_compile_definitions(CppInterOpTests PRIVATE "EMSCRIPTEN_SHARED_LIBRARY") + target_compile_definitions(CppInterOpDispatchTests PRIVATE "EMSCRIPTEN_SHARED_LIBRARY") target_compile_definitions(DynamicLibraryManagerTests PRIVATE "EMSCRIPTEN_SHARED_LIBRARY") else() target_compile_definitions(CppInterOpTests PRIVATE "EMSCRIPTEN_STATIC_LIBRARY") + target_compile_definitions(CppInterOpDispatchTests PRIVATE "EMSCRIPTEN_STATIC_LIBRARY") target_compile_definitions(DynamicLibraryManagerTests PRIVATE "EMSCRIPTEN_STATIC_LIBRARY") endif() endif() diff --git a/unittests/CppInterOp/DispatchAPITest.cpp b/unittests/CppInterOp/DispatchAPITest.cpp deleted file mode 100644 index a74a0798e..000000000 --- a/unittests/CppInterOp/DispatchAPITest.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "CppInterOp/Dispatch.h" - -#include "Utils.h" - -#include "gtest/gtest.h" - -using namespace TestUtils; -using namespace llvm; -using namespace clang; - -#define X(name, type) CppAPIType::name Cpp::name = nullptr; -CPPINTEROP_API_MAP -#undef X - -class DispatchAPITest : public ::testing::Test { -protected: - static void SetUpTestSuite() { - if (!Cpp::LoadDispatchAPI(CPPINTEROP_LIB_DIR)) - GTEST_FAIL(); - } - static void TearDownTestSuite() { - Cpp::UnloadDispatchAPI(); - } -}; - -TEST_F(DispatchAPITest, Basic_IsClassSymbolLookup) { - std::vector Decls; - GetAllTopLevelDecls("namespace N {} class C{}; int I;", Decls); - EXPECT_FALSE(Cpp::IsClass(Decls[0])); - EXPECT_TRUE(Cpp::IsClass(Decls[1])); - EXPECT_FALSE(Cpp::IsClass(Decls[2])); -} - -TEST_F(DispatchAPITest, Basic_Demangle) { - - std::string code = R"( - int add(int x, int y) { return x + y; } - int add(double x, double y) { return x + y; } - )"; - - std::vector Decls; - GetAllTopLevelDecls(code, Decls); - EXPECT_EQ(Decls.size(), 2); - - auto Add_int = clang::GlobalDecl(static_cast(Decls[0])); - auto Add_double = clang::GlobalDecl(static_cast(Decls[1])); - - std::string mangled_add_int; - std::string mangled_add_double; - compat::maybeMangleDeclName(Add_int, mangled_add_int); - compat::maybeMangleDeclName(Add_double, mangled_add_double); - - std::string demangled_add_int = Cpp::Demangle(mangled_add_int); - std::string demangled_add_double = Cpp::Demangle(mangled_add_double); - - EXPECT_NE(demangled_add_int.find(Cpp::GetQualifiedCompleteName(Decls[0])), - std::string::npos); - EXPECT_NE(demangled_add_double.find(Cpp::GetQualifiedCompleteName(Decls[1])), - std::string::npos); -} From f8d869acbdcb8acd9309a56de60b0e66cb51ac6d Mon Sep 17 00:00:00 2001 From: Aaron Jomy Date: Fri, 9 Jan 2026 17:47:34 +0100 Subject: [PATCH 9/9] Add default arguments, use dynamic names in the test fixtures This patch also improves the readability of the test run log: ``` 2: [ RUN ] CppInterOpDispatchTest/InProcessJIT.Interpreter_IncludePaths 2: [ OK ] CppInterOpDispatchTest/InProcessJIT.Interpreter_IncludePaths (0 ms) 2: [ RUN ] CppInterOpDispatchTest/InProcessJIT.Interpreter_CodeCompletion 2: [ OK ] CppInterOpDispatchTest/InProcessJIT.Interpreter_CodeCompletion (86 ms) 2: [ RUN ] CppInterOpDispatchTest/InProcessJIT.Interpreter_ExternalInterpreter 2: [ OK ] CppInterOpDispatchTest/InProcessJIT.Interpreter_ExternalInterpreter (1123 ms) 2: [ RUN ] CppInterOpDispatchTest/InProcessJIT.Jit_InsertOrReplaceJitSymbol 2: [ OK ] CppInterOpDispatchTest/InProcessJIT.Jit_InsertOrReplaceJitSymbol (56 ms) 2: [ RUN ] CppInterOpDispatchTest/InProcessJIT.Jit_StreamRedirect 2: [ OK ] CppInterOpDispatchTest/InProcessJIT.Jit_StreamRedirect (0 ms) 2: [ RUN ] CppInterOpDispatchTest/InProcessJIT.Jit_StreamRedirectJIT 2: [ OK ] CppInterOpDispatchTest/InProcessJIT.Jit_StreamRedirectJIT (154 ms) 2: [ RUN ] CppInterOpDispatchTest/InProcessJIT.ScopeReflection_IsEnumScope 2: [ OK ] CppInterOpDispatchTest/InProcessJIT.ScopeReflection_IsEnumScope (21 ms) 2: [ RUN ] CppInterOpDispatchTest/InProcessJIT.ScopeReflection_IsEnumConstant ``` instead of: ``` 2: [ RUN ] CppInterOpDispatchTest/InProcessJIT.InterpreterTestIncludePaths 2: [ OK ] CppInterOpDispatchTest/InProcessJIT.InterpreterTestIncludePaths (0 ms) 2: [ RUN ] CppInterOpDispatchTest/InProcessJIT.InterpreterTestCodeCompletion 2: [ OK ] CppInterOpDispatchTest/InProcessJIT.InterpreterTestCodeCompletion (86 ms) 2: [ RUN ] CppInterOpDispatchTest/InProcessJIT.InterpreterTestExternalInterpreter 2: [ OK ] CppInterOpDispatchTest/InProcessJIT.InterpreterTestExternalInterpreter (1123 ms) 2: [ RUN ] CppInterOpDispatchTest/InProcessJIT.JitTestInsertOrReplaceJitSymbol 2: [ OK ] CppInterOpDispatchTest/InProcessJIT.JitTestInsertOrReplaceJitSymbol (56 ms) 2: [ RUN ] CppInterOpDispatchTest/InProcessJIT.JitTestStreamRedirect 2: [ OK ] CppInterOpDispatchTest/InProcessJIT.JitTestStreamRedirect (0 ms) 2: [ RUN ] CppInterOpDispatchTest/InProcessJIT.JitTestStreamRedirectJIT 2: [ OK ] CppInterOpDispatchTest/InProcessJIT.JitTestStreamRedirectJIT (154 ms) 2: [ RUN ] CppInterOpDispatchTest/InProcessJIT.ScopeReflectionTestIsEnumScope 2: [ OK ] CppInterOpDispatchTest/InProcessJIT.ScopeReflectionTestIsEnumScope (21 ms) 2: [ RUN ] CppInterOpDispatchTest/InProcessJIT.ScopeReflectionTestIsEnumConstant ``` We repeated the word "Test" twice and the lack of a spacer made it hard to read. Since this patch changes the TYPED_TEST line to use `CPPINTEROP_TEST_MODE` instead of `CppInterOpTest` this is a good opportunity to improve this without bloating the history --- unittests/CppInterOp/CUDATest.cpp | 8 +- .../CppInterOp/DynamicLibraryManagerTest.cpp | 4 +- unittests/CppInterOp/EnumReflectionTest.cpp | 18 +- .../CppInterOp/FunctionReflectionTest.cpp | 320 +++++++++--------- unittests/CppInterOp/InterpreterTest.cpp | 60 ++-- unittests/CppInterOp/JitTest.cpp | 6 +- unittests/CppInterOp/ScopeReflectionTest.cpp | 130 +++---- unittests/CppInterOp/TypeReflectionTest.cpp | 58 ++-- .../CppInterOp/VariableReflectionTest.cpp | 131 ++++--- 9 files changed, 369 insertions(+), 366 deletions(-) diff --git a/unittests/CppInterOp/CUDATest.cpp b/unittests/CppInterOp/CUDATest.cpp index 45b41c94d..64951740d 100644 --- a/unittests/CppInterOp/CUDATest.cpp +++ b/unittests/CppInterOp/CUDATest.cpp @@ -17,7 +17,7 @@ static bool HasCudaSDK() { if (!Cpp::CreateInterpreter({}, {"--cuda"})) return false; return Cpp::Declare("__global__ void test_func() {}" - "test_func<<<1,1>>>();") == 0; + "test_func<<<1,1>>>();", false) == 0; }; static bool hasCuda = supportsCudaSDK(); return hasCuda; @@ -35,9 +35,9 @@ static bool HasCudaRuntime() { if (!Cpp::CreateInterpreter({}, {"--cuda"})) return false; if (Cpp::Declare("__global__ void test_func() {}" - "test_func<<<1,1>>>();")) + "test_func<<<1,1>>>();", false)) return false; - intptr_t result = Cpp::Evaluate("(bool)cudaGetLastError()"); + intptr_t result = Cpp::Evaluate("(bool)cudaGetLastError()", nullptr); return !(bool)result; }; static bool hasCuda = supportsCuda(); @@ -65,7 +65,7 @@ TEST(CUDATest, CUDAH) { GTEST_SKIP() << "Skipping CUDA tests as CUDA SDK not found"; Cpp::CreateInterpreter({}, {"--cuda"}); - bool success = !Cpp::Declare("#include "); + bool success = !Cpp::Declare("#include ", false); EXPECT_TRUE(success); } diff --git a/unittests/CppInterOp/DynamicLibraryManagerTest.cpp b/unittests/CppInterOp/DynamicLibraryManagerTest.cpp index ca17a16ad..ab3ca8125 100644 --- a/unittests/CppInterOp/DynamicLibraryManagerTest.cpp +++ b/unittests/CppInterOp/DynamicLibraryManagerTest.cpp @@ -20,7 +20,7 @@ std::string GetExecutablePath(const char* Argv0) { return llvm::sys::fs::getMainExecutable(Argv0, MainAddr); } -TYPED_TEST(CppInterOpTest, DynamicLibraryManagerTestSanity) { +TYPED_TEST(CPPINTEROP_TEST_MODE, DynamicLibraryManager_Sanity) { #ifdef EMSCRIPTEN GTEST_SKIP() << "Test fails for Emscipten builds"; #endif @@ -69,7 +69,7 @@ TYPED_TEST(CppInterOpTest, DynamicLibraryManagerTestSanity) { // EXPECT_FALSE(Cpp::GetFunctionAddress("ret_zero")); } -TYPED_TEST(CppInterOpTest, DynamicLibraryManagerTestBasicSymbolLookup) { +TYPED_TEST(CPPINTEROP_TEST_MODE, DynamicLibraryManager_BasicSymbolLookup) { #ifndef EMSCRIPTEN GTEST_SKIP() << "This test is only intended for Emscripten builds."; #else diff --git a/unittests/CppInterOp/EnumReflectionTest.cpp b/unittests/CppInterOp/EnumReflectionTest.cpp index 89f41dddf..19b58f3e7 100644 --- a/unittests/CppInterOp/EnumReflectionTest.cpp +++ b/unittests/CppInterOp/EnumReflectionTest.cpp @@ -12,7 +12,7 @@ using namespace TestUtils; using namespace llvm; using namespace clang; -TYPED_TEST(CppInterOpTest, EnumReflectionTestIsEnumType) { +TYPED_TEST(CPPINTEROP_TEST_MODE, EnumReflection_IsEnumType) { std::vector Decls; std::string code = R"( enum class E { @@ -40,7 +40,7 @@ TYPED_TEST(CppInterOpTest, EnumReflectionTestIsEnumType) { EXPECT_TRUE(Cpp::IsEnumType(Cpp::GetVariableType(Decls[5]))); } -TYPED_TEST(CppInterOpTest, EnumReflectionTestGetIntegerTypeFromEnumScope) { +TYPED_TEST(CPPINTEROP_TEST_MODE, EnumReflection_GetIntegerTypeFromEnumScope) { std::vector Decls; std::string code = R"( enum Switch : bool { @@ -90,7 +90,7 @@ TYPED_TEST(CppInterOpTest, EnumReflectionTestGetIntegerTypeFromEnumScope) { EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetIntegerTypeFromEnumScope(Decls[5])),"NULL TYPE"); } -TYPED_TEST(CppInterOpTest, EnumReflectionTestGetIntegerTypeFromEnumType) { +TYPED_TEST(CPPINTEROP_TEST_MODE, EnumReflection_GetIntegerTypeFromEnumType) { std::vector Decls; std::string code = R"( enum Switch : bool { @@ -150,7 +150,7 @@ TYPED_TEST(CppInterOpTest, EnumReflectionTestGetIntegerTypeFromEnumType) { EXPECT_EQ(get_int_type_from_enum_var(Decls[11]), "NULL TYPE"); // When a non Enum Type variable is used } -TYPED_TEST(CppInterOpTest, EnumReflectionTestGetEnumConstants) { +TYPED_TEST(CPPINTEROP_TEST_MODE, EnumReflection_GetEnumConstants) { std::vector Decls; std::string code = R"( enum ZeroEnum { @@ -194,7 +194,7 @@ TYPED_TEST(CppInterOpTest, EnumReflectionTestGetEnumConstants) { EXPECT_EQ(Cpp::GetEnumConstants(Decls[5]).size(), 0); } -TYPED_TEST(CppInterOpTest, EnumReflectionTestGetEnumConstantType) { +TYPED_TEST(CPPINTEROP_TEST_MODE, EnumReflection_GetEnumConstantType) { std::vector Decls; std::string code = R"( enum Enum0 { @@ -225,7 +225,7 @@ TYPED_TEST(CppInterOpTest, EnumReflectionTestGetEnumConstantType) { EXPECT_EQ(get_enum_constant_type_as_str(nullptr), "NULL TYPE"); } -TYPED_TEST(CppInterOpTest, EnumReflectionTestGetEnumConstantValue) { +TYPED_TEST(CPPINTEROP_TEST_MODE, EnumReflection_GetEnumConstantValue) { std::vector Decls; std::string code = R"( enum Counter { @@ -253,7 +253,7 @@ TYPED_TEST(CppInterOpTest, EnumReflectionTestGetEnumConstantValue) { EXPECT_EQ(Cpp::GetEnumConstantValue(Decls[1]), 0); // Checking value of non enum constant } -TYPED_TEST(CppInterOpTest, EnumReflectionTestGetEnums) { +TYPED_TEST(CPPINTEROP_TEST_MODE, EnumReflection_GetEnums) { std::string code = R"( enum Color { Red, @@ -302,8 +302,8 @@ TYPED_TEST(CppInterOpTest, EnumReflectionTestGetEnums) { Cpp::TCppScope_t myClass_scope = Cpp::GetScope("myClass", 0); Cpp::TCppScope_t unsupported_scope = Cpp::GetScope("myVariable", 0); - Cpp::GetEnums(globalscope,enumNames1); - Cpp::GetEnums(Animals_scope,enumNames2); + Cpp::GetEnums(globalscope, enumNames1); + Cpp::GetEnums(Animals_scope, enumNames2); Cpp::GetEnums(myClass_scope, enumNames3); Cpp::GetEnums(unsupported_scope, enumNames4); diff --git a/unittests/CppInterOp/FunctionReflectionTest.cpp b/unittests/CppInterOp/FunctionReflectionTest.cpp index 6e863a793..749603963 100644 --- a/unittests/CppInterOp/FunctionReflectionTest.cpp +++ b/unittests/CppInterOp/FunctionReflectionTest.cpp @@ -19,7 +19,11 @@ using namespace TestUtils; using namespace llvm; using namespace clang; -TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetClassMethods) { +// Reusable empty template args vector. In the dispatch mode, passing an empty initializer list {} +// does not work since the compiler cannot deduce the type for a function pointer +std::vector empty_templ_args = {}; + +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_GetClassMethods) { std::vector Decls; std::string code = R"( class A; @@ -171,7 +175,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetClassMethods) { clang_Interpreter_dispose(I); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestConstructorInGetClassMethods) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_ConstructorInGetClassMethods) { std::vector Decls; std::string code = R"( struct S { @@ -195,7 +199,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestConstructorInGetClassMethods) { EXPECT_TRUE(has_constructor(Decls[0])); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestHasDefaultConstructor) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_HasDefaultConstructor) { std::vector Decls; std::string code = R"( class A { @@ -236,7 +240,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestHasDefaultConstructor) { clang_Interpreter_dispose(I); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetDestructor) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_GetDestructor) { std::vector Decls; std::string code = R"( class A { @@ -272,7 +276,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetDestructor) { clang_Interpreter_dispose(I); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionsUsingName) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_GetFunctionsUsingName) { std::vector Decls; std::string code = R"( class A { @@ -316,7 +320,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionsUsingName) { EXPECT_EQ(get_number_of_funcs_using_name(Decls[2], ""), 0); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetClassDecls) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_GetClassDecls) { std::vector Decls, SubDecls; std::string code = R"( class MyTemplatedMethodClass { @@ -353,7 +357,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetClassDecls) { EXPECT_EQ(Cpp::GetName(methods[3]), Cpp::GetName(SubDecls[8])); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionTemplatedDecls) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_GetFunctionTemplatedDecls) { std::vector Decls, SubDecls; std::string code = R"( class MyTemplatedMethodClass { @@ -390,7 +394,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionTemplatedDecls) { EXPECT_EQ(Cpp::GetName(template_methods[3]), Cpp::GetName(SubDecls[6])); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionReturnType) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_GetFunctionReturnType) { std::vector Decls, SubDecls, TemplateSubDecls; std::string code = R"( namespace N { class C {}; } @@ -483,11 +487,11 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionReturnType) { std::vector args2 = {C.DoubleTy.getAsOpaquePtr()}; EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetFunctionReturnType(Cpp::GetNamed( - "func", Cpp::InstantiateTemplate(Decls[15], args2.data(), 1)))), + "func", Cpp::InstantiateTemplate(Decls[15], args2.data(), 1, false)))), "double"); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionNumArgs) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_GetFunctionNumArgs) { std::vector Decls, TemplateSubDecls; std::string code = R"( void f1() {} @@ -526,7 +530,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionNumArgs) { EXPECT_EQ(Cpp::GetFunctionNumArgs(TemplateSubDecls[3]), 3); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionRequiredArgs) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_GetFunctionRequiredArgs) { std::vector Decls, TemplateSubDecls; std::string code = R"( void f1() {} @@ -561,7 +565,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionRequiredArgs) { EXPECT_EQ(Cpp::GetFunctionRequiredArgs(TemplateSubDecls[3]), 2); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionArgType) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_GetFunctionArgType) { std::vector Decls; std::string code = R"( void f1(int i, double d, long l, char ch) {} @@ -581,7 +585,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionArgType) { EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetFunctionArgType(Decls[2], 0)), "NULL TYPE"); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionSignature) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_GetFunctionSignature) { std::vector Decls; std::string code = R"( class C { @@ -625,7 +629,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionSignature) { EXPECT_EQ(Cpp::GetFunctionSignature(nullptr), ""); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestIsTemplatedFunction) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_IsTemplatedFunction) { std::vector Decls; std::vector SubDeclsC1; std::string code = R"( @@ -665,7 +669,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestIsTemplatedFunction) { clang_Interpreter_dispose(I); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestExistsFunctionTemplate) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_ExistsFunctionTemplate) { std::vector Decls; std::string code = R"( template @@ -693,7 +697,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestExistsFunctionTemplate) { clang_Interpreter_dispose(I); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestInstantiateTemplateFunctionFromString) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_InstantiateTemplateFunctionFromString) { #if CLANG_VERSION_MAJOR == 18 && defined(CPPINTEROP_USE_CLING) && \ defined(_WIN32) && (defined(_M_ARM) || defined(_M_ARM64)) GTEST_SKIP() << "Test fails with Cling on Windows on ARM"; @@ -709,7 +713,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestInstantiateTemplateFunctionFrom EXPECT_TRUE(Instance1); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestInstantiateFunctionTemplate) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_InstantiateFunctionTemplate) { std::vector Decls; std::string code = R"( template T TrivialFnTemplate() { return T(); } @@ -720,7 +724,7 @@ template T TrivialFnTemplate() { return T(); } std::vector args1 = {C.IntTy.getAsOpaquePtr()}; auto Instance1 = Cpp::InstantiateTemplate(Decls[0], args1.data(), - /*type_size*/ args1.size()); + /*type_size*/ args1.size(), false); EXPECT_TRUE(isa((Decl*)Instance1)); FunctionDecl* FD = cast((Decl*)Instance1); FunctionDecl* FnTD1 = FD->getTemplateInstantiationPattern(); @@ -729,7 +733,7 @@ template T TrivialFnTemplate() { return T(); } EXPECT_TRUE(TA1.getAsType()->isIntegerType()); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestInstantiateTemplateMethod) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_InstantiateTemplateMethod) { std::vector Decls; std::string code = R"( class MyTemplatedMethodClass { @@ -748,7 +752,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestInstantiateTemplateMethod) { std::vector args1 = {C.IntTy.getAsOpaquePtr()}; auto Instance1 = Cpp::InstantiateTemplate(Decls[1], args1.data(), - /*type_size*/ args1.size()); + /*type_size*/ args1.size(), false); EXPECT_TRUE(isa((Decl*)Instance1)); FunctionDecl* FD = cast((Decl*)Instance1); FunctionDecl* FnTD1 = FD->getTemplateInstantiationPattern(); @@ -757,7 +761,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestInstantiateTemplateMethod) { EXPECT_TRUE(TA1.getAsType()->isIntegerType()); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestLookupConstructors) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_LookupConstructors) { if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; @@ -798,7 +802,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestLookupConstructors) { EXPECT_EQ(Cpp::GetFunctionSignature(ctors[3]), "MyClass::MyClass(T t)"); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetClassTemplatedMethods) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_GetClassTemplatedMethods) { if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; @@ -856,7 +860,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetClassTemplatedMethods) { "void MyClass::templatedStaticMethod(T param)"); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetClassTemplatedMethods_VariadicsAndOthers) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_GetClassTemplatedMethods_VariadicsAndOthers) { std::vector Decls; std::string code = R"( class MyClass { @@ -910,7 +914,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetClassTemplatedMethods_Variad "void MyClass::staticVariadic(T t, Args ...args)"); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestInstantiateVariadicFunction) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_InstantiateVariadicFunction) { std::vector Decls; std::string code = R"( class MyClass {}; @@ -928,7 +932,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestInstantiateVariadicFunction) { std::vector args1 = {C.DoubleTy.getAsOpaquePtr(), C.IntTy.getAsOpaquePtr()}; auto Instance1 = Cpp::InstantiateTemplate(Decls[1], args1.data(), - /*type_size*/ args1.size()); + /*type_size*/ args1.size(), false); EXPECT_TRUE(Cpp::IsTemplatedFunction(Instance1)); EXPECT_EQ(Cpp::GetFunctionSignature(Instance1), "template<> void VariadicFn<>(double args, int args)"); @@ -973,7 +977,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestInstantiateVariadicFunction) { "fixedParam, MyClass args, double args)"); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestBestOverloadFunctionMatch0) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_BestOverloadFunctionMatch0) { // make sure templates are not instantiated multiple times std::vector Decls; std::string code = R"( @@ -1015,15 +1019,15 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestBestOverloadFunctionMatch0) { EXPECT_EQ(fn, fn0); fn = Cpp::InstantiateTemplate(Decls[0], explicit_args1.data(), - explicit_args1.size()); + explicit_args1.size(), false); EXPECT_EQ(fn, fn0); fn = Cpp::InstantiateTemplate(Decls[0], explicit_args2.data(), - explicit_args2.size()); + explicit_args2.size(), false); EXPECT_EQ(fn, fn0); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestBestOverloadFunctionMatch1) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_BestOverloadFunctionMatch1) { std::vector Decls; std::string code = R"( class MyTemplatedMethodClass { @@ -1103,7 +1107,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestBestOverloadFunctionMatch1) { "template<> long MyTemplatedMethodClass::get_size<1, int>(int a)"); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestBestOverloadFunctionMatch2) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_BestOverloadFunctionMatch2) { std::vector Decls; std::string code = R"( template @@ -1139,12 +1143,12 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestBestOverloadFunctionMatch2) { std::vector args1 = {C.IntTy.getAsOpaquePtr()}; std::vector args2 = { - Cpp::GetVariableType(Cpp::GetNamed("a"))}; + Cpp::GetVariableType(Cpp::GetNamed("a", 0))}; std::vector args3 = {C.IntTy.getAsOpaquePtr(), C.IntTy.getAsOpaquePtr()}; std::vector args4 = { - Cpp::GetVariableType(Cpp::GetNamed("a")), - Cpp::GetVariableType(Cpp::GetNamed("a"))}; + Cpp::GetVariableType(Cpp::GetNamed("a", 0)), + Cpp::GetVariableType(Cpp::GetNamed("a", 0))}; std::vector args5 = {C.IntTy.getAsOpaquePtr(), C.DoubleTy.getAsOpaquePtr()}; @@ -1173,7 +1177,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestBestOverloadFunctionMatch2) { "void somefunc(int arg1, double arg2)"); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestBestOverloadFunctionMatch3) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_BestOverloadFunctionMatch3) { std::vector Decls; std::string code = R"( template @@ -1211,12 +1215,12 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestBestOverloadFunctionMatch3) { ASTContext& C = Interp->getCI()->getASTContext(); std::vector args1 = { - Cpp::GetVariableType(Cpp::GetNamed("a")), - Cpp::GetVariableType(Cpp::GetNamed("a"))}; + Cpp::GetVariableType(Cpp::GetNamed("a", 0)), + Cpp::GetVariableType(Cpp::GetNamed("a", 0))}; std::vector args2 = { - Cpp::GetVariableType(Cpp::GetNamed("a")), C.IntTy.getAsOpaquePtr()}; + Cpp::GetVariableType(Cpp::GetNamed("a", 0)), C.IntTy.getAsOpaquePtr()}; std::vector args3 = { - Cpp::GetVariableType(Cpp::GetNamed("a")), C.DoubleTy.getAsOpaquePtr()}; + Cpp::GetVariableType(Cpp::GetNamed("a", 0)), C.DoubleTy.getAsOpaquePtr()}; std::vector explicit_args; @@ -1229,13 +1233,13 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestBestOverloadFunctionMatch3) { candidates.clear(); Cpp::GetOperator( - Cpp::GetScopeFromType(Cpp::GetVariableType(Cpp::GetNamed("a"))), - Cpp::Operator::OP_Minus, candidates); + Cpp::GetScopeFromType(Cpp::GetVariableType(Cpp::GetNamed("a", 0))), + Cpp::Operator::OP_Minus, candidates, Cpp::OperatorArity::kBoth); EXPECT_EQ(candidates.size(), 1); std::vector args4 = { - Cpp::GetVariableType(Cpp::GetNamed("a"))}; + Cpp::GetVariableType(Cpp::GetNamed("a", 0))}; Cpp::TCppFunction_t func4 = Cpp::BestOverloadFunctionMatch(candidates, explicit_args, args4); @@ -1251,7 +1255,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestBestOverloadFunctionMatch3) { "template<> A A::operator-(A rhs)"); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestBestOverloadFunctionMatch4) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_BestOverloadFunctionMatch4) { std::vector Decls, SubDecls; std::string code = R"( template @@ -1288,13 +1292,13 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestBestOverloadFunctionMatch4) { std::vector args1 = {}; std::vector args2 = {C.IntTy.getAsOpaquePtr()}; std::vector args3 = { - Cpp::GetVariableType(Cpp::GetNamed("a"))}; + Cpp::GetVariableType(Cpp::GetNamed("a", 0))}; std::vector args4 = { - Cpp::GetVariableType(Cpp::GetNamed("a")), - Cpp::GetVariableType(Cpp::GetNamed("b"))}; + Cpp::GetVariableType(Cpp::GetNamed("a", 0)), + Cpp::GetVariableType(Cpp::GetNamed("b", 0))}; std::vector args5 = { - Cpp::GetVariableType(Cpp::GetNamed("a")), - Cpp::GetVariableType(Cpp::GetNamed("a"))}; + Cpp::GetVariableType(Cpp::GetNamed("a", 0)), + Cpp::GetVariableType(Cpp::GetNamed("a", 0))}; std::vector explicit_args1; std::vector explicit_args2 = {C.IntTy.getAsOpaquePtr(), @@ -1322,7 +1326,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestBestOverloadFunctionMatch4) { "template<> void B::fn(A x, A y)"); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestBestOverloadFunctionMatch5) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_BestOverloadFunctionMatch5) { std::vector Decls; std::string code = R"( template @@ -1346,7 +1350,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestBestOverloadFunctionMatch5) { }; Cpp::TCppScope_t callme = Cpp::InstantiateTemplate( - Decls[0], explicit_params.data(), explicit_params.size()); + Decls[0], explicit_params.data(), explicit_params.size(), false); EXPECT_TRUE(callme); std::vector arg_types = { @@ -1356,7 +1360,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestBestOverloadFunctionMatch5) { }; Cpp::TCppScope_t callback = - Cpp::BestOverloadFunctionMatch(candidates, {}, arg_types); + Cpp::BestOverloadFunctionMatch(candidates, empty_templ_args, arg_types); EXPECT_TRUE(callback); EXPECT_EQ(Cpp::GetFunctionSignature(callback), @@ -1364,7 +1368,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestBestOverloadFunctionMatch5) { "&>>(void (*callable)(double, int), double &args, int &args)"); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestIsPublicMethod) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_IsPublicMethod) { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -1391,7 +1395,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestIsPublicMethod) { EXPECT_FALSE(Cpp::IsPublicMethod(SubDecls[9])); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestIsProtectedMethod) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_IsProtectedMethod) { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -1416,7 +1420,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestIsProtectedMethod) { EXPECT_TRUE(Cpp::IsProtectedMethod(SubDecls[8])); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestIsPrivateMethod) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_IsPrivateMethod) { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -1441,7 +1445,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestIsPrivateMethod) { EXPECT_FALSE(Cpp::IsPrivateMethod(SubDecls[8])); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestIsConstructor) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_IsConstructor) { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -1488,7 +1492,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestIsConstructor) { EXPECT_EQ(templCtorCount, 1); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestIsDestructor) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_IsDestructor) { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -1513,7 +1517,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestIsDestructor) { EXPECT_FALSE(Cpp::IsDestructor(SubDecls[8])); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestIsStaticMethod) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_IsStaticMethod) { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -1530,7 +1534,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestIsStaticMethod) { EXPECT_TRUE(Cpp::IsStaticMethod(SubDecls[2])); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionAddress) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_GetFunctionAddress) { #ifdef EMSCRIPTEN #if CLANG_VERSION_MAJOR < 20 GTEST_SKIP() << "Test fails for Emscipten builds"; @@ -1578,13 +1582,13 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionAddress) { ASTContext& C = Interp->getCI()->getASTContext(); std::vector argument = {C.DoubleTy.getAsOpaquePtr()}; Cpp::TCppScope_t add1_double = - Cpp::InstantiateTemplate(funcs[0], argument.data(), argument.size()); + Cpp::InstantiateTemplate(funcs[0], argument.data(), argument.size(), false); EXPECT_TRUE(add1_double); EXPECT_TRUE(Cpp::GetFunctionAddress(add1_double)); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestIsVirtualMethod) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_IsVirtualMethod) { std::vector Decls, SubDecls; std::string code = R"( class A { @@ -1604,7 +1608,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestIsVirtualMethod) { EXPECT_FALSE(Cpp::IsVirtualMethod(Decls[0])); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestJitCallAdvanced) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_JitCallAdvanced) { #ifdef EMSCRIPTEN #if CLANG_VERSION_MAJOR < 20 GTEST_SKIP() << "Test fails for Emscipten builds"; @@ -1639,13 +1643,13 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestJitCallAdvanced) { Ctor.Invoke(&object); EXPECT_TRUE(object) << "Failed to call the ctor."; // Building a wrapper with a typedef decl must be possible. - EXPECT_TRUE(Cpp::Destruct(object, Decls[1])); + EXPECT_TRUE(Cpp::Destruct(object, Decls[1], true, 0)); // C API auto* I = clang_createInterpreterFromRawPtr(Cpp::GetInterpreter()); auto S = clang_getDefaultConstructor(make_scope(Decls[0], I)); void* object_c = nullptr; - clang_invoke(S, &object_c, nullptr, 0, nullptr); + clang_invoke(S, &object_c, nullptr, 0, 0); EXPECT_TRUE(object_c) << "Failed to call the ctor."; clang_destruct(object_c, make_scope(Decls[1], I), true); // Clean up resources @@ -1655,7 +1659,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestJitCallAdvanced) { #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST #ifndef _WIN32 // Death tests do not work on Windows -TYPED_TEST(CppInterOpTest, FunctionReflectionTestJitCallDebug) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_JitCallDebug) { #ifdef EMSCRIPTEN #if CLANG_VERSION_MAJOR < 20 GTEST_SKIP() << "Test fails for Emscipten builds"; @@ -1689,7 +1693,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestJitCallDebug) { { JC.InvokeConstructor(/*result=*/nullptr); }, "Must pass the location of the created object!"); - void* result = Cpp::Allocate(Decls[0]); + void* result = Cpp::Allocate(Decls[0], 1); EXPECT_DEATH( { JC.InvokeConstructor(&result, 0UL); }, "Number of objects to construct should be atleast 1"); @@ -1729,8 +1733,8 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestJitCallDebug) { EXPECT_TRUE(*obj == 42); // Destructors - Cpp::TCppScope_t scope_C = Cpp::GetNamed("C"); - Cpp::TCppObject_t object_C = Cpp::Construct(scope_C); + Cpp::TCppScope_t scope_C = Cpp::GetNamed("C", 0); + Cpp::TCppObject_t object_C = Cpp::Construct(scope_C, nullptr, 1); // Make destructor callable and pass arguments JC = Cpp::MakeFunctionCallable(SubDecls[4]); @@ -1751,7 +1755,7 @@ instantiation_in_host(); template int instantiation_in_host(); #endif -TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionCallWrapper) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_GetFunctionCallWrapper) { #ifdef EMSCRIPTEN GTEST_SKIP() << "Test fails for Emscipten builds"; #endif @@ -1792,13 +1796,13 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionCallWrapper) { Cpp::MakeFunctionCallable(Decls[0]); EXPECT_TRUE(FCI1.getKind() == Cpp::JitCall::kGenericCall); Cpp::JitCall FCI2 = - Cpp::MakeFunctionCallable(Cpp::GetNamed("f2")); + Cpp::MakeFunctionCallable(Cpp::GetNamed("f2", 0)); EXPECT_TRUE(FCI2.getKind() == Cpp::JitCall::kGenericCall); Cpp::JitCall FCI3 = - Cpp::MakeFunctionCallable(Cpp::GetNamed("f3", Cpp::GetNamed("NS"))); + Cpp::MakeFunctionCallable(Cpp::GetNamed("f3", Cpp::GetNamed("NS", 0))); EXPECT_TRUE(FCI3.getKind() == Cpp::JitCall::kGenericCall); Cpp::JitCall FCI4 = - Cpp::MakeFunctionCallable(Cpp::GetNamed("f4", Cpp::GetNamed("NS"))); + Cpp::MakeFunctionCallable(Cpp::GetNamed("f4", Cpp::GetNamed("NS", 0))); EXPECT_TRUE(FCI4.getKind() == Cpp::JitCall::kGenericCall); int i = 9, ret1, ret3, ret4; @@ -1821,7 +1825,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionCallWrapper) { EXPECT_EQ(ret4, 4); Cpp::JitCall FCI5 = - Cpp::MakeFunctionCallable(Cpp::GetNamed("f5", Cpp::GetNamed("NS"))); + Cpp::MakeFunctionCallable(Cpp::GetNamed("f5", Cpp::GetNamed("NS", 0))); EXPECT_TRUE(FCI5.getKind() == Cpp::JitCall::kGenericCall); typedef int (*int_func)(); @@ -1839,7 +1843,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionCallWrapper) { }; )"); - clang::NamedDecl *ClassC = (clang::NamedDecl*)Cpp::GetNamed("C"); + clang::NamedDecl *ClassC = (clang::NamedDecl*)Cpp::GetNamed("C", 0); auto *CtorD = (clang::CXXConstructorDecl*)Cpp::GetDefaultConstructor(ClassC); auto FCI_Ctor = Cpp::MakeFunctionCallable(CtorD); @@ -1874,10 +1878,10 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionCallWrapper) { std::vector argument = {C.IntTy.getAsOpaquePtr()}; auto Instance1 = Cpp::InstantiateTemplate(Decls1[0], argument.data(), - /*type_size*/ argument.size()); + /*type_size*/ argument.size(), false); EXPECT_TRUE(isa((Decl*)Instance1)); auto* CTSD1 = static_cast(Instance1); - auto* Add_D = Cpp::GetNamed("Add",CTSD1); + auto* Add_D = Cpp::GetNamed("Add", CTSD1); Cpp::JitCall FCI_Add = Cpp::MakeFunctionCallable(Add_D); EXPECT_TRUE(FCI_Add.getKind() == Cpp::JitCall::kGenericCall); @@ -1894,7 +1898,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionCallWrapper) { } )"); - Cpp::TCppScope_t set_5 = Cpp::GetNamed("set_5"); + Cpp::TCppScope_t set_5 = Cpp::GetNamed("set_5", 0); EXPECT_TRUE(set_5); Cpp::JitCall set_5_f = Cpp::MakeFunctionCallable(set_5); @@ -1920,7 +1924,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionCallWrapper) { )"); Cpp::TCppScope_t TypedefToPrivateClass = - Cpp::GetNamed("TypedefToPrivateClass"); + Cpp::GetNamed("TypedefToPrivateClass", 0); EXPECT_TRUE(TypedefToPrivateClass); Cpp::TCppScope_t f = Cpp::GetNamed("f", TypedefToPrivateClass); @@ -1941,7 +1945,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionCallWrapper) { bool operator<(T t) { return true; } }; )"); - Cpp::TCppScope_t TOperator = Cpp::GetNamed("TOperator"); + Cpp::TCppScope_t TOperator = Cpp::GetNamed("TOperator", 0); auto* TOperatorCtor = Cpp::GetDefaultConstructor(TOperator); auto FCI_TOperatorCtor = Cpp::MakeFunctionCallable(TOperatorCtor); @@ -1950,12 +1954,12 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionCallWrapper) { EXPECT_TRUE(toperator); std::vector operators; - Cpp::GetOperator(TOperator, Cpp::OP_Less, operators); + Cpp::GetOperator(TOperator, Cpp::Operator::OP_Less, operators, Cpp::OperatorArity::kBoth); EXPECT_EQ(operators.size(), 1); Cpp::TCppScope_t op_templated = operators[0]; auto TAI = Cpp::TemplateArgInfo(Cpp::GetType("int")); - Cpp::TCppScope_t op = Cpp::InstantiateTemplate(op_templated, &TAI, 1); + Cpp::TCppScope_t op = Cpp::InstantiateTemplate(op_templated, &TAI, 1, false); auto FCI_op = Cpp::MakeFunctionCallable(op); bool boolean = false; FCI_op.Invoke((void*)&boolean, {args, /*args_size=*/1}, toperator); @@ -1990,14 +1994,14 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionCallWrapper) { N1::N2::Klass1 K2; )"); - Cpp::TCppType_t K1 = Cpp::GetTypeFromScope(Cpp::GetNamed("K1")); - Cpp::TCppType_t K2 = Cpp::GetTypeFromScope(Cpp::GetNamed("K2")); + Cpp::TCppType_t K1 = Cpp::GetTypeFromScope(Cpp::GetNamed("K1", 0)); + Cpp::TCppType_t K2 = Cpp::GetTypeFromScope(Cpp::GetNamed("K2", 0)); operators.clear(); - Cpp::GetOperator(Cpp::GetScope("N2", Cpp::GetScope("N1")), Cpp::OP_Plus, - operators); + Cpp::GetOperator(Cpp::GetScope("N2", Cpp::GetScope("N1", 0)), Cpp::Operator::OP_Plus, + operators, Cpp::OperatorArity::kBoth); EXPECT_EQ(operators.size(), 1); Cpp::TCppFunction_t kop = - Cpp::BestOverloadFunctionMatch(operators, {}, {K1, K2}); + Cpp::BestOverloadFunctionMatch(operators, empty_templ_args, {K1, K2}); auto chrono_op_fn_callable = Cpp::MakeFunctionCallable(kop); EXPECT_EQ(chrono_op_fn_callable.getKind(), Cpp::JitCall::kGenericCall); @@ -2070,9 +2074,9 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionCallWrapper) { )"); std::vector unresolved_candidate_methods; - Cpp::GetClassTemplatedMethods("get", Cpp::GetScope("my_std"), + Cpp::GetClassTemplatedMethods("get", Cpp::GetScope("my_std", 0), unresolved_candidate_methods); - Cpp::TCppType_t p = Cpp::GetTypeFromScope(Cpp::GetNamed("p")); + Cpp::TCppType_t p = Cpp::GetTypeFromScope(Cpp::GetNamed("p", 0)); EXPECT_TRUE(p); Cpp::TCppScope_t fn = Cpp::BestOverloadFunctionMatch( @@ -2149,8 +2153,8 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionCallWrapper) { Cpp::TCppScope_t tuple_tuple = Cpp::BestOverloadFunctionMatch( unresolved_candidate_methods, {}, - {Cpp::GetVariableType(Cpp::GetNamed("tuple_one")), - Cpp::GetVariableType(Cpp::GetNamed("tuple_two"))}); + {Cpp::GetVariableType(Cpp::GetNamed("tuple_one", 0)), + Cpp::GetVariableType(Cpp::GetNamed("tuple_two", 0))}); EXPECT_TRUE(tuple_tuple); auto tuple_tuple_callable = Cpp::MakeFunctionCallable(tuple_tuple); @@ -2165,7 +2169,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionCallWrapper) { )"); Cpp::TCppScope_t bar = - Cpp::GetNamed("bar", Cpp::GetScope("EnumFunctionSameName")); + Cpp::GetNamed("bar", Cpp::GetScope("EnumFunctionSameName", 0)); EXPECT_TRUE(bar); auto bar_callable = Cpp::MakeFunctionCallable(bar); @@ -2181,7 +2185,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionCallWrapper) { template void consume(T t) {} - )"); + )", false); unresolved_candidate_methods.clear(); Cpp::GetClassTemplatedMethods("consume", Cpp::GetGlobalScope(), @@ -2190,7 +2194,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionCallWrapper) { Cpp::TCppScope_t consume = Cpp::BestOverloadFunctionMatch( unresolved_candidate_methods, {}, - {Cpp::GetVariableType(Cpp::GetNamed("consumable"))}); + {Cpp::GetVariableType(Cpp::GetNamed("consumable", 0))}); EXPECT_TRUE(consume); auto consume_callable = Cpp::MakeFunctionCallable(consume); @@ -2210,21 +2214,21 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionCallWrapper) { const Product operator*(const KlassProduct &other) const { return Product(); } }; - )"); + )", false); - Cpp::TCppScope_t KlassProduct = Cpp::GetNamed("KlassProduct"); + Cpp::TCppScope_t KlassProduct = Cpp::GetNamed("KlassProduct", 0); EXPECT_TRUE(KlassProduct); Cpp::TCppScope_t KlassProduct_int = - Cpp::InstantiateTemplate(KlassProduct, &TAI, 1); + Cpp::InstantiateTemplate(KlassProduct, &TAI, 1, false); EXPECT_TRUE(KlassProduct_int); TAI = Cpp::TemplateArgInfo(Cpp::GetType("float")); Cpp::TCppScope_t KlassProduct_float = - Cpp::InstantiateTemplate(KlassProduct, &TAI, 1); + Cpp::InstantiateTemplate(KlassProduct, &TAI, 1, false); EXPECT_TRUE(KlassProduct_float); operators.clear(); - Cpp::GetOperator(KlassProduct_int, Cpp::OP_Star, operators); + Cpp::GetOperator(KlassProduct_int, Cpp::Operator::OP_Star, operators, Cpp::OperatorArity::kBoth); EXPECT_EQ(operators.size(), 2); op = Cpp::BestOverloadFunctionMatch( @@ -2244,43 +2248,43 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionCallWrapper) { template class TemplatedEnum {}; } - )"); + )", false); - Cpp::TCppScope_t TemplatedEnum = Cpp::GetScope("TemplatedEnum"); + Cpp::TCppScope_t TemplatedEnum = Cpp::GetScope("TemplatedEnum", 0); EXPECT_TRUE(TemplatedEnum); auto TAI_enum = - Cpp::TemplateArgInfo(Cpp::GetTypeFromScope(Cpp::GetNamed("MyEnum")), "1"); + Cpp::TemplateArgInfo(Cpp::GetTypeFromScope(Cpp::GetNamed("MyEnum", 0)), "1"); Cpp::TCppScope_t TemplatedEnum_instantiated = - Cpp::InstantiateTemplate(TemplatedEnum, &TAI_enum, 1); + Cpp::InstantiateTemplate(TemplatedEnum, &TAI_enum, 1, false); EXPECT_TRUE(TemplatedEnum_instantiated); - Cpp::TCppObject_t obj = Cpp::Construct(TemplatedEnum_instantiated); + Cpp::TCppObject_t obj = Cpp::Construct(TemplatedEnum_instantiated, nullptr, 1); EXPECT_TRUE(obj); - Cpp::Destruct(obj, TemplatedEnum_instantiated); + Cpp::Destruct(obj, TemplatedEnum_instantiated, true, 0); obj = nullptr; Cpp::TCppScope_t MyNameSpace_TemplatedEnum = - Cpp::GetScope("TemplatedEnum", Cpp::GetScope("MyNameSpace")); + Cpp::GetScope("TemplatedEnum", Cpp::GetScope("MyNameSpace", 0)); EXPECT_TRUE(TemplatedEnum); TAI_enum = Cpp::TemplateArgInfo(Cpp::GetTypeFromScope(Cpp::GetNamed( - "MyEnum", Cpp::GetScope("MyNameSpace"))), + "MyEnum", Cpp::GetScope("MyNameSpace", 0))), "1"); Cpp::TCppScope_t MyNameSpace_TemplatedEnum_instantiated = - Cpp::InstantiateTemplate(MyNameSpace_TemplatedEnum, &TAI_enum, 1); + Cpp::InstantiateTemplate(MyNameSpace_TemplatedEnum, &TAI_enum, 1, false); EXPECT_TRUE(TemplatedEnum_instantiated); - obj = Cpp::Construct(MyNameSpace_TemplatedEnum_instantiated); + obj = Cpp::Construct(MyNameSpace_TemplatedEnum_instantiated, nullptr, 1); EXPECT_TRUE(obj); - Cpp::Destruct(obj, MyNameSpace_TemplatedEnum_instantiated); + Cpp::Destruct(obj, MyNameSpace_TemplatedEnum_instantiated, true, 0); obj = nullptr; Cpp::Declare(R"( auto get_fn(int x) { return [x](int y){ return x + y; }; } - )"); + )", false); - Cpp::TCppScope_t get_fn = Cpp::GetNamed("get_fn"); + Cpp::TCppScope_t get_fn = Cpp::GetNamed("get_fn", 0); EXPECT_TRUE(get_fn); auto get_fn_callable = Cpp::MakeFunctionCallable(get_fn); @@ -2290,7 +2294,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionCallWrapper) { EXPECT_FALSE(Cpp::IsLambdaClass(Cpp::GetFunctionReturnType(bar))); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestIsConstMethod) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_IsConstMethod) { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -2308,7 +2312,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestIsConstMethod) { EXPECT_FALSE(Cpp::IsConstMethod(method)); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionArgName) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_GetFunctionArgName) { std::vector Decls; std::string code = R"( void f1(int i, double d, long l, char ch) {} @@ -2348,7 +2352,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionArgName) { EXPECT_EQ(Cpp::GetFunctionArgName(Decls[4], 3), "l"); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionArgDefault) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_GetFunctionArgDefault) { std::vector Decls; std::string code = R"( void f1(int i, double d = 4.0, const char *s = "default", char ch = 'c') {} @@ -2400,7 +2404,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionArgDefault) { ASTContext& C = Interp->getCI()->getASTContext(); Cpp::TemplateArgInfo template_args[1] = {C.IntTy.getAsOpaquePtr()}; Cpp::TCppScope_t my_struct = - Cpp::InstantiateTemplate(Decls[6], template_args, 1); + Cpp::InstantiateTemplate(Decls[6], template_args, 1, false); EXPECT_TRUE(my_struct); std::vector fns = @@ -2412,7 +2416,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetFunctionArgDefault) { EXPECT_EQ(Cpp::GetFunctionArgDefault(fn, 1), "S()"); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestConstruct) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_Construct) { #ifdef EMSCRIPTEN #if CLANG_VERSION_MAJOR < 20 GTEST_SKIP() << "Test fails for Emscipten builds"; @@ -2445,8 +2449,8 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestConstruct) { GetAllTopLevelDecls(code, Decls, false, interpreter_args); GetAllSubDecls(Decls[1], SubDecls); testing::internal::CaptureStdout(); - Cpp::TCppScope_t scope = Cpp::GetNamed("C"); - Cpp::TCppObject_t object = Cpp::Construct(scope); + Cpp::TCppScope_t scope = Cpp::GetNamed("C", 0); + Cpp::TCppObject_t object = Cpp::Construct(scope, nullptr, 1); EXPECT_TRUE(object != nullptr); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(output, "Constructor Executed"); @@ -2454,28 +2458,28 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestConstruct) { // Placement. testing::internal::CaptureStdout(); - void* where = Cpp::Allocate(scope); - EXPECT_TRUE(where == Cpp::Construct(scope, where)); + void* where = Cpp::Allocate(scope, 1); + EXPECT_TRUE(where == Cpp::Construct(scope, where, 1)); // Check for the value of x which should be at the start of the object. EXPECT_TRUE(*(int *)where == 12345); - Cpp::Deallocate(scope, where); + Cpp::Deallocate(scope, where, 1); output = testing::internal::GetCapturedStdout(); EXPECT_EQ(output, "Constructor Executed"); output.clear(); // Pass a constructor testing::internal::CaptureStdout(); - where = Cpp::Allocate(scope); - EXPECT_TRUE(where == Cpp::Construct(SubDecls[3], where)); + where = Cpp::Allocate(scope, 1); + EXPECT_TRUE(where == Cpp::Construct(SubDecls[3], where, 1)); EXPECT_TRUE(*(int*)where == 12345); - Cpp::Deallocate(scope, where); + Cpp::Deallocate(scope, where, 1); output = testing::internal::GetCapturedStdout(); EXPECT_EQ(output, "Constructor Executed"); output.clear(); // Pass a non-class decl, this should fail - where = Cpp::Allocate(scope); - where = Cpp::Construct(Decls[2], where); + where = Cpp::Allocate(scope, 1); + where = Cpp::Construct(Decls[2], where, 1); EXPECT_TRUE(where == nullptr); // C API testing::internal::CaptureStdout(); @@ -2495,7 +2499,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestConstruct) { } // Test zero initialization of PODs and default initialization cases -TYPED_TEST(CppInterOpTest, FunctionReflectionTestConstructPOD) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_ConstructPOD) { #ifdef EMSCRIPTEN #if CLANG_VERSION_MAJOR < 20 GTEST_SKIP() << "Test fails for Emscipten builds"; @@ -2522,17 +2526,17 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestConstructPOD) { }; })"); - auto *ns = Cpp::GetNamed("PODS"); + auto *ns = Cpp::GetNamed("PODS", 0); Cpp::TCppScope_t scope = Cpp::GetNamed("SomePOD_B", ns); EXPECT_TRUE(scope); - Cpp::TCppObject_t object = Cpp::Construct(scope); + Cpp::TCppObject_t object = Cpp::Construct(scope, nullptr, 1); EXPECT_TRUE(object != nullptr); int* fInt = reinterpret_cast(reinterpret_cast(object)); EXPECT_TRUE(*fInt == 0); scope = Cpp::GetNamed("SomePOD_C", ns); EXPECT_TRUE(scope); - object = Cpp::Construct(scope); + object = Cpp::Construct(scope, nullptr, 1); EXPECT_TRUE(object); auto* fDouble = reinterpret_cast(reinterpret_cast(object) + sizeof(int)); @@ -2540,7 +2544,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestConstructPOD) { } // Test nested constructor calls -TYPED_TEST(CppInterOpTest, FunctionReflectionTestConstructNested) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_ConstructNested) { #ifdef EMSCRIPTEN #if CLANG_VERSION_MAJOR < 20 GTEST_SKIP() << "Test fails for Emscipten builds"; @@ -2579,9 +2583,9 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestConstructNested) { )"); testing::internal::CaptureStdout(); - Cpp::TCppScope_t scope_A = Cpp::GetNamed("A"); - Cpp::TCppScope_t scope_B = Cpp::GetNamed("B"); - Cpp::TCppObject_t object = Cpp::Construct(scope_B); + Cpp::TCppScope_t scope_A = Cpp::GetNamed("A", 0); + Cpp::TCppScope_t scope_B = Cpp::GetNamed("B", 0); + Cpp::TCppObject_t object = Cpp::Construct(scope_B, nullptr, 1); EXPECT_TRUE(object != nullptr); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(output, "A Constructor Called\nB Constructor Called\n"); @@ -2589,8 +2593,8 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestConstructNested) { // In-memory construction testing::internal::CaptureStdout(); - void* arena = Cpp::Allocate(scope_B); - EXPECT_TRUE(arena == Cpp::Construct(scope_B, arena)); + void* arena = Cpp::Allocate(scope_B, 1); + EXPECT_TRUE(arena == Cpp::Construct(scope_B, arena, 1)); // Check if both integers a_val and b_val were set. EXPECT_EQ(*(int*)arena, 7); @@ -2598,13 +2602,13 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestConstructNested) { int* b_val_ptr = reinterpret_cast(reinterpret_cast(arena) + a_size); EXPECT_EQ(*b_val_ptr, 99); - Cpp::Deallocate(scope_B, arena); + Cpp::Deallocate(scope_B, arena, 1); output = testing::internal::GetCapturedStdout(); EXPECT_EQ(output, "A Constructor Called\nB Constructor Called\n"); output.clear(); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestConstructArray) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_ConstructArray) { #if defined(EMSCRIPTEN) GTEST_SKIP() << "Test fails for Emscripten builds"; #endif @@ -2630,7 +2634,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestConstructArray) { }; )"); - Cpp::TCppScope_t scope = Cpp::GetNamed("C"); + Cpp::TCppScope_t scope = Cpp::GetNamed("C", 0); std::string output; size_t a = 5; // Construct an array of 5 objects @@ -2658,7 +2662,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestConstructArray) { output.clear(); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestDestruct) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_Destruct) { #ifdef EMSCRIPTEN GTEST_SKIP() << "Test fails for Emscipten builds"; #endif @@ -2686,20 +2690,20 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestDestruct) { )"); testing::internal::CaptureStdout(); - Cpp::TCppScope_t scope = Cpp::GetNamed("C"); - Cpp::TCppObject_t object = Cpp::Construct(scope); - EXPECT_TRUE(Cpp::Destruct(object, scope)); + Cpp::TCppScope_t scope = Cpp::GetNamed("C", 0); + Cpp::TCppObject_t object = Cpp::Construct(scope, nullptr, 1); + EXPECT_TRUE(Cpp::Destruct(object, scope, true, 0)); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(output, "Destructor Executed"); output.clear(); testing::internal::CaptureStdout(); - object = Cpp::Construct(scope); + object = Cpp::Construct(scope, nullptr, 1); // Make sure we do not call delete by adding an explicit Deallocate. If we // called delete the Deallocate will cause a double deletion error. - EXPECT_TRUE(Cpp::Destruct(object, scope, /*withFree=*/false)); - Cpp::Deallocate(scope, object); + EXPECT_TRUE(Cpp::Destruct(object, scope, /*withFree=*/false, 0)); + Cpp::Deallocate(scope, object, 1); output = testing::internal::GetCapturedStdout(); EXPECT_EQ(output, "Destructor Executed"); @@ -2716,7 +2720,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestDestruct) { clang_Interpreter_takeInterpreterAsPtr(I); clang_Interpreter_dispose(I); - // Failure Test, FunctionReflectionTestthis wrapper should not compile since we explicitly delete + // Failure Test, this wrapper should not compile since we explicitly delete // the destructor Interp->declare(R"( class D { @@ -2726,12 +2730,12 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestDestruct) { }; )"); - scope = Cpp::GetNamed("D"); - object = Cpp::Construct(scope); - EXPECT_FALSE(Cpp::Destruct(object, scope)); + scope = Cpp::GetNamed("D", 0); + object = Cpp::Construct(scope, nullptr, 1); + EXPECT_FALSE(Cpp::Destruct(object, scope, true, 0)); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestDestructArray) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_DestructArray) { #ifdef EMSCRIPTEN GTEST_SKIP() << "Test fails for Emscipten builds"; #endif @@ -2762,7 +2766,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestDestructArray) { }; )"); - Cpp::TCppScope_t scope = Cpp::GetNamed("C"); + Cpp::TCppScope_t scope = Cpp::GetNamed("C", 0); std::string output; size_t a = 5; // Construct an array of 5 objects @@ -2810,7 +2814,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestDestructArray) { output.clear(); } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestUndoTest) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_UndoTest) { #ifdef _WIN32 GTEST_SKIP() << "Disabled on Windows. Needs fixing."; #endif @@ -2837,7 +2841,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestUndoTest) { #endif } -TYPED_TEST(CppInterOpTest, FunctionReflectionTestFailingTest1) { +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_FailingTest1) { #ifdef _WIN32 GTEST_SKIP() << "Disabled on Windows. Needs fixing."; #endif @@ -2854,20 +2858,20 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestFailingTest1) { template bool is_equal(const C1& c1, const C2& c2) { return (bool)(c1 == c2); } - )")); + )", false)); - Cpp::TCppType_t o1 = Cpp::GetTypeFromScope(Cpp::GetNamed("o1")); - Cpp::TCppType_t o2 = Cpp::GetTypeFromScope(Cpp::GetNamed("o2")); + Cpp::TCppType_t o1 = Cpp::GetTypeFromScope(Cpp::GetNamed("o1", 0)); + Cpp::TCppType_t o2 = Cpp::GetTypeFromScope(Cpp::GetNamed("o2", 0)); std::vector fns; Cpp::GetClassTemplatedMethods("is_equal", Cpp::GetGlobalScope(), fns); EXPECT_EQ(fns.size(), 1); Cpp::TemplateArgInfo args[2] = {{o1}, {o2}}; - Cpp::TCppScope_t fn = Cpp::InstantiateTemplate(fns[0], args, 2); + Cpp::TCppScope_t fn = Cpp::InstantiateTemplate(fns[0], args, 2, false); EXPECT_TRUE(fn); Cpp::JitCall jit_call = Cpp::MakeFunctionCallable(fn); EXPECT_EQ(jit_call.getKind(), Cpp::JitCall::kUnknown); // expected to fail - EXPECT_FALSE(Cpp::Declare("int x = 1;")); - EXPECT_FALSE(Cpp::Declare("int y = x;")); + EXPECT_FALSE(Cpp::Declare("int x = 1;", false)); + EXPECT_FALSE(Cpp::Declare("int y = x;", false)); } diff --git a/unittests/CppInterOp/InterpreterTest.cpp b/unittests/CppInterOp/InterpreterTest.cpp index 59047854e..890faeff1 100644 --- a/unittests/CppInterOp/InterpreterTest.cpp +++ b/unittests/CppInterOp/InterpreterTest.cpp @@ -27,14 +27,14 @@ using ::testing::StartsWith; -TYPED_TEST(CppInterOpTest, InterpreterTestVersion) { +TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_Version) { EXPECT_THAT(Cpp::GetVersion(), StartsWith("CppInterOp version")); } #ifdef NDEBUG -TYPED_TEST(CppInterOpTest, DISABLED_InterpreterTestDebugFlag) { +TYPED_TEST(CPPINTEROP_TEST_MODE, DISABLED_Interpreter_DebugFlag) { #else -TYPED_TEST(CppInterOpTest, InterpreterTestDebugFlag) { +TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_DebugFlag) { #endif // NDEBUG TestFixture::CreateInterpreter(); EXPECT_FALSE(Cpp::IsDebugOutputEnabled()); @@ -43,7 +43,7 @@ TYPED_TEST(CppInterOpTest, InterpreterTestDebugFlag) { Cpp::Process("int a = 12;"); cerrs = testing::internal::GetCapturedStderr(); EXPECT_STREQ(cerrs.c_str(), ""); - Cpp::EnableDebugOutput(); + Cpp::EnableDebugOutput(true); EXPECT_TRUE(Cpp::IsDebugOutputEnabled()); testing::internal::CaptureStderr(); Cpp::Process("int b = 12;"); @@ -58,7 +58,7 @@ TYPED_TEST(CppInterOpTest, InterpreterTestDebugFlag) { EXPECT_STREQ(cerrs.c_str(), ""); } -TYPED_TEST(CppInterOpTest, InterpreterTestEvaluate) { +TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_Evaluate) { #ifdef EMSCRIPTEN GTEST_SKIP() << "Test fails for Emscipten builds"; #endif @@ -74,7 +74,7 @@ TYPED_TEST(CppInterOpTest, InterpreterTestEvaluate) { // Due to a deficiency in the clang-repl implementation to get the value we // always must omit the ; TestFixture::CreateInterpreter(); - EXPECT_TRUE(Cpp::Evaluate("__cplusplus") == 201402); + EXPECT_TRUE(Cpp::Evaluate("__cplusplus", nullptr) == 201402); bool HadError; EXPECT_TRUE(Cpp::Evaluate("#error", &HadError) == (intptr_t)~0UL); @@ -97,7 +97,7 @@ TYPED_TEST(CppInterOpTest, InterpreterTestEvaluate) { EXPECT_FALSE(HadError); } -TYPED_TEST(CppInterOpTest, InterpreterTestDeleteInterpreter) { +TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_DeleteInterpreter) { if (TypeParam::isOutOfProcess) GTEST_SKIP() << "Test fails for OOP JIT builds"; auto* I1 = TestFixture::CreateInterpreter(); @@ -117,7 +117,7 @@ TYPED_TEST(CppInterOpTest, InterpreterTestDeleteInterpreter) { EXPECT_EQ(I2, Cpp::GetInterpreter()) << "I2 is not active"; } -TYPED_TEST(CppInterOpTest, InterpreterTestActivateInterpreter) { +TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_ActivateInterpreter) { #ifdef EMSCRIPTEN_STATIC_LIBRARY GTEST_SKIP() << "Test fails for Emscipten static library build"; #endif @@ -129,23 +129,23 @@ TYPED_TEST(CppInterOpTest, InterpreterTestActivateInterpreter) { auto* Cpp20 = TestFixture::CreateInterpreter({"-std=c++20"}); EXPECT_TRUE(Cpp14 && Cpp17 && Cpp20); - EXPECT_TRUE(Cpp::Evaluate("__cplusplus") == 202002L) + EXPECT_TRUE(Cpp::Evaluate("__cplusplus", nullptr) == 202002L) << "Failed to activate C++20"; auto* UntrackedI = reinterpret_cast(static_cast(~0U)); EXPECT_FALSE(Cpp::ActivateInterpreter(UntrackedI)); EXPECT_TRUE(Cpp::ActivateInterpreter(Cpp14)); - EXPECT_TRUE(Cpp::Evaluate("__cplusplus") == 201402L); + EXPECT_TRUE(Cpp::Evaluate("__cplusplus", nullptr) == 201402L); Cpp::DeleteInterpreter(Cpp14); EXPECT_EQ(Cpp::GetInterpreter(), Cpp20); EXPECT_TRUE(Cpp::ActivateInterpreter(Cpp17)); - EXPECT_TRUE(Cpp::Evaluate("__cplusplus") == 201703L); + EXPECT_TRUE(Cpp::Evaluate("__cplusplus", nullptr) == 201703L); } -TYPED_TEST(CppInterOpTest, InterpreterTestProcess) { +TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_Process) { #ifdef EMSCRIPTEN_STATIC_LIBRARY GTEST_SKIP() << "Test fails for Emscipten static library build"; #endif @@ -175,7 +175,7 @@ TYPED_TEST(CppInterOpTest, InterpreterTestProcess) { clang_Interpreter_dispose(CXI); } -TYPED_TEST(CppInterOpTest, InterpreterTestEmscriptenExceptionHandling) { +TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_EmscriptenExceptionHandling) { #ifndef EMSCRIPTEN GTEST_SKIP() << "This test is intended to check exception handling for Emscripten builds."; #endif @@ -189,7 +189,7 @@ TYPED_TEST(CppInterOpTest, InterpreterTestEmscriptenExceptionHandling) { "-mllvm", "-enable-emscripten-sjlj" }; - Cpp::CreateInterpreter(Args); + Cpp::CreateInterpreter(Args, {}); const char* tryCatchCode = R"( try { @@ -202,7 +202,7 @@ TYPED_TEST(CppInterOpTest, InterpreterTestEmscriptenExceptionHandling) { EXPECT_TRUE(Cpp::Process(tryCatchCode) == 0); } -TYPED_TEST(CppInterOpTest, InterpreterTestCreateInterpreter) { +TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_CreateInterpreter) { auto* I = TestFixture::CreateInterpreter(); EXPECT_TRUE(I); // Check if the default standard is c++14 @@ -211,18 +211,18 @@ TYPED_TEST(CppInterOpTest, InterpreterTestCreateInterpreter) { "int cpp14() { return 2014; }\n" "#else\n" "void cppUnknown() {}\n" - "#endif"); - EXPECT_TRUE(Cpp::GetNamed("cpp14")); - EXPECT_FALSE(Cpp::GetNamed("cppUnknown")); + "#endif", false); + EXPECT_TRUE(Cpp::GetNamed("cpp14", nullptr)); + EXPECT_FALSE(Cpp::GetNamed("cppUnknown", nullptr)); I = TestFixture::CreateInterpreter({"-std=c++17"}); Cpp::Declare("#if __cplusplus==201703L\n" "int cpp17() { return 2017; }\n" "#else\n" "void cppUnknown() {}\n" - "#endif"); - EXPECT_TRUE(Cpp::GetNamed("cpp17")); - EXPECT_FALSE(Cpp::GetNamed("cppUnknown")); + "#endif", false); + EXPECT_TRUE(Cpp::GetNamed("cpp17", nullptr)); + EXPECT_FALSE(Cpp::GetNamed("cppUnknown", nullptr)); #ifndef CPPINTEROP_USE_CLING @@ -238,7 +238,7 @@ TYPED_TEST(CppInterOpTest, InterpreterTestCreateInterpreter) { } #ifndef CPPINTEROP_USE_CLING -TYPED_TEST(CppInterOpTest, InterpreterTestCreateInterpreterCAPI) { +TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_CreateInterpreterCAPI) { const char* argv[] = {"-std=c++17"}; auto *CXI = clang_createInterpreter(argv, 1); auto CLI = clang_Interpreter_getClangInterpreter(CXI); @@ -246,7 +246,7 @@ TYPED_TEST(CppInterOpTest, InterpreterTestCreateInterpreterCAPI) { clang_Interpreter_dispose(CXI); } -TYPED_TEST(CppInterOpTest, InterpreterTestCreateInterpreterCAPIFailure) { +TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_CreateInterpreterCAPIFailure) { #ifdef _WIN32 GTEST_SKIP() << "Disabled on Windows. Needs fixing."; #endif @@ -257,12 +257,12 @@ TYPED_TEST(CppInterOpTest, InterpreterTestCreateInterpreterCAPIFailure) { #endif #ifdef LLVM_BINARY_DIR -TYPED_TEST(CppInterOpTest, InterpreterTestDetectResourceDir) { +TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_DetectResourceDir) { #ifdef EMSCRIPTEN GTEST_SKIP() << "Test fails for Emscipten builds"; #endif #else -TYPED_TEST(CppInterOpTest, InterpreterTestDISABLED_DetectResourceDir) { +TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_DISABLED_DetectResourceDir) { #endif // LLVM_BINARY_DIR #ifdef _WIN32 GTEST_SKIP() << "Disabled on Windows. Needs fixing."; @@ -279,7 +279,7 @@ TYPED_TEST(CppInterOpTest, InterpreterTestDISABLED_DetectResourceDir) { EXPECT_STREQ(DetectedPath.c_str(), Cpp::GetResourceDir()); } -TYPED_TEST(CppInterOpTest, InterpreterTestDetectSystemCompilerIncludePaths) { +TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_DetectSystemCompilerIncludePaths) { #ifdef EMSCRIPTEN GTEST_SKIP() << "Test fails for Emscipten builds"; #endif @@ -291,7 +291,7 @@ TYPED_TEST(CppInterOpTest, InterpreterTestDetectSystemCompilerIncludePaths) { EXPECT_FALSE(includes.empty()); } -TYPED_TEST(CppInterOpTest, InterpreterTestIncludePaths) { +TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_IncludePaths) { if (TypeParam::isOutOfProcess) GTEST_SKIP() << "Test fails for OOP JIT builds"; std::vector includes; @@ -317,11 +317,11 @@ TYPED_TEST(CppInterOpTest, InterpreterTestIncludePaths) { std::end(includes)); } -TYPED_TEST(CppInterOpTest, InterpreterTestCodeCompletion) { +TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_CodeCompletion) { #if CLANG_VERSION_MAJOR >= 18 || defined(CPPINTEROP_USE_CLING) TestFixture::CreateInterpreter(); std::vector cc; - Cpp::Declare("int foo = 12;"); + Cpp::Declare("int foo = 12;", false); Cpp::CodeComplete(cc, "f", 1, 2); // We check only for 'float' and 'foo', because they // must be present in the result. Other hints may appear @@ -337,7 +337,7 @@ TYPED_TEST(CppInterOpTest, InterpreterTestCodeCompletion) { #endif } -TYPED_TEST(CppInterOpTest, InterpreterTestExternalInterpreterTest) { +TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_ExternalInterpreter) { if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; diff --git a/unittests/CppInterOp/JitTest.cpp b/unittests/CppInterOp/JitTest.cpp index 0137095c1..f3d8c5eac 100644 --- a/unittests/CppInterOp/JitTest.cpp +++ b/unittests/CppInterOp/JitTest.cpp @@ -11,7 +11,7 @@ static int printf_jit(const char* format, ...) { return 0; } -TYPED_TEST(CppInterOpTest, JitTestInsertOrReplaceJitSymbol) { +TYPED_TEST(CPPINTEROP_TEST_MODE, Jit_InsertOrReplaceJitSymbol) { #ifdef EMSCRIPTEN GTEST_SKIP() << "Test fails for Emscipten builds"; #endif @@ -41,7 +41,7 @@ TYPED_TEST(CppInterOpTest, JitTestInsertOrReplaceJitSymbol) { EXPECT_TRUE(Cpp::InsertOrReplaceJitSymbol("non_existent", 0)); } -TYPED_TEST(CppInterOpTest, JitTestStreamRedirect) { +TYPED_TEST(CPPINTEROP_TEST_MODE, Jit_StreamRedirect) { if (TypeParam::isOutOfProcess) GTEST_SKIP() << "Test fails for OOP JIT builds"; // printf and etc are fine here. @@ -75,7 +75,7 @@ TYPED_TEST(CppInterOpTest, JitTestStreamRedirect) { // NOLINTEND(cppcoreguidelines-pro-type-vararg) } -TYPED_TEST(CppInterOpTest, JitTestStreamRedirectJIT) { +TYPED_TEST(CPPINTEROP_TEST_MODE, Jit_StreamRedirectJIT) { #ifdef EMSCRIPTEN GTEST_SKIP() << "Test fails for Emscipten builds"; #endif diff --git a/unittests/CppInterOp/ScopeReflectionTest.cpp b/unittests/CppInterOp/ScopeReflectionTest.cpp index 62a472554..b54c0f1d8 100644 --- a/unittests/CppInterOp/ScopeReflectionTest.cpp +++ b/unittests/CppInterOp/ScopeReflectionTest.cpp @@ -25,7 +25,7 @@ using namespace TestUtils; using namespace llvm; using namespace clang; -TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsEnumScope) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_IsEnumScope) { std::vector Decls; std::vector SubDecls; std::string code = R"( @@ -48,7 +48,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsEnumScope) { EXPECT_FALSE(Cpp::IsEnumScope(SubDecls[1])); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsEnumConstant) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_IsEnumConstant) { std::vector Decls; std::vector SubDecls; std::string code = R"( @@ -71,7 +71,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsEnumConstant) { EXPECT_TRUE(Cpp::IsEnumConstant(SubDecls[1])); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestDemangle) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_Demangle) { if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; @@ -101,7 +101,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestDemangle) { std::string::npos); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsAggregate) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_IsAggregate) { std::vector Decls; std::string code = R"( char cv[4] = {}; @@ -127,7 +127,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsAggregate) { } // Check that the CharInfo table has been constructed reasonably. -TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsNamespace) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_IsNamespace) { std::vector Decls; GetAllTopLevelDecls("namespace N {} class C{}; int I;", Decls); EXPECT_TRUE(Cpp::IsNamespace(Decls[0])); @@ -135,7 +135,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsNamespace) { EXPECT_FALSE(Cpp::IsNamespace(Decls[2])); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsClass) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_IsClass) { std::vector Decls; GetAllTopLevelDecls("namespace N {} class C{}; int I;", Decls); EXPECT_FALSE(Cpp::IsClass(Decls[0])); @@ -143,7 +143,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsClass) { EXPECT_FALSE(Cpp::IsClass(Decls[2])); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsClassPolymorphic) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_IsClassPolymorphic) { std::vector Decls; GetAllTopLevelDecls(R"( namespace N {} @@ -165,7 +165,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsClassPolymorphic) { EXPECT_FALSE(Cpp::IsClassPolymorphic(Decls[3])); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsComplete) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_IsComplete) { std::vector Decls; std::string code = R"( namespace N {} @@ -190,7 +190,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsComplete) { EXPECT_FALSE(Cpp::IsComplete(nullptr)); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestSizeOf) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_SizeOf) { std::vector Decls; std::string code = R"(namespace N {} class C{}; int I; struct S; enum E : int; union U{}; class Size4{int i;}; @@ -209,7 +209,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestSizeOf) { } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsBuiltin) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_IsBuiltin) { #if CLANG_VERSION_MAJOR == 18 && defined(CPPINTEROP_USE_CLING) && \ defined(_WIN32) && (defined(_M_ARM) || defined(_M_ARM64)) GTEST_SKIP() << "Test fails with Cling on Windows on ARM"; @@ -245,7 +245,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsBuiltin) { EXPECT_TRUE(Cpp::IsBuiltin(C.getTypeDeclType(CTSD).getAsOpaquePtr())); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsTemplate) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_IsTemplate) { std::vector Decls; std::string code = R"(template class A{}; @@ -271,7 +271,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsTemplate) { EXPECT_FALSE(Cpp::IsTemplate(Decls[3])); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsTemplateSpecialization) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_IsTemplateSpecialization) { std::vector Decls; std::string code = R"( template @@ -287,7 +287,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsTemplateSpecialization) { Cpp::GetScopeFromType(Cpp::GetVariableType(Decls[1])))); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsTypedefed) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_IsTypedefed) { std::vector Decls; std::string code = R"( typedef int I; @@ -301,7 +301,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsTypedefed) { EXPECT_FALSE(Cpp::IsTypedefed(Decls[2])); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsAbstract) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_IsAbstract) { std::vector Decls; std::string code = R"( class A {}; @@ -321,7 +321,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsAbstract) { EXPECT_FALSE(Cpp::IsAbstract(Decls[2])); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsVariable) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_IsVariable) { std::vector Decls; std::string code = R"( int i; @@ -345,7 +345,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsVariable) { EXPECT_TRUE(Cpp::IsVariable(SubDecls[3])); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetName) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_GetName) { std::vector Decls; std::string code = R"(namespace N {} class C{}; int I; struct S; enum E : int; union U{}; class Size4{int i;}; @@ -363,7 +363,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetName) { EXPECT_EQ(Cpp::GetName(nullptr), ""); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetCompleteName) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_GetCompleteName) { std::vector Decls; std::string code = R"(namespace N {} class C{}; @@ -404,12 +404,12 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetCompleteName) { ASTContext& C = Interp->getCI()->getASTContext(); Cpp::TemplateArgInfo template_args[2] = {C.IntTy.getAsOpaquePtr(), C.DoubleTy.getAsOpaquePtr()}; - Cpp::TCppScope_t fn = Cpp::InstantiateTemplate(Decls[11], template_args, 2); + Cpp::TCppScope_t fn = Cpp::InstantiateTemplate(Decls[11], template_args, 2, false); EXPECT_TRUE(fn); EXPECT_EQ(Cpp::GetCompleteName(fn), "fn"); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetQualifiedName) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_GetQualifiedName) { std::vector Decls; std::string code = R"(namespace N { class C { @@ -429,7 +429,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetQualifiedName) { EXPECT_EQ(Cpp::GetQualifiedName(Decls[4]), "N::C::E"); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetQualifiedCompleteName) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_GetQualifiedCompleteName) { std::vector Decls; std::string code = R"(namespace N { class C { @@ -454,7 +454,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetQualifiedCompleteName) { EXPECT_EQ(Cpp::GetQualifiedCompleteName(Decls[6]), "N::C::E"); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetUsingNamespaces) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_GetUsingNamespaces) { std::vector Decls, Decls1; std::string code = R"( namespace abc { @@ -487,12 +487,12 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetUsingNamespaces) { EXPECT_EQ(usingNamespaces1.size(), 0); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetGlobalScope) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_GetGlobalScope) { EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetGlobalScope()), ""); EXPECT_EQ(Cpp::GetName(Cpp::GetGlobalScope()), ""); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetUnderlyingScope) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_GetUnderlyingScope) { std::vector Decls; std::string code = R"( namespace N { @@ -511,7 +511,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetUnderlyingScope) { EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetUnderlyingScope(nullptr)), ""); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetScope) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_GetScope) { std::string code = R"(namespace N { class C { int i; @@ -537,7 +537,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetScope) { EXPECT_EQ(Cpp::GetQualifiedName(non_existent), ""); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetScopefromCompleteName) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_GetScopefromCompleteName) { std::string code = R"(namespace N1 { namespace N2 { class C { @@ -556,7 +556,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetScopefromCompleteName) { EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetScopeFromCompleteName("N1::N2::C::S")), "N1::N2::C::S"); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetNamed) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_GetNamed) { #if CLANG_VERSION_MAJOR == 18 && defined(CPPINTEROP_USE_CLING) && \ defined(_WIN32) && (defined(_M_ARM) || defined(_M_ARM64)) GTEST_SKIP() << "Test fails with Cling on Windows on ARM"; @@ -601,7 +601,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetNamed) { EXPECT_EQ(Cpp::GetQualifiedName(std_string_npos_var), "std::basic_string::npos"); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetParentScope) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_GetParentScope) { std::string code = R"(namespace N1 { namespace N2 { class C { @@ -616,7 +616,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetParentScope) { TestFixture::CreateInterpreter(); Interp->declare(code); - Cpp::TCppScope_t ns_N1 = Cpp::GetNamed("N1"); + Cpp::TCppScope_t ns_N1 = Cpp::GetNamed("N1", 0); Cpp::TCppScope_t ns_N2 = Cpp::GetNamed("N2", ns_N1); Cpp::TCppScope_t cl_C = Cpp::GetNamed("C", ns_N2); Cpp::TCppScope_t int_i = Cpp::GetNamed("i", cl_C); @@ -633,7 +633,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetParentScope) { EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetParentScope(en_B)), "N1::N2::C::E"); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetScopeFromType) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_GetScopeFromType) { std::vector Decls; std::string code = R"( namespace N { @@ -677,7 +677,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetScopeFromType) { "N::C"); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetNumBases) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_GetNumBases) { std::vector Decls; std::string code = R"( class A {}; @@ -708,7 +708,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetNumBases) { EXPECT_EQ(Cpp::GetNumBases(Cpp::GetUnderlyingScope(Decls[7])), 1); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetBaseClass) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_GetBaseClass) { std::vector Decls; std::string code = R"( class A {}; @@ -744,20 +744,20 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetBaseClass) { EXPECT_EQ(get_base_class_name(Decls[4], 0), "D"); EXPECT_EQ(get_base_class_name(Decls[10], 0), ""); - auto *VD = Cpp::GetNamed("var"); + auto *VD = Cpp::GetNamed("var", 0); auto *VT = Cpp::GetVariableType(VD); auto *TC2_A_Decl = Cpp::GetScopeFromType(VT); auto *TC1_A_Decl = Cpp::GetBaseClass(TC2_A_Decl, 0); EXPECT_EQ(Cpp::GetCompleteName(TC1_A_Decl), "TC1"); - auto* VD1 = Cpp::GetNamed("var1"); + auto* VD1 = Cpp::GetNamed("var1", 0); auto* VT1 = Cpp::GetVariableType(VD1); auto* TC3_A_Decl = Cpp::GetScopeFromType(VT1); auto* A_class = Cpp::GetBaseClass(TC3_A_Decl, 0); EXPECT_EQ(Cpp::GetCompleteName(A_class), "A"); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsSubclass) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_IsSubclass) { std::vector Decls; std::string code = R"( class A {}; @@ -799,7 +799,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestIsSubclass) { EXPECT_FALSE(Cpp::IsSubclass(Decls[4], nullptr)); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetBaseClassOffset) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_GetBaseClassOffset) { std::vector Decls; #define Stringify(s) Stringifyx(s) #define Stringifyx(...) #__VA_ARGS__ @@ -836,7 +836,7 @@ CODE; EXPECT_EQ(Cpp::GetBaseClassOffset(Decls[6], Decls[0]), (char *)(A*)g - (char *)g); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetAllCppNames) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_GetAllCppNames) { std::vector Decls; std::string code = R"( class A { int a; }; @@ -878,7 +878,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetAllCppNames) { test_get_all_cpp_names(Decls[5], {}); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestInstantiateNNTPClassTemplate) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_InstantiateNNTPClassTemplate) { std::vector Decls; std::string code = R"( template @@ -897,7 +897,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestInstantiateNNTPClassTemplate) { Cpp::TCppType_t IntTy = C.IntTy.getAsOpaquePtr(); std::vector args1 = {{IntTy, "5"}}; EXPECT_TRUE(Cpp::InstantiateTemplate(Decls[0], args1.data(), - /*type_size*/ args1.size())); + /*type_size*/ args1.size(), false)); // C API auto* I = clang_createInterpreterFromRawPtr(Cpp::GetInterpreter()); @@ -911,7 +911,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestInstantiateNNTPClassTemplate) { clang_Interpreter_dispose(I); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestInstantiateVarTemplate) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_InstantiateVarTemplate) { std::vector Decls; std::string code = R"( template constexpr T pi = T(3.1415926535897932385L); @@ -922,7 +922,7 @@ template constexpr T pi = T(3.1415926535897932385L); std::vector args1 = {C.IntTy.getAsOpaquePtr()}; auto Instance1 = Cpp::InstantiateTemplate(Decls[0], args1.data(), - /*type_size*/ args1.size()); + /*type_size*/ args1.size(), false); EXPECT_TRUE(isa((Decl*)Instance1)); auto* VD = cast((Decl*)Instance1); VarTemplateDecl* VDTD1 = VD->getSpecializedTemplate(); @@ -935,7 +935,7 @@ template constexpr T pi = T(3.1415926535897932385L); EXPECT_TRUE(TA1.getAsType()->isIntegerType()); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestInstantiateFunctionTemplate) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_InstantiateFunctionTemplate) { std::vector Decls; std::string code = R"( template T TrivialFnTemplate() { return T(); } @@ -946,7 +946,7 @@ template T TrivialFnTemplate() { return T(); } std::vector args1 = {C.IntTy.getAsOpaquePtr()}; auto Instance1 = Cpp::InstantiateTemplate(Decls[0], args1.data(), - /*type_size*/ args1.size()); + /*type_size*/ args1.size(), false); EXPECT_TRUE(isa((Decl*)Instance1)); FunctionDecl* FD = cast((Decl*)Instance1); FunctionDecl* FnTD1 = FD->getTemplateInstantiationPattern(); @@ -955,7 +955,7 @@ template T TrivialFnTemplate() { return T(); } EXPECT_TRUE(TA1.getAsType()->isIntegerType()); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestInstantiateTemplateFunctionFromString) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_InstantiateTemplateFunctionFromString) { #if CLANG_VERSION_MAJOR == 18 && defined(CPPINTEROP_USE_CLING) && \ defined(_WIN32) && (defined(_M_ARM) || defined(_M_ARM64)) GTEST_SKIP() << "Test fails with Cling on Windows on ARM"; @@ -971,7 +971,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestInstantiateTemplateFunctionFromStr EXPECT_TRUE(Instance1); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestInstantiateTemplate) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_InstantiateTemplate) { std::vector Decls; std::string code = R"( template @@ -1016,7 +1016,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestInstantiateTemplate) { std::vector args1 = {C.IntTy.getAsOpaquePtr()}; auto Instance1 = Cpp::InstantiateTemplate(Decls[0], args1.data(), - /*type_size*/ args1.size()); + /*type_size*/ args1.size(), false); EXPECT_TRUE(isa((Decl*)Instance1)); auto *CTSD1 = static_cast(Instance1); EXPECT_TRUE(CTSD1->hasDefinition()); @@ -1025,7 +1025,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestInstantiateTemplate) { EXPECT_TRUE(CTSD1->hasDefinition()); auto Instance2 = Cpp::InstantiateTemplate(Decls[1], nullptr, - /*type_size*/ 0); + /*type_size*/ 0, false); EXPECT_TRUE(isa((Decl*)Instance2)); auto *CTSD2 = static_cast(Instance2); EXPECT_TRUE(CTSD2->hasDefinition()); @@ -1034,7 +1034,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestInstantiateTemplate) { std::vector args3 = {C.IntTy.getAsOpaquePtr()}; auto Instance3 = Cpp::InstantiateTemplate(Decls[2], args3.data(), - /*type_size*/ args3.size()); + /*type_size*/ args3.size(), false); EXPECT_TRUE(isa((Decl*)Instance3)); auto *CTSD3 = static_cast(Instance3); EXPECT_TRUE(CTSD3->hasDefinition()); @@ -1051,7 +1051,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestInstantiateTemplate) { std::vector args4 = {C.IntTy.getAsOpaquePtr(), {C.IntTy.getAsOpaquePtr(), "3"}}; auto Instance4 = Cpp::InstantiateTemplate(Decls[3], args4.data(), - /*type_size*/ args4.size()); + /*type_size*/ args4.size(), false); EXPECT_TRUE(isa((Decl*)Instance4)); auto *CTSD4 = static_cast(Instance4); @@ -1062,7 +1062,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestInstantiateTemplate) { EXPECT_TRUE(TA4_1.getAsIntegral() == 3); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetClassTemplateInstantiationArgs) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_GetClassTemplateInstantiationArgs) { std::vector Decls; std::string code = R"( template struct __Cppyy_AppendTypesSlow {}; @@ -1073,9 +1073,9 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetClassTemplateInstantiationArgs) GetAllTopLevelDecls(code, Decls); - auto *v1 = Cpp::GetNamed("v1"); - auto *v2 = Cpp::GetNamed("v2"); - auto *v3 = Cpp::GetNamed("v3"); + auto *v1 = Cpp::GetNamed("v1", 0); + auto *v2 = Cpp::GetNamed("v2", 0); + auto *v3 = Cpp::GetNamed("v3", 0); EXPECT_TRUE(v1 && v2 && v3); auto *v1_class = Cpp::GetScopeFromType(Cpp::GetVariableType(v1)); @@ -1100,7 +1100,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetClassTemplateInstantiationArgs) } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestIncludeVector) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_IncludeVector) { #if CLANG_VERSION_MAJOR == 18 && defined(CPPINTEROP_USE_CLING) && \ defined(_WIN32) && (defined(_M_ARM) || defined(_M_ARM64)) GTEST_SKIP() << "Test fails with Cling on Windows on ARM"; @@ -1116,7 +1116,7 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestIncludeVector) { Interp->declare(code); } -TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetOperator) { +TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_GetOperator) { if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; @@ -1154,38 +1154,38 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetOperator) { } )"; - Cpp::Declare(code.c_str()); + Cpp::Declare(code.c_str(), false); std::vector ops; - Cpp::GetOperator(Cpp::GetGlobalScope(), Cpp::Operator::OP_Plus, ops); + Cpp::GetOperator(Cpp::GetGlobalScope(), Cpp::Operator::OP_Plus, ops, Cpp::OperatorArity::kBoth); EXPECT_EQ(ops.size(), 1); ops.clear(); - Cpp::GetOperator(Cpp::GetGlobalScope(), Cpp::Operator::OP_Minus, ops); + Cpp::GetOperator(Cpp::GetGlobalScope(), Cpp::Operator::OP_Minus, ops, Cpp::OperatorArity::kBoth); EXPECT_EQ(ops.size(), 1); ops.clear(); - Cpp::GetOperator(Cpp::GetGlobalScope(), Cpp::Operator::OP_Star, ops); + Cpp::GetOperator(Cpp::GetGlobalScope(), Cpp::Operator::OP_Star, ops, Cpp::OperatorArity::kBoth); EXPECT_EQ(ops.size(), 0); ops.clear(); // operators defined within a namespace - Cpp::GetOperator(Cpp::GetScope("extra_ops"), Cpp::Operator::OP_Plus, ops); + Cpp::GetOperator(Cpp::GetScope("extra_ops", 0), Cpp::Operator::OP_Plus, ops, Cpp::OperatorArity::kBoth); EXPECT_EQ(ops.size(), 2); ops.clear(); // unary operator - Cpp::GetOperator(Cpp::GetScope("extra_ops"), Cpp::Operator::OP_Tilde, ops); + Cpp::GetOperator(Cpp::GetScope("extra_ops", 0), Cpp::Operator::OP_Tilde, ops, Cpp::OperatorArity::kBoth); EXPECT_EQ(ops.size(), 1); ops.clear(); - Cpp::GetOperator(Cpp::GetScope("extra_ops"), Cpp::Operator::OP_Tilde, ops, + Cpp::GetOperator(Cpp::GetScope("extra_ops", 0), Cpp::Operator::OP_Tilde, ops, Cpp::OperatorArity::kUnary); EXPECT_EQ(ops.size(), 1); ops.clear(); - Cpp::GetOperator(Cpp::GetScope("extra_ops"), Cpp::Operator::OP_Tilde, ops, + Cpp::GetOperator(Cpp::GetScope("extra_ops", 0), Cpp::Operator::OP_Tilde, ops, Cpp::OperatorArity::kBinary); EXPECT_EQ(ops.size(), 0); @@ -1205,13 +1205,13 @@ TYPED_TEST(CppInterOpTest, ScopeReflectionTestGetOperator) { } }; )"; - Cpp::Declare(inheritance_code.c_str()); + Cpp::Declare(inheritance_code.c_str(), false); ops.clear(); - Cpp::GetOperator(Cpp::GetScope("Child"), Cpp::Operator::OP_Plus, ops); + Cpp::GetOperator(Cpp::GetScope("Child", 0), Cpp::Operator::OP_Plus, ops, Cpp::OperatorArity::kBoth); EXPECT_EQ(ops.size(), 1); ops.clear(); - Cpp::GetOperator(Cpp::GetScope("Child"), Cpp::Operator::OP_Minus, ops); + Cpp::GetOperator(Cpp::GetScope("Child", 0), Cpp::Operator::OP_Minus, ops, Cpp::OperatorArity::kBoth); EXPECT_EQ(ops.size(), 1); } diff --git a/unittests/CppInterOp/TypeReflectionTest.cpp b/unittests/CppInterOp/TypeReflectionTest.cpp index 2da308f2a..1baeb0496 100644 --- a/unittests/CppInterOp/TypeReflectionTest.cpp +++ b/unittests/CppInterOp/TypeReflectionTest.cpp @@ -17,7 +17,7 @@ using namespace TestUtils; using namespace llvm; using namespace clang; -TYPED_TEST(CppInterOpTest, TypeReflectionTestGetTypeAsString) { +TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_GetTypeAsString) { std::vector Decls; std::string code = R"( namespace N { @@ -57,7 +57,7 @@ TYPED_TEST(CppInterOpTest, TypeReflectionTestGetTypeAsString) { EXPECT_EQ(Cpp::GetTypeAsString(QT7.getAsOpaquePtr()), "char[4]"); } -TYPED_TEST(CppInterOpTest, TypeReflectionTestGetSizeOfType) { +TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_GetSizeOfType) { std::vector Decls; std::string code = R"( struct S { @@ -85,7 +85,7 @@ TYPED_TEST(CppInterOpTest, TypeReflectionTestGetSizeOfType) { sizeof(intptr_t)); } -TYPED_TEST(CppInterOpTest, TypeReflectionTestGetCanonicalType) { +TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_GetCanonicalType) { std::vector Decls; std::string code = R"( typedef int I; @@ -108,7 +108,7 @@ TYPED_TEST(CppInterOpTest, TypeReflectionTestGetCanonicalType) { EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetCanonicalType(D4)), "NULL TYPE"); } -TYPED_TEST(CppInterOpTest, TypeReflectionTestGetType) { +TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_GetType) { TestFixture::CreateInterpreter(); std::string code = R"( @@ -133,7 +133,7 @@ TYPED_TEST(CppInterOpTest, TypeReflectionTestGetType) { EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("struct")),"NULL TYPE"); } -TYPED_TEST(CppInterOpTest, TypeReflectionTestIsRecordType) { +TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_IsRecordType) { std::vector Decls; std::string code = R"( @@ -200,7 +200,7 @@ TYPED_TEST(CppInterOpTest, TypeReflectionTestIsRecordType) { EXPECT_FALSE(is_var_of_record_ty(Decls[24])); } -TYPED_TEST(CppInterOpTest, TypeReflectionTestGetUnderlyingType) { +TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_GetUnderlyingType) { std::vector Decls; std::string code = R"( @@ -278,7 +278,7 @@ TYPED_TEST(CppInterOpTest, TypeReflectionTestGetUnderlyingType) { EXPECT_EQ(get_underly_var_type_as_str(Decls[30]), "E"); } -TYPED_TEST(CppInterOpTest, TypeReflectionTestIsUnderlyingTypeRecordType) { +TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_IsUnderlyingTypeRecordType) { std::vector Decls; std::string code = R"( @@ -345,7 +345,7 @@ TYPED_TEST(CppInterOpTest, TypeReflectionTestIsUnderlyingTypeRecordType) { EXPECT_TRUE(is_var_of_underly_record_ty(Decls[24])); } -TYPED_TEST(CppInterOpTest, TypeReflectionTestGetComplexType) { +TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_GetComplexType) { TestFixture::CreateInterpreter(); auto get_complex_type_as_string = [&](const std::string &element_type) { @@ -379,7 +379,7 @@ TYPED_TEST(CppInterOpTest, TypeReflectionTestGetComplexType) { clang_Interpreter_dispose(I); } -TYPED_TEST(CppInterOpTest, TypeReflectionTestGetTypeFromScope) { +TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_GetTypeFromScope) { std::vector Decls; std::string code = R"( @@ -396,7 +396,7 @@ TYPED_TEST(CppInterOpTest, TypeReflectionTestGetTypeFromScope) { EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetTypeFromScope(nullptr)), "NULL TYPE"); } -TYPED_TEST(CppInterOpTest, TypeReflectionTestIsTypeDerivedFrom) { +TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_IsTypeDerivedFrom) { std::vector Decls; std::string code = R"( @@ -433,7 +433,7 @@ TYPED_TEST(CppInterOpTest, TypeReflectionTestIsTypeDerivedFrom) { EXPECT_FALSE(Cpp::IsTypeDerivedFrom(type_A, type_E)); } -TYPED_TEST(CppInterOpTest, TypeReflectionTestGetDimensions) { +TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_GetDimensions) { std::vector Decls, SubDecls; std::string code = R"( @@ -528,7 +528,7 @@ TYPED_TEST(CppInterOpTest, TypeReflectionTestGetDimensions) { } } -TYPED_TEST(CppInterOpTest, TypeReflectionTestIsPODType) { +TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_IsPODType) { std::vector Decls; std::string code = R"( @@ -550,7 +550,7 @@ TYPED_TEST(CppInterOpTest, TypeReflectionTestIsPODType) { EXPECT_FALSE(Cpp::IsPODType(0)); } -TYPED_TEST(CppInterOpTest, TypeReflectionTestIsSmartPtrType) { +TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_IsSmartPtrType) { #if CLANG_VERSION_MAJOR == 18 && defined(CPPINTEROP_USE_CLING) && \ defined(_WIN32) && (defined(_M_ARM) || defined(_M_ARM64)) GTEST_SKIP() << "Test fails with Cling on Windows on ARM"; @@ -583,7 +583,7 @@ TYPED_TEST(CppInterOpTest, TypeReflectionTestIsSmartPtrType) { )"); auto get_type_from_varname = [&](const std::string &varname) { - return Cpp::GetVariableType(Cpp::GetNamed(varname)); + return Cpp::GetVariableType(Cpp::GetNamed(varname, 0)); }; //EXPECT_TRUE(Cpp::IsSmartPtrType(get_type_from_varname("smart_ptr1"))); @@ -596,7 +596,7 @@ TYPED_TEST(CppInterOpTest, TypeReflectionTestIsSmartPtrType) { EXPECT_FALSE(Cpp::IsSmartPtrType(get_type_from_varname("object"))); } -TYPED_TEST(CppInterOpTest, TypeReflectionTestIsFunctionPointerType) { +TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_IsFunctionPointerType) { std::vector interpreter_args = {"-include", "new"}; TestFixture::CreateInterpreter(interpreter_args); @@ -608,12 +608,12 @@ TYPED_TEST(CppInterOpTest, TypeReflectionTestIsFunctionPointerType) { )"); EXPECT_TRUE( - Cpp::IsFunctionPointerType(Cpp::GetVariableType(Cpp::GetNamed("f")))); + Cpp::IsFunctionPointerType(Cpp::GetVariableType(Cpp::GetNamed("f", 0)))); EXPECT_FALSE( - Cpp::IsFunctionPointerType(Cpp::GetVariableType(Cpp::GetNamed("i")))); + Cpp::IsFunctionPointerType(Cpp::GetVariableType(Cpp::GetNamed("i", 0)))); } -TYPED_TEST(CppInterOpTest, TypeReflectionTestOperatorSpelling) { +TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_OperatorSpelling) { EXPECT_EQ(Cpp::GetSpellingFromOperator(Cpp::OP_Less), "<"); EXPECT_EQ(Cpp::GetSpellingFromOperator(Cpp::OP_Plus), "+"); EXPECT_EQ(Cpp::GetOperatorFromSpelling("->"), Cpp::OP_Arrow); @@ -621,7 +621,7 @@ TYPED_TEST(CppInterOpTest, TypeReflectionTestOperatorSpelling) { EXPECT_EQ(Cpp::GetOperatorFromSpelling("invalid"), Cpp::OP_None); } -TYPED_TEST(CppInterOpTest, TypeReflectionTestTypeQualifiers) { +TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_TypeQualifiers) { TestFixture::CreateInterpreter(); Cpp::Declare(R"( int *a; @@ -632,16 +632,16 @@ TYPED_TEST(CppInterOpTest, TypeReflectionTestTypeQualifiers) { int *__restrict__ const f = nullptr; int *__restrict__ volatile g; int *__restrict__ const volatile h = nullptr; - )"); - - Cpp::TCppType_t a = Cpp::GetVariableType(Cpp::GetNamed("a")); - Cpp::TCppType_t b = Cpp::GetVariableType(Cpp::GetNamed("b")); - Cpp::TCppType_t c = Cpp::GetVariableType(Cpp::GetNamed("c")); - Cpp::TCppType_t d = Cpp::GetVariableType(Cpp::GetNamed("d")); - Cpp::TCppType_t e = Cpp::GetVariableType(Cpp::GetNamed("e")); - Cpp::TCppType_t f = Cpp::GetVariableType(Cpp::GetNamed("f")); - Cpp::TCppType_t g = Cpp::GetVariableType(Cpp::GetNamed("g")); - Cpp::TCppType_t h = Cpp::GetVariableType(Cpp::GetNamed("h")); + )", false); + + Cpp::TCppType_t a = Cpp::GetVariableType(Cpp::GetNamed("a", 0)); + Cpp::TCppType_t b = Cpp::GetVariableType(Cpp::GetNamed("b", 0)); + Cpp::TCppType_t c = Cpp::GetVariableType(Cpp::GetNamed("c", 0)); + Cpp::TCppType_t d = Cpp::GetVariableType(Cpp::GetNamed("d", 0)); + Cpp::TCppType_t e = Cpp::GetVariableType(Cpp::GetNamed("e", 0)); + Cpp::TCppType_t f = Cpp::GetVariableType(Cpp::GetNamed("f", 0)); + Cpp::TCppType_t g = Cpp::GetVariableType(Cpp::GetNamed("g", 0)); + Cpp::TCppType_t h = Cpp::GetVariableType(Cpp::GetNamed("h", 0)); EXPECT_FALSE(Cpp::HasTypeQualifier(nullptr, Cpp::QualKind::Const)); EXPECT_FALSE(Cpp::RemoveTypeQualifier(nullptr, Cpp::QualKind::Const)); diff --git a/unittests/CppInterOp/VariableReflectionTest.cpp b/unittests/CppInterOp/VariableReflectionTest.cpp index 581dab7e4..5fde76214 100644 --- a/unittests/CppInterOp/VariableReflectionTest.cpp +++ b/unittests/CppInterOp/VariableReflectionTest.cpp @@ -16,7 +16,7 @@ using namespace TestUtils; using namespace llvm; using namespace clang; -TYPED_TEST(CppInterOpTest, VariableReflectionTestGetDatamembers) { +TYPED_TEST(CPPINTEROP_TEST_MODE, VariableReflection_GetDatamembers) { std::vector Decls; std::string code = R"( class C { @@ -113,7 +113,7 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestGetDatamembers) { CODE -TYPED_TEST(CppInterOpTest, VariableReflectionTestDatamembersWithAnonymousStructOrUnion) { +TYPED_TEST(CPPINTEROP_TEST_MODE, VariableReflection_DatamembersWithAnonymousStructOrUnion) { if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; @@ -136,33 +136,33 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestDatamembersWithAnonymousStructO 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]), + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass1[0], 0), 0); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass1[1], 0), ((intptr_t) & (k1.a)) - ((intptr_t) & (k1.num))); - EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass1[2]), + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass1[2], 0), ((intptr_t) & (k1.b)) - ((intptr_t) & (k1.num))); - EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass2[0]), 0); - EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass2[1]), + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass2[0], 0), 0); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass2[1], 0), ((intptr_t) & (k2.a)) - ((intptr_t) & (k2.num))); - EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass2[2]), + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass2[2], 0), ((intptr_t) & (k2.b)) - ((intptr_t) & (k2.num))); - EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[0]), 0); - EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[1]), + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[0], 0), 0); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[1], 0), ((intptr_t) & (k3.a)) - ((intptr_t) & (k3.num))); - EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[2]), + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[2], 0), ((intptr_t) & (k3.b)) - ((intptr_t) & (k3.num))); - EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[3]), + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[3], 0), ((intptr_t) & (k3.c)) - ((intptr_t) & (k3.num))); - EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[4]), + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[4], 0), ((intptr_t) & (k3.num2)) - ((intptr_t) & (k3.num))); #ifdef _WIN32 #pragma warning(default : 4201) #endif } -TYPED_TEST(CppInterOpTest, VariableReflectionTestGetTypeAsString) { +TYPED_TEST(CPPINTEROP_TEST_MODE, VariableReflection_GetTypeAsString) { if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; @@ -181,7 +181,7 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestGetTypeAsString) { )"; TestFixture::CreateInterpreter(); - EXPECT_EQ(Cpp::Declare(code.c_str()), 0); + EXPECT_EQ(Cpp::Declare(code.c_str(), false), 0); Cpp::TCppScope_t wrapper = Cpp::GetScopeFromCompleteName("my_namespace::Wrapper"); @@ -195,7 +195,7 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestGetTypeAsString) { "my_namespace::Container"); } -TYPED_TEST(CppInterOpTest, VariableReflectionTestLookupDatamember) { +TYPED_TEST(CPPINTEROP_TEST_MODE, VariableReflection_LookupDatamember) { std::vector Decls; std::string code = R"( class C { @@ -219,7 +219,7 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestLookupDatamember) { EXPECT_EQ(Cpp::GetQualifiedName(Cpp::LookupDatamember("k", Decls[0])), ""); } -TYPED_TEST(CppInterOpTest, VariableReflectionTestGetVariableType) { +TYPED_TEST(CPPINTEROP_TEST_MODE, VariableReflection_GetVariableType) { std::vector Decls; std::string code = R"( class C {}; @@ -268,7 +268,7 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestGetVariableType) { CODE -TYPED_TEST(CppInterOpTest, VariableReflectionTestGetVariableOffset) { +TYPED_TEST(CPPINTEROP_TEST_MODE, VariableReflection_GetVariableOffset) { #ifdef EMSCRIPTEN #if CLANG_VERSION_MAJOR < 20 GTEST_SKIP() << "Test fails for Emscipten builds"; @@ -287,63 +287,62 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestGetVariableOffset) { std::vector datamembers; Cpp::GetDatamembers(Decls[4], datamembers); - EXPECT_TRUE((bool) Cpp::GetVariableOffset(Decls[0])); // a - EXPECT_TRUE((bool) Cpp::GetVariableOffset(Decls[1])); // N - EXPECT_TRUE((bool)Cpp::GetVariableOffset(Decls[2])); // S - EXPECT_TRUE((bool)Cpp::GetVariableOffset(Decls[3])); // SN + EXPECT_TRUE((bool) Cpp::GetVariableOffset(Decls[0], 0)); // a + EXPECT_TRUE((bool) Cpp::GetVariableOffset(Decls[1], 0)); // N + EXPECT_TRUE((bool)Cpp::GetVariableOffset(Decls[2], 0)); // S + EXPECT_TRUE((bool)Cpp::GetVariableOffset(Decls[3], 0)); // SN - EXPECT_EQ(Cpp::GetVariableOffset(datamembers[0]), 0); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers[0], 0), 0); - EXPECT_EQ(Cpp::GetVariableOffset(datamembers[1]), + EXPECT_EQ(Cpp::GetVariableOffset(datamembers[1], 0), ((intptr_t) &(c.b)) - ((intptr_t) &(c.a))); - EXPECT_EQ(Cpp::GetVariableOffset(datamembers[2]), + EXPECT_EQ(Cpp::GetVariableOffset(datamembers[2], 0), ((intptr_t) &(c.c)) - ((intptr_t) &(c.a))); - EXPECT_EQ(Cpp::GetVariableOffset(datamembers[3]), + EXPECT_EQ(Cpp::GetVariableOffset(datamembers[3], 0), ((intptr_t) &(c.d)) - ((intptr_t) &(c.a))); auto* VD_C_s_a = Cpp::GetNamed("s_a", Decls[4]); // C::s_a - EXPECT_TRUE((bool) Cpp::GetVariableOffset(VD_C_s_a)); + EXPECT_TRUE((bool) Cpp::GetVariableOffset(VD_C_s_a, 0)); struct K { int x; int y; int z; }; - Cpp::Declare("struct K;"); - Cpp::TCppScope_t k = Cpp::GetNamed("K"); + Cpp::Declare("struct K;", false); + Cpp::TCppScope_t k = Cpp::GetNamed("K", 0); EXPECT_TRUE(k); - Cpp::Declare("struct K { int x; int y; int z; };"); - + Cpp::Declare("struct K { int x; int y; int z; };", false); datamembers.clear(); Cpp::GetDatamembers(k, datamembers); EXPECT_EQ(datamembers.size(), 3); - EXPECT_EQ(Cpp::GetVariableOffset(datamembers[0]), offsetof(K, x)); - EXPECT_EQ(Cpp::GetVariableOffset(datamembers[1]), offsetof(K, y)); - EXPECT_EQ(Cpp::GetVariableOffset(datamembers[2]), offsetof(K, z)); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers[0], 0), offsetof(K, x)); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers[1], 0), offsetof(K, y)); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers[2], 0), offsetof(K, z)); Cpp::Declare(R"( template struct ClassWithStatic { static T const ref_value; }; template T constexpr ClassWithStatic::ref_value = 42; - )"); + )", false); - Cpp::TCppScope_t klass = Cpp::GetNamed("ClassWithStatic"); + Cpp::TCppScope_t klass = Cpp::GetNamed("ClassWithStatic", 0); EXPECT_TRUE(klass); ASTContext& C = Interp->getCI()->getASTContext(); std::vector template_args = { {C.IntTy.getAsOpaquePtr()}}; Cpp::TCppScope_t klass_instantiated = Cpp::InstantiateTemplate( - klass, template_args.data(), template_args.size()); + klass, template_args.data(), template_args.size(), false); EXPECT_TRUE(klass_instantiated); Cpp::TCppScope_t var = Cpp::GetNamed("ref_value", klass_instantiated); EXPECT_TRUE(var); - EXPECT_TRUE(Cpp::GetVariableOffset(var)); + EXPECT_TRUE(Cpp::GetVariableOffset(var, 0)); } #define CODE \ @@ -379,7 +378,7 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestGetVariableOffset) { CODE -TYPED_TEST(CppInterOpTest, VariableReflectionTestVariableOffsetsWithInheritance) { +TYPED_TEST(CPPINTEROP_TEST_MODE, VariableReflection_VariableOffsetsWithInheritance) { #if CLANG_VERSION_MAJOR == 18 && defined(CPPINTEROP_USE_CLING) && \ defined(_WIN32) && (defined(_M_ARM) || defined(_M_ARM64)) GTEST_SKIP() << "Test fails with Cling on Windows on ARM"; @@ -390,16 +389,16 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestVariableOffsetsWithInheritance) std::vector interpreter_args = {"-include", "new"}; TestFixture::CreateInterpreter(interpreter_args); - Cpp::Declare("#include"); + Cpp::Declare("#include", false); #define Stringify(s) Stringifyx(s) #define Stringifyx(...) #__VA_ARGS__ - Cpp::Declare(Stringify(CODE)); + Cpp::Declare(Stringify(CODE), false); #undef Stringifyx #undef Stringify #undef CODE - Cpp::TCppScope_t myklass = Cpp::GetNamed("MyKlass"); + Cpp::TCppScope_t myklass = Cpp::GetNamed("MyKlass", 0); EXPECT_TRUE(myklass); size_t num_bases = Cpp::GetNumBases(myklass); @@ -435,7 +434,7 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestVariableOffsetsWithInheritance) ((intptr_t)&(my_k.s)) - ((intptr_t)&(my_k))); } -TYPED_TEST(CppInterOpTest, VariableReflectionTestIsPublicVariable) { +TYPED_TEST(CPPINTEROP_TEST_MODE, VariableReflection_IsPublicVariable) { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -458,7 +457,7 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestIsPublicVariable) { EXPECT_FALSE(Cpp::IsPublicVariable(SubDecls[7])); } -TYPED_TEST(CppInterOpTest, VariableReflectionTestIsProtectedVariable) { +TYPED_TEST(CPPINTEROP_TEST_MODE, VariableReflection_IsProtectedVariable) { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -479,7 +478,7 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestIsProtectedVariable) { EXPECT_TRUE(Cpp::IsProtectedVariable(SubDecls[6])); } -TYPED_TEST(CppInterOpTest, VariableReflectionTestIsPrivateVariable) { +TYPED_TEST(CPPINTEROP_TEST_MODE, VariableReflection_IsPrivateVariable) { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -500,7 +499,7 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestIsPrivateVariable) { EXPECT_FALSE(Cpp::IsPrivateVariable(SubDecls[6])); } -TYPED_TEST(CppInterOpTest, VariableReflectionTestIsStaticVariable) { +TYPED_TEST(CPPINTEROP_TEST_MODE, VariableReflection_IsStaticVariable) { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -516,7 +515,7 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestIsStaticVariable) { EXPECT_TRUE(Cpp::IsStaticVariable(SubDecls[2])); } -TYPED_TEST(CppInterOpTest, VariableReflectionTestIsConstVariable) { +TYPED_TEST(CPPINTEROP_TEST_MODE, VariableReflection_IsConstVariable) { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -533,7 +532,7 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestIsConstVariable) { EXPECT_TRUE(Cpp::IsConstVariable(SubDecls[2])); } -TYPED_TEST(CppInterOpTest, VariableReflectionTestDISABLED_GetArrayDimensions) { +TYPED_TEST(CPPINTEROP_TEST_MODE, VariableReflection_DISABLED_GetArrayDimensions) { std::vector Decls; std::string code = R"( int a; @@ -557,7 +556,7 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestDISABLED_GetArrayDimensions) { // EXPECT_TRUE(is_vec_eq(Cpp::GetArrayDimensions(Decls[2]), {1,2})); } -TYPED_TEST(CppInterOpTest, VariableReflectionTestStaticConstExprDatamember) { +TYPED_TEST(CPPINTEROP_TEST_MODE, VariableReflection_StaticConstExprDatamember) { if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; @@ -588,16 +587,16 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestStaticConstExprDatamember) { template struct Elements : public integral_constant {}; - )"); + )", false); - Cpp::TCppScope_t MyClass = Cpp::GetNamed("MyClass"); + Cpp::TCppScope_t MyClass = Cpp::GetNamed("MyClass", 0); EXPECT_TRUE(MyClass); std::vector datamembers; Cpp::GetStaticDatamembers(MyClass, datamembers); EXPECT_EQ(datamembers.size(), 1); - intptr_t offset = Cpp::GetVariableOffset(datamembers[0]); + intptr_t offset = Cpp::GetVariableOffset(datamembers[0], 0); EXPECT_EQ(3, *(size_t*)offset); ASTContext& C = Interp->getCI()->getASTContext(); @@ -605,23 +604,23 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestStaticConstExprDatamember) { {C.IntTy.getAsOpaquePtr(), "5"}}; Cpp::TCppFunction_t MyTemplatedClass = - Cpp::InstantiateTemplate(Cpp::GetNamed("MyTemplatedClass"), - template_args.data(), template_args.size()); + Cpp::InstantiateTemplate(Cpp::GetNamed("MyTemplatedClass", 0), + template_args.data(), template_args.size(), false); EXPECT_TRUE(MyTemplatedClass); datamembers.clear(); Cpp::GetStaticDatamembers(MyTemplatedClass, datamembers); EXPECT_EQ(datamembers.size(), 1); - offset = Cpp::GetVariableOffset(datamembers[0]); + offset = Cpp::GetVariableOffset(datamembers[0], 0); EXPECT_EQ(5, *(size_t*)offset); std::vector ele_template_args = { {C.IntTy.getAsOpaquePtr()}, {C.FloatTy.getAsOpaquePtr()}}; Cpp::TCppFunction_t Elements = Cpp::InstantiateTemplate( - Cpp::GetNamed("Elements"), ele_template_args.data(), - ele_template_args.size()); + Cpp::GetNamed("Elements", 0), ele_template_args.data(), + ele_template_args.size(), false); EXPECT_TRUE(Elements); EXPECT_EQ(1, Cpp::GetNumBases(Elements)); @@ -632,11 +631,11 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestStaticConstExprDatamember) { Cpp::GetStaticDatamembers(IC, datamembers); EXPECT_EQ(datamembers.size(), 1); - offset = Cpp::GetVariableOffset(datamembers[0]); + offset = Cpp::GetVariableOffset(datamembers[0], 0); EXPECT_EQ(2, *(size_t*)offset); } -TYPED_TEST(CppInterOpTest, VariableReflectionTestGetEnumConstantDatamembers) { +TYPED_TEST(CPPINTEROP_TEST_MODE, VariableReflection_GetEnumConstantDatamembers) { TestFixture::CreateInterpreter(); Cpp::Declare(R"( @@ -645,13 +644,13 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestGetEnumConstantDatamembers) { enum A { ONE, TWO, THREE }; enum class B { SEVEN, EIGHT, NINE }; }; - )"); + )", false); - Cpp::TCppScope_t MyEnumClass = Cpp::GetNamed("MyEnumClass"); + Cpp::TCppScope_t MyEnumClass = Cpp::GetNamed("MyEnumClass", 0); EXPECT_TRUE(MyEnumClass); std::vector datamembers; - Cpp::GetEnumConstantDatamembers(MyEnumClass, datamembers); + Cpp::GetEnumConstantDatamembers(MyEnumClass, datamembers, true); EXPECT_EQ(datamembers.size(), 9); EXPECT_TRUE(Cpp::IsEnumType(Cpp::GetVariableType(datamembers[0]))); @@ -660,7 +659,7 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestGetEnumConstantDatamembers) { EXPECT_EQ(datamembers2.size(), 6); } -TYPED_TEST(CppInterOpTest, VariableReflectionTestIs_Get_Pointer) { +TYPED_TEST(CPPINTEROP_TEST_MODE, VariableReflection_Is_Get_Pointer) { TestFixture::CreateInterpreter(); std::vector Decls; std::string code = R"( @@ -692,7 +691,7 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestIs_Get_Pointer) { EXPECT_FALSE(Cpp::GetPointeeType(Cpp::GetVariableType(Decls[5]))); } -TYPED_TEST(CppInterOpTest, VariableReflectionTestIs_Get_Reference) { +TYPED_TEST(CPPINTEROP_TEST_MODE, VariableReflection_Is_Get_Reference) { TestFixture::CreateInterpreter(); std::vector Decls; std::string code = R"( @@ -725,7 +724,7 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestIs_Get_Reference) { EXPECT_EQ(Cpp::GetValueKind(Cpp::GetVariableType(Decls[2])), Cpp::ValueKind::LValue); - EXPECT_EQ(Cpp::GetReferencedType(Cpp::GetVariableType(Decls[1])), + EXPECT_EQ(Cpp::GetReferencedType(Cpp::GetVariableType(Decls[1]), false), Cpp::GetVariableType(Decls[2])); EXPECT_EQ(Cpp::GetValueKind( Cpp::GetReferencedType(Cpp::GetVariableType(Decls[1]), true)), @@ -734,7 +733,7 @@ TYPED_TEST(CppInterOpTest, VariableReflectionTestIs_Get_Reference) { Cpp::ValueKind::None); } -TYPED_TEST(CppInterOpTest, VariableReflectionTestGetPointerType) { +TYPED_TEST(CPPINTEROP_TEST_MODE, VariableReflection_GetPointerType) { TestFixture::CreateInterpreter(); std::vector Decls; std::string code = R"(