Rely on the placement new version provided by clang-repl.#912
Rely on the placement new version provided by clang-repl.#912vgvassilev wants to merge 1 commit into
Conversation
| // Per [new.delete.placement] the standard placement overloads are | ||
| // declared `noexcept`; this non-noexcept redeclaration only parses | ||
| // if <new> is NOT in scope. | ||
| ASSERT_EQ(0, Cpp::Declare("void* operator new(__SIZE_TYPE__, void*);")); |
There was a problem hiding this comment.
warning: too few arguments to function call, expected 2, have 1 [clang-diagnostic-error]
ASSERT_EQ(0, Cpp::Declare("void* operator new(__SIZE_TYPE__, void*);"));
^Additional context
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest.h:1913: expanded from macro 'ASSERT_EQ'
#define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2)
^build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest.h:1897: expanded from macro 'GTEST_ASSERT_EQ'
ASSERT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2)
^build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:147: expanded from macro 'ASSERT_PRED_FORMAT2'
GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_)
^build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:133: expanded from macro 'GTEST_PRED_FORMAT2_'
GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), on_failure)
^build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:78: expanded from macro 'GTEST_ASSERT_'
if (const ::testing::AssertionResult gtest_ar = (expression)) \
^|
|
||
| // One JitCall is enough — if the wrapper regresses to plain placement | ||
| // new, MakeFunctionCallable fails to compile without <new>. | ||
| Cpp::Declare("int jc_sq(int x) { return x * x; }"); |
There was a problem hiding this comment.
warning: too few arguments to function call, expected 2, have 1 [clang-diagnostic-error]
.
^| auto JC = Cpp::MakeFunctionCallable(Cpp::GetNamed("jc_sq" DFLT_NULLPTR)); | ||
| ASSERT_TRUE(JC.isValid()); | ||
| int arg = 5, ret = 0; | ||
| void* args[] = {&arg}; |
There was a problem hiding this comment.
warning: do not declare C-style arrays, use std::array<> instead [cppcoreguidelines-avoid-c-arrays]
;
^| auto JC = Cpp::MakeFunctionCallable(Cpp::GetNamed("jc_sq" DFLT_NULLPTR)); | ||
| ASSERT_TRUE(JC.isValid()); | ||
| int arg = 5, ret = 0; | ||
| void* args[] = {&arg}; |
There was a problem hiding this comment.
warning: multiple declarations in a single statement reduces readability [readability-isolate-declaration]
| void* args[] = {&arg}; | |
| ; | |
| ;int arg = 5; | |
| int ret = 0; |
| ASSERT_TRUE(JC.isValid()); | ||
| int arg = 5, ret = 0; | ||
| void* args[] = {&arg}; | ||
| JC.Invoke(&ret, {args, 1}); |
There was a problem hiding this comment.
warning: do not implicitly decay an array into a pointer; consider using gsl::array_view or an explicit cast instead [cppcoreguidelines-pro-bounds-array-to-pointer-decay]
;
^| auto JCRef = Cpp::MakeFunctionCallable(RefFD); | ||
| EXPECT_TRUE(JCRef.getKind() == Cpp::JitCall::kGenericCall); | ||
| int* ref_ret = nullptr; | ||
| JCRef.Invoke(&ref_ret); |
There was a problem hiding this comment.
warning: multilevel pointer conversion from 'int **' to 'void *', please use explicit cast [bugprone-multi-level-implicit-pointer-conversion]
;
^| EXPECT_EQ(*ref_ret, 7); | ||
| *ref_ret = 11; | ||
| int* ref_ret2 = nullptr; | ||
| JCRef.Invoke(&ref_ret2); |
There was a problem hiding this comment.
warning: multilevel pointer conversion from 'int **' to 'void *', please use explicit cast [bugprone-multi-level-implicit-pointer-conversion]
;
^b972a1d to
b16bb04
Compare
| // from the arena base (not past a cookie header). | ||
| const size_t T = Cpp::SizeOf(scope); | ||
| for (size_t i = 0; i < kN; ++i) { | ||
| int* slot = reinterpret_cast<int*>(reinterpret_cast<char*>(arena) + i * T); |
There was a problem hiding this comment.
warning: do not use reinterpret_cast [cppcoreguidelines-pro-type-reinterpret-cast]
++i) {
^| // from the arena base (not past a cookie header). | ||
| const size_t T = Cpp::SizeOf(scope); | ||
| for (size_t i = 0; i < kN; ++i) { | ||
| int* slot = reinterpret_cast<int*>(reinterpret_cast<char*>(arena) + i * T); |
There was a problem hiding this comment.
warning: do not use reinterpret_cast [cppcoreguidelines-pro-type-reinterpret-cast]
++i) {
^| const size_t T = Cpp::SizeOf(scope); | ||
| for (size_t i = 0; i < kN; ++i) { | ||
| int* slot = reinterpret_cast<int*>(reinterpret_cast<char*>(arena) + i * T); | ||
| EXPECT_EQ(*slot, 0xC0DE) << "element " << i << " not at expected offset"; |
There was a problem hiding this comment.
warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
| EXPECT_EQ(*slot, 0xC0DE) << "element " << i << " not at expected offset"; | |
| ++i) { | |
| * T);() |
| if (llvm::sys::RunningOnValgrind()) | ||
| GTEST_SKIP() << "XFAIL due to Valgrind report"; | ||
| std::vector<const char*> interpreter_args = { "-include", "new", "-Xclang", "-iwithsysroot/include/compat" }; | ||
| std::vector<const char*> interpreter_args = {"-Xclang", |
There was a problem hiding this comment.
warning: no header providing "std::vector" is directly included [misc-include-cleaner]
unittests/CppInterOp/InterpreterTest.cpp:2:
+ #include <vector>b16bb04 to
3add78b
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #912 +/- ##
==========================================
+ Coverage 85.89% 85.94% +0.04%
==========================================
Files 15 15
Lines 4971 4995 +24
==========================================
+ Hits 4270 4293 +23
- Misses 701 702 +1
🚀 New features to boost your workflow:
|
ad9a0fb to
3abcaec
Compare
| #include <cstddef> | ||
| #include <cstdint> | ||
| #include <set> | ||
| #include <string> |
There was a problem hiding this comment.
warning: included header set is not used directly [misc-include-cleaner]
| #include <string> | |
| #include <string> |
| #include <cstdint> | ||
| #include <set> | ||
| #include <string> | ||
| #include <vector> |
There was a problem hiding this comment.
warning: included header string is not used directly [misc-include-cleaner]
| #include <vector> | |
| #include <vector> |
| #include <set> | ||
| #include <string> | ||
| #include <vector> | ||
|
|
There was a problem hiding this comment.
warning: included header vector is not used directly [misc-include-cleaner]
| void** m_Args = nullptr; | ||
| size_t m_ArgSize = 0; | ||
| // Clang struggles with =default... | ||
| ArgList() {} |
There was a problem hiding this comment.
warning: use '= default' to define a trivial default constructor [modernize-use-equals-default]
| ArgList() {} | |
| ArgList() = default; |
|
|
||
| public: | ||
| [[nodiscard]] Kind getKind() const { return m_Kind; } | ||
| bool isValid() const { return getKind() != kUnknown; } |
There was a problem hiding this comment.
warning: function 'isValid' should be marked [[nodiscard]] [modernize-use-nodiscard]
| bool isValid() const { return getKind() != kUnknown; } | |
| [[nodiscard]] bool isValid() const { return getKind() != kUnknown; } |
| public: | ||
| [[nodiscard]] Kind getKind() const { return m_Kind; } | ||
| bool isValid() const { return getKind() != kUnknown; } | ||
| bool isInvalid() const { return !isValid(); } |
There was a problem hiding this comment.
warning: function 'isInvalid' should be marked [[nodiscard]] [modernize-use-nodiscard]
| bool isInvalid() const { return !isValid(); } | |
| [[nodiscard]] bool isInvalid() const { return !isValid(); } |
| #ifndef NDEBUG | ||
| ReportInvokeStart(object, nary, withFree); | ||
| #endif // NDEBUG | ||
| m_DestructorCall(object, nary, withFree); |
There was a problem hiding this comment.
warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access]
m_DestructorCall(object, nary, withFree);
^| "Invalid args!"); | ||
| ReportInvokeStart(result, args, nullptr); | ||
| #endif // NDEBUG | ||
| m_ConstructorCall(result, nary, args.m_ArgSize, args.m_Args, is_arena); |
There was a problem hiding this comment.
warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access]
m_ConstructorCall(result, nary, args.m_ArgSize, args.m_Args, is_arena);
^|
|
||
| // FIXME: Rework GetDimensions to make this enum redundant. | ||
| namespace DimensionValue { | ||
| enum : long int { |
There was a problem hiding this comment.
warning: enum '(unnamed enum at /github/workspace/include/CppInterOp/CppInterOpTypes.h:338:1)' uses a larger base type ('long', size: 8 bytes) than necessary for its value set, consider using 'std::int8_t' (1 byte) as the base type to reduce its size [performance-enum-size]
enum : long int {
^| // symbol is always resolvable there, even when the host's dynamic | ||
| // linker does not expose libclangInterpreter's copy. | ||
| namespace { | ||
| void* CppInterOpPlacementNew(std::size_t, void* __p, |
There was a problem hiding this comment.
warning: declaration uses identifier '__p', which is a reserved identifier [bugprone-reserved-identifier]
void* CppInterOpPlacementNew(std::size_t, void* __p,
^this fix will not be applied because it overlaps with another fix
6593d5e to
9352072
Compare
| // symbol is always resolvable there, even when the host's dynamic | ||
| // linker does not expose libclangInterpreter's copy. | ||
| namespace { | ||
| void* CppInterOpPlacementNew(std::size_t, void* __p, |
There was a problem hiding this comment.
warning: invalid case style for parameter '__p' [readability-identifier-naming]
void* CppInterOpPlacementNew(std::size_t, void* __p,
^this fix will not be applied because it overlaps with another fix
| // Apply the target-triple's symbol prefix (empty on ELF, `_` on macOS | ||
| // Mach-O / x86 Windows) so the interned name matches what the JIT | ||
| // will look up when resolving references from compiled modules. | ||
| MangleAndInterner Mangle(ES, Jit.getDataLayout()); |
There was a problem hiding this comment.
warning: no header providing "llvm::orc::MangleAndInterner" is directly included [misc-include-cleaner]
lib/CppInterOp/CppInterOp.cpp:84:
- #include <map>
+ #include <llvm/ExecutionEngine/Orc/Mangling.h>
+ #include <map>| compat::maybeMangleDeclName(GlobalDecl(FD), mangled); | ||
| DefineAbsoluteSymbol( | ||
| *I, mangled.c_str(), | ||
| reinterpret_cast<uint64_t>(&CppInterOpPlacementNew)); |
There was a problem hiding this comment.
warning: do not use reinterpret_cast [cppcoreguidelines-pro-type-reinterpret-cast]
^| ASSERT_NE(arena, nullptr); | ||
|
|
||
| EXPECT_EQ(Cpp::Construct(scope, arena), arena); | ||
| EXPECT_EQ(*reinterpret_cast<int*>(arena), 42); |
There was a problem hiding this comment.
warning: do not use reinterpret_cast [cppcoreguidelines-pro-type-reinterpret-cast]
EXPECT_EQ(*reinterpret_cast<int*>(arena), 42);
^| << "Wrapper's placement-new expression failed to compile for a " | ||
| "class that declares its own operator new; add `::` to force " | ||
| "global-scope lookup."; | ||
| EXPECT_EQ(*reinterpret_cast<int*>(arena), 123); |
There was a problem hiding this comment.
warning: do not use reinterpret_cast [cppcoreguidelines-pro-type-reinterpret-cast]
;
^9352072 to
302308c
Compare
| std::string mangled; | ||
| compat::maybeMangleDeclName(GlobalDecl(FD), mangled); | ||
| DefineAbsoluteSymbol(*I, mangled.c_str(), | ||
| reinterpret_cast<uint64_t>(&CppInterOpPlacementNew)); |
There was a problem hiding this comment.
warning: do not use reinterpret_cast [cppcoreguidelines-pro-type-reinterpret-cast]
^dd4fecf to
f66e448
Compare
The JitCall wrapper generator emits placement-new expressions on two hot paths (`make_narg_call_with_return` and the `make_narg_ctor_with_return` scalar branch), and the array-ctor branch emitted `new (p) T[n]`. Each of those forms binds against the standard placement operators declared in `<new>`, so every JitCall consumer had to pull `<new>` into the interpreter's TU and every ctor-using test passed `-include new` on the command line. Emit `::new (p, __ci_newtag) T(...)` instead. The tagged scalar overload `operator new(size_t, void*, __clang_Interpreter_NewTag)` is preloaded by clang-repl's Runtimes string (LLVM 18+, llvm/llvm-project@1566f1ffc6b5), and its definition is registered in the JIT dylib by a local forwarder `CppInterOpPlacementNew` plumbed through `DefineAbsoluteSymbol` -- otherwise embedders that dlopen libclangCppInterOp with RTLD_LOCAL (cppyy, the DispatchTests binary) cannot resolve `_ZnwmPv26__clang_Interpreter_NewTag` at JIT link time. `DefineAbsoluteSymbol` now uses `Jit.mangleAndIntern` so the registered key carries the target DataLayout's global-symbol prefix (empty on ELF, `_` on Mach-O / 32-bit COFF). The array default-ctor branch becomes a loop of scalar tagged placements: a tagged `operator new[]` would insert an Itanium ABI array cookie ([expr.new]/8, Itanium C++ ABI S2.7) and break the `Construct(scope, arena, n) == arena` contract. The unary `::` qualifier on every placement-new emission forces name lookup straight to global scope; per [class.free]/2, if the allocated type has any class-scope `operator new`, global scope is otherwise not consulted as a fallback and the wrapper refuses to compile (cppyy's test14_new_overloader was the regression). The non-tagged `: new T(args)` arm of the is_arena ternary stays unqualified so `Cpp::Construct(scope)` still routes through the class allocator. Regression coverage: DispatchSmokeTest.TaggedPlacementNewResolvable pins the JIT-link path under dlopen-RTLD_LOCAL; DispatchSmokeTest. PlacementConstructTaggedNew pins the wrapper-emit path; and the JitCallNoNewHeader / ArrayConstructNoCookie / ConstructClassWith OperatorNew tests under FunctionReflectionTest pin the no-`<new>` premise, the no-cookie array contract, and the global-vs-class allocator routing respectively. Valgrind-XFAIL skips at the new test sites are gated `#if CLANG_VERSION_MAJOR < 22`; LLVM 22 dropped `llvm/Support/Valgrind.h`.
f66e448 to
1d338e4
Compare
This patch removes the requirement for JitCall to include the header to access operator placement new. It now reuses the symbol provided by clang-repl.