Skip to content

Commit 90f8b37

Browse files
committed
Fix $Proxy.wrap mapping for empty structs with no fields
Trying to pass an empty $Proxy.wrap struct with no fields fails because BuildOne overload for the last field number is incorrectly declared to accept an lvalue Builder reference instead of a univeral reference, and the CustomBuildField overload which calls BuildOne passes an rvalue Builder. The problem did not happen as long as the wrapped struct had at least one field because CustomBuildField would call the other BuildOne overload for the first field number which accepts an rvalue Builder, and that BuildOne overload would call the next BuildOne overload for the next field number, passing the builder as an lvalue. A test is included which triggers the bug. Compiler output before the bugfix looked like: include/mp/proxy-types.h:1066:5: error: no matching function for call to 'BuildOne' 1066 | BuildOne<0>(local_type, invoke_context, output.init(), value); include/mp/proxy-types.h:1050:6: note: candidate function [with index = 0, LocalType = mp::test::FooEmpty, Value = mp::test::FooEmpty, Output = mp::test::messages::FooEmpty::Builder] not viable: expects an lvalue for 3rd argument 1050 | void BuildOne(TypeList<LocalType> param,
1 parent e454072 commit 90f8b37

File tree

4 files changed

+13
-2
lines changed

4 files changed

+13
-2
lines changed

include/mp/proxy-types.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,8 +1049,8 @@ void BuildOne(TypeList<LocalType> param,
10491049
template <size_t index, typename LocalType, typename Value, typename Output>
10501050
void BuildOne(TypeList<LocalType> param,
10511051
InvokeContext& invoke_context,
1052-
Output& output,
1053-
Value& value,
1052+
Output&& output,
1053+
Value&& value,
10541054
typename std::enable_if<index == ProxyType<LocalType>::fields>::type* enable = nullptr)
10551055
{
10561056
}

test/mp/test/foo.capnp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ interface FooInterface $Proxy.wrap("mp::test::FooImplementation") {
2424
callbackSaved @9 (context :Proxy.Context, arg: Int32) -> (result :Int32);
2525
callbackExtended @10 (context :Proxy.Context, callback :ExtendedCallback, arg: Int32) -> (result :Int32);
2626
passCustom @11 (arg :FooCustom) -> (result :FooCustom);
27+
passEmpty @12 (arg :FooEmpty) -> (result :FooEmpty);
2728
}
2829

2930
interface FooCallback $Proxy.wrap("mp::test::FooCallback") {
@@ -46,6 +47,9 @@ struct FooCustom $Proxy.wrap("mp::test::FooCustom") {
4647
v2 @1 :Int32;
4748
}
4849

50+
struct FooEmpty $Proxy.wrap("mp::test::FooEmpty") {
51+
}
52+
4953
struct Pair(T1, T2) {
5054
first @0 :T1;
5155
second @1 :T2;

test/mp/test/foo.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ struct FooCustom
2727
int v2;
2828
};
2929

30+
struct FooEmpty
31+
{
32+
};
33+
3034
class FooCallback
3135
{
3236
public:
@@ -55,6 +59,7 @@ class FooImplementation
5559
int callbackSaved(int arg) { return m_callback->call(arg); }
5660
int callbackExtended(ExtendedCallback& callback, int arg) { return callback.callExtended(arg); }
5761
FooCustom passCustom(FooCustom foo) { return foo; }
62+
FooEmpty passEmpty(FooEmpty foo) { return foo; }
5863
std::shared_ptr<FooCallback> m_callback;
5964
};
6065

test/mp/test/test.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ KJ_TEST("Call FooInterface methods")
106106
KJ_EXPECT(custom_in.v1 == custom_out.v1);
107107
KJ_EXPECT(custom_in.v2 == custom_out.v2);
108108

109+
foo->passEmpty(FooEmpty{});
110+
109111
disconnect_client();
110112
thread.join();
111113

0 commit comments

Comments
 (0)