Skip to content

Commit 2e79822

Browse files
authored
[embind] Support policies in allow_subclass (#26307)
Add support for passing policies to the allow_subclass method in embind. This allows the use of constructors that require policies, such as those taking raw pointers, when enabling C++ subclassing from JavaScript. Previously, allow_subclass only accepted a constructor argument, making it impossible to use policies like allow_raw_pointer with the generated 'implement' method. Fixes #26270
1 parent 8a64538 commit 2e79822

3 files changed

Lines changed: 68 additions & 6 deletions

File tree

system/include/emscripten/bind.h

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1424,6 +1424,32 @@ struct RegisterClassMethod<FunctionTag<Callable, ReturnType (ThisType, Args...)>
14241424
}
14251425
};
14261426

1427+
// Helper structs for shifting argument indices when a policy is applied.
1428+
template<typename Slot>
1429+
struct ShiftSlot {
1430+
using type = Slot;
1431+
};
1432+
1433+
template<int Index>
1434+
struct ShiftSlot<arg<Index>> {
1435+
using type = arg<Index + 1>;
1436+
};
1437+
1438+
template<typename Policy>
1439+
struct ShiftPolicy {
1440+
using type = Policy;
1441+
};
1442+
1443+
template<typename Slot>
1444+
struct ShiftPolicy<allow_raw_pointer<Slot>> {
1445+
using type = allow_raw_pointer<typename ShiftSlot<Slot>::type>;
1446+
};
1447+
1448+
template<typename Slot>
1449+
struct ShiftPolicy<nonnull<Slot>> {
1450+
using type = nonnull<typename ShiftSlot<Slot>::type>;
1451+
};
1452+
14271453
} // end namespace internal
14281454

14291455
template<typename... ConstructorArgs>
@@ -1532,10 +1558,11 @@ class class_ {
15321558
return *this;
15331559
}
15341560

1535-
template<typename WrapperType, typename... ConstructorArgs>
1561+
template<typename WrapperType, typename... ConstructorArgs, typename... Policies>
15361562
EMSCRIPTEN_ALWAYS_INLINE const class_& allow_subclass(
15371563
const char* wrapperClassName,
1538-
::emscripten::constructor<ConstructorArgs...> = ::emscripten::constructor<>()
1564+
::emscripten::constructor<ConstructorArgs...> = ::emscripten::constructor<>(),
1565+
Policies... policies
15391566
) const {
15401567
using namespace internal;
15411568

@@ -1549,18 +1576,20 @@ class class_ {
15491576
class_function(
15501577
"implement",
15511578
&wrapped_new<WrapperType*, WrapperType, val, ConstructorArgs...>,
1552-
allow_raw_pointer<ret_val>(), nonnull<ret_val>())
1579+
allow_raw_pointer<ret_val>(), nonnull<ret_val>(),
1580+
typename ShiftPolicy<Policies>::type()...)
15531581
.class_function(
15541582
"extend",
15551583
&wrapped_extend<WrapperType>)
15561584
;
15571585
}
15581586

1559-
template<typename WrapperType, typename PointerType, typename... ConstructorArgs>
1587+
template<typename WrapperType, typename PointerType, typename... ConstructorArgs, typename... Policies>
15601588
EMSCRIPTEN_ALWAYS_INLINE const class_& allow_subclass(
15611589
const char* wrapperClassName,
15621590
const char* pointerName,
1563-
::emscripten::constructor<ConstructorArgs...> = ::emscripten::constructor<>()
1591+
::emscripten::constructor<ConstructorArgs...> = ::emscripten::constructor<>(),
1592+
Policies... policies
15641593
) const {
15651594
using namespace internal;
15661595

@@ -1575,7 +1604,8 @@ class class_ {
15751604
class_function(
15761605
"implement",
15771606
&wrapped_new<PointerType, WrapperType, val, ConstructorArgs...>,
1578-
allow_raw_pointer<ret_val>())
1607+
allow_raw_pointer<ret_val>(),
1608+
typename ShiftPolicy<Policies>::type()...)
15791609
.class_function(
15801610
"extend",
15811611
&wrapped_extend<WrapperType>)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#include <emscripten/bind.h>
2+
3+
using namespace emscripten;
4+
5+
struct Base {
6+
virtual ~Base() {}
7+
};
8+
9+
struct Sub : Base {
10+
Sub(Base* b) {}
11+
};
12+
13+
struct SubWrapper : wrapper<Sub> {
14+
EMSCRIPTEN_WRAPPER(SubWrapper);
15+
};
16+
17+
EMSCRIPTEN_BINDINGS(test) {
18+
class_<Base>("Base")
19+
.constructor<>()
20+
;
21+
22+
class_<Sub>("Sub")
23+
.allow_subclass<SubWrapper>("SubWrapper", constructor<Base*>(), allow_raw_pointer<arg<0>>())
24+
;
25+
}
26+
27+
int main() {
28+
return 0;
29+
}

test/test_other.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3381,6 +3381,9 @@ def test_embind_no_raw_pointers(self, filename):
33813381
def test_embind_allow_raw_pointer(self):
33823382
self.emcc(test_file('embind/test_embind_allow_raw_pointer.cpp'), ['-lembind'])
33833383

3384+
def test_embind_subclass_pointer(self):
3385+
self.emcc(test_file('embind/test_embind_subclass_pointer.cpp'), ['-lembind'])
3386+
33843387
@is_slow_test
33853388
@parameterized({
33863389
'': [],

0 commit comments

Comments
 (0)