Commit f87b3068 authored by Harris Hancock's avatar Harris Hancock

MSVC non-const copy capture workaround

MSVC refuses the following code:

struct Foo { Foo(Foo&) {} };
Foo foo;
[foo] {}();

because it only seems to want to consider const copy constructors when
capturing objects by value in lambda capture lists.
parent 9d5c1579
......@@ -499,7 +499,7 @@ public:
request.set("j", true);
return request.send().then(
[this,context](capnp::Response<DynamicStruct>&& response) mutable {
[this,KJ_CPCAP(context)](capnp::Response<DynamicStruct>&& response) mutable {
EXPECT_EQ("foo", response.get("x").as<Text>());
auto result = context.getResults();
......
......@@ -64,7 +64,8 @@ protected:
if (params.getTailCall()) {
return context.tailCall(kj::mv(req));
} else {
return req.send().then([context](Response<test::TestMembrane::Result>&& result) mutable {
return req.send().then(
[KJ_CPCAP(context)](Response<test::TestMembrane::Result>&& result) mutable {
context.setResults(result);
});
}
......@@ -76,7 +77,8 @@ protected:
if (params.getTailCall()) {
return context.tailCall(kj::mv(req));
} else {
return req.send().then([context](Response<test::TestMembrane::Result>&& result) mutable {
return req.send().then(
[KJ_CPCAP(context)](Response<test::TestMembrane::Result>&& result) mutable {
context.setResults(result);
});
}
......
......@@ -1072,7 +1072,7 @@ public:
auto cap = context.getParams().getCap();
context.releaseParams();
return cap.saveRequest().send()
.then([context](Response<Persistent<Text>::SaveResults> response) mutable {
.then([KJ_CPCAP(context)](Response<Persistent<Text>::SaveResults> response) mutable {
context.getResults().initSturdyRef().getObjectId().setAs<Text>(
kj::str("imported-", response.getSturdyRef()));
});
......@@ -1082,7 +1082,8 @@ public:
auto cap = context.getParams().getCap();
context.releaseParams();
return cap.saveRequest().send()
.then([context](Response<Persistent<test::TestSturdyRef>::SaveResults> response) mutable {
.then([KJ_CPCAP(context)]
(Response<Persistent<test::TestSturdyRef>::SaveResults> response) mutable {
context.getResults().setSturdyRef(kj::str("exported-",
response.getSturdyRef().getObjectId().getAs<Text>()));
});
......
......@@ -66,7 +66,7 @@ private:
kj::Promise<bool> AsyncMessageReader::read(kj::AsyncInputStream& inputStream,
kj::ArrayPtr<word> scratchSpace) {
return inputStream.tryRead(firstWord, sizeof(firstWord), sizeof(firstWord))
.then([this,&inputStream,scratchSpace](size_t n) mutable -> kj::Promise<bool> {
.then([this,&inputStream,KJ_CPCAP(scratchSpace)](size_t n) mutable -> kj::Promise<bool> {
if (n == 0) {
return false;
} else if (n < sizeof(firstWord)) {
......@@ -95,7 +95,7 @@ kj::Promise<void> AsyncMessageReader::readAfterFirstWord(kj::AsyncInputStream& i
// Read sizes for all segments except the first. Include padding if necessary.
moreSizes = kj::heapArray<_::WireValue<uint32_t>>(segmentCount() & ~1);
return inputStream.read(moreSizes.begin(), moreSizes.size() * sizeof(moreSizes[0]))
.then([this,&inputStream,scratchSpace]() mutable {
.then([this,&inputStream,KJ_CPCAP(scratchSpace)]() mutable {
return readSegments(inputStream, scratchSpace);
});
} else {
......
......@@ -943,7 +943,7 @@ kj::Promise<void> TestPipelineImpl::getCap(GetCapContext context) {
request.setJ(true);
return request.send().then(
[this,context](Response<test::TestInterface::FooResults>&& response) mutable {
[this,KJ_CPCAP(context)](Response<test::TestInterface::FooResults>&& response) mutable {
EXPECT_EQ("foo", response.getX());
auto result = context.getResults();
......@@ -1005,7 +1005,7 @@ kj::Promise<void> TestMoreStuffImpl::callFoo(CallFooContext context) {
request.setJ(true);
return request.send().then(
[context](Response<test::TestInterface::FooResults>&& response) mutable {
[KJ_CPCAP(context)](Response<test::TestInterface::FooResults>&& response) mutable {
EXPECT_EQ("foo", response.getX());
context.getResults().setS("bar");
});
......@@ -1017,13 +1017,13 @@ kj::Promise<void> TestMoreStuffImpl::callFooWhenResolved(CallFooWhenResolvedCont
auto params = context.getParams();
auto cap = params.getCap();
return cap.whenResolved().then([cap,context]() mutable {
return cap.whenResolved().then([KJ_CPCAP(cap),KJ_CPCAP(context)]() mutable {
auto request = cap.fooRequest();
request.setI(123);
request.setJ(true);
return request.send().then(
[context](Response<test::TestInterface::FooResults>&& response) mutable {
[KJ_CPCAP(context)](Response<test::TestInterface::FooResults>&& response) mutable {
EXPECT_EQ("foo", response.getX());
context.getResults().setS("bar");
});
......@@ -1059,7 +1059,7 @@ kj::Promise<void> TestMoreStuffImpl::callHeld(CallHeldContext context) {
request.setJ(true);
return request.send().then(
[context](Response<test::TestInterface::FooResults>&& response) mutable {
[KJ_CPCAP(context)](Response<test::TestInterface::FooResults>&& response) mutable {
EXPECT_EQ("foo", response.getX());
context.getResults().setS("bar");
});
......@@ -1092,7 +1092,7 @@ kj::Promise<void> TestMoreStuffImpl::loop(uint depth, test::TestInterface::Clien
ADD_FAILURE() << "Looped too long, giving up.";
return kj::READY_NOW;
} else {
return kj::evalLater([=]() mutable {
return kj::evalLater([this,depth,KJ_CPCAP(cap),KJ_CPCAP(context)]() mutable {
return loop(depth + 1, cap, context);
});
}
......
......@@ -334,7 +334,7 @@ private:
}
return op->onComplete()
.then([this,bufs,minBytes,alreadyRead](Win32IocpEventPort::IoResult result) mutable
.then([this,KJ_CPCAP(bufs),minBytes,alreadyRead](Win32IocpEventPort::IoResult result) mutable
-> Promise<size_t> {
if (result.errorCode != ERROR_SUCCESS) {
if (alreadyRead > 0) {
......@@ -386,7 +386,7 @@ private:
}
return op->onComplete()
.then([this,bufs](Win32IocpEventPort::IoResult result) mutable -> Promise<void> {
.then([this,KJ_CPCAP(bufs)](Win32IocpEventPort::IoResult result) mutable -> Promise<void> {
if (result.errorCode != ERROR_SUCCESS) {
KJ_FAIL_WIN32("WSASend()", result.errorCode) { break; }
return kj::READY_NOW;
......@@ -1015,7 +1015,7 @@ private:
}).then([](Own<AsyncIoStream>&& stream) -> Promise<Own<AsyncIoStream>> {
// Success, pass along.
return kj::mv(stream);
}, [&lowLevel,addrs](Exception&& exception) mutable -> Promise<Own<AsyncIoStream>> {
}, [&lowLevel,KJ_CPCAP(addrs)](Exception&& exception) mutable -> Promise<Own<AsyncIoStream>> {
// Connect failed.
if (addrs.size() > 1) {
// Try the next address instead.
......
......@@ -373,6 +373,24 @@ struct DisallowConstCopy {
DisallowConstCopy& operator=(DisallowConstCopy&&) = default;
};
#if _MSC_VER
#define KJ_CPCAP(obj) obj=::kj::cp(obj)
// TODO(msvc): MSVC refuses to invoke non-const versions of copy constructors in by-value lambda
// captures. Wrap your captured object in this macro to force the compiler to perform a copy.
// Example:
//
// struct Foo: DisallowConstCopy {};
// Foo foo;
// auto lambda = [KJ_CPCAP(foo)] {};
#else
#define KJ_CPCAP(obj) obj
// Clang and gcc both already perform copy capturing correctly with non-const copy constructors.
#endif
template <typename T>
struct DisallowConstCopyIfNotConst: public DisallowConstCopy {
// Inherit from this when implementing a template that contains a pointer to T and which should
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment