Skip to content

Commit 5d2637a

Browse files
committed
[cxx-interop] add support for 'mutableAddress' pointee for non-copyable C++ types
1 parent 86e5556 commit 5d2637a

File tree

4 files changed

+138
-3
lines changed

4 files changed

+138
-3
lines changed

lib/ClangImporter/SwiftDeclSynthesizer.cpp

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1542,6 +1542,29 @@ synthesizeUnwrappingGetterOrAddressGetterBody(AbstractFunctionDecl *afd,
15421542
pointeePropertyRefExpr->setType(elementTy);
15431543
propertyExpr = pointeePropertyRefExpr;
15441544
}
1545+
// Cast an 'address' result from a mutable pointer if needed.
1546+
if (isAddress &&
1547+
getterImpl->getResultInterfaceType()->isUnsafeMutablePointer()) {
1548+
auto reinterpretCast = cast<FuncDecl>(
1549+
getBuiltinValueDecl(ctx, ctx.getIdentifier("reinterpretCast")));
1550+
auto rawTy = getterImpl->getResultInterfaceType();
1551+
auto enumTy = elementTy;
1552+
SubstitutionMap subMap = SubstitutionMap::get(
1553+
reinterpretCast->getGenericSignature(), {rawTy, enumTy}, {});
1554+
ConcreteDeclRef concreteDeclRef(reinterpretCast, subMap);
1555+
auto reinterpretCastRef = new (ctx)
1556+
DeclRefExpr(concreteDeclRef, DeclNameLoc(), /*implicit*/ true);
1557+
FunctionType::ExtInfo info;
1558+
reinterpretCastRef->setType(
1559+
FunctionType::get({FunctionType::Param(rawTy)}, enumTy, info));
1560+
1561+
auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {propertyExpr});
1562+
auto reinterpreted =
1563+
CallExpr::createImplicit(ctx, reinterpretCastRef, argList);
1564+
reinterpreted->setType(enumTy);
1565+
reinterpreted->setThrows(nullptr);
1566+
propertyExpr = reinterpreted;
1567+
}
15451568

15461569
auto returnStmt = new (ctx) ReturnStmt(SourceLoc(), propertyExpr,
15471570
/*implicit*/ true);
@@ -1611,6 +1634,26 @@ synthesizeUnwrappingSetterBody(AbstractFunctionDecl *afd, void *context) {
16111634
return {body, /*isTypeChecked*/ true};
16121635
}
16131636

1637+
static std::pair<BraceStmt *, bool>
1638+
synthesizeUnwrappingAddressSetterBody(AbstractFunctionDecl *afd,
1639+
void *context) {
1640+
auto setterDecl = cast<AccessorDecl>(afd);
1641+
auto setterImpl = static_cast<FuncDecl *>(context);
1642+
1643+
ASTContext &ctx = setterDecl->getASTContext();
1644+
1645+
auto selfArg = createSelfArg(setterDecl);
1646+
auto *setterImplCallExpr =
1647+
createAccessorImplCallExpr(setterImpl, selfArg, nullptr);
1648+
1649+
auto returnStmt = new (ctx) ReturnStmt(SourceLoc(), setterImplCallExpr,
1650+
/*implicit*/ true);
1651+
1652+
auto body = BraceStmt::create(ctx, SourceLoc(), {returnStmt}, SourceLoc(),
1653+
/*implicit*/ true);
1654+
return {body, /*isTypeChecked*/ true};
1655+
}
1656+
16141657
SubscriptDecl *SwiftDeclSynthesizer::makeSubscript(FuncDecl *getter,
16151658
FuncDecl *setter) {
16161659
assert((getter || setter) &&
@@ -1755,8 +1798,9 @@ SwiftDeclSynthesizer::makeDereferencedPointeeProperty(FuncDecl *getter,
17551798
paramVarDecl->setSpecifier(ParamSpecifier::Default);
17561799
paramVarDecl->setInterfaceType(elementTy);
17571800

1758-
auto setterParamList =
1759-
ParameterList::create(ctx, {paramVarDecl});
1801+
auto setterParamList = useAddress
1802+
? ParameterList::create(ctx, {})
1803+
: ParameterList::create(ctx, {paramVarDecl});
17601804

17611805
setterDecl = AccessorDecl::create(
17621806
ctx, setterImpl->getLoc(), setterImpl->getLoc(),
@@ -1773,7 +1817,10 @@ SwiftDeclSynthesizer::makeDereferencedPointeeProperty(FuncDecl *getter,
17731817
setterDecl->setImplicit();
17741818
setterDecl->setIsDynamic(false);
17751819
setterDecl->setIsTransparent(true);
1776-
setterDecl->setBodySynthesizer(synthesizeUnwrappingSetterBody, setterImpl);
1820+
setterDecl->setBodySynthesizer(useAddress
1821+
? synthesizeUnwrappingAddressSetterBody
1822+
: synthesizeUnwrappingSetterBody,
1823+
setterImpl);
17771824

17781825
if (setterImpl->isMutating()) {
17791826
setterDecl->setSelfAccessKind(SelfAccessKind::Mutating);

test/Interop/Cxx/operators/move-only/Inputs/move-only-cxx-value-operators.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,17 @@ class NonCopyableHolderConstDeref {
3535
inline const NonCopyable & operator *() const { return x; }
3636
};
3737

38+
class NonCopyableHolderPairedDeref {
39+
NONCOPYABLE_HOLDER_WRAPPER(NonCopyableHolderPairedDeref)
40+
41+
inline const NonCopyable & operator *() const { return x; }
42+
inline NonCopyable & operator *() { return x; }
43+
};
44+
45+
class NonCopyableHolderMutDeref {
46+
NONCOPYABLE_HOLDER_WRAPPER(NonCopyableHolderMutDeref)
47+
48+
inline NonCopyable & operator *() { return x; }
49+
};
50+
3851
#endif // TEST_INTEROP_CXX_OPERATORS_MOVE_ONLY_OPS_H

test/Interop/Cxx/operators/move-only/move-only-synthesized-properties.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,43 @@ MoveOnlyCxxOperators.test("NonCopyableHolderConstDeref pointee borrow") {
2929
expectEqual(k, 11)
3030
}
3131

32+
MoveOnlyCxxOperators.test("testNonCopyableHolderPairedDeref pointee borrow") {
33+
var holder = NonCopyableHolderPairedDeref(11)
34+
var k = borrowNC(holder.pointee)
35+
expectEqual(k, 33)
36+
k = holder.pointee.method(2)
37+
expectEqual(k, 22)
38+
k = holder.pointee.x
39+
expectEqual(k, 11)
40+
k = inoutNC(&holder.pointee, -1)
41+
expectEqual(k, -1)
42+
expectEqual(holder.pointee.x, -1)
43+
holder.pointee.mutMethod(3)
44+
expectEqual(holder.pointee.x, 3)
45+
holder.pointee.x = 34
46+
expectEqual(holder.pointee.x, 34)
47+
consumingNC(holder.pointee)
48+
expectEqual(holder.pointee.x, 0)
49+
}
50+
51+
MoveOnlyCxxOperators.test("testNonCopyableHolderMutDeref pointee borrow") {
52+
var holder = NonCopyableHolderMutDeref(11)
53+
var k = borrowNC(holder.pointee)
54+
expectEqual(k, 33)
55+
k = holder.pointee.method(2)
56+
expectEqual(k, 22)
57+
k = holder.pointee.x
58+
expectEqual(k, 11)
59+
k = inoutNC(&holder.pointee, -1)
60+
expectEqual(k, -1)
61+
expectEqual(holder.pointee.x, -1)
62+
holder.pointee.mutMethod(3)
63+
expectEqual(holder.pointee.x, 3)
64+
holder.pointee.x = 34
65+
expectEqual(holder.pointee.x, 34)
66+
consumingNC(holder.pointee)
67+
expectEqual(holder.pointee.x, 0)
68+
}
69+
70+
3271
runAllTests()

test/Interop/Cxx/operators/move-only/move-only-synthesized-property-typecheck.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,40 @@ func testNonCopyableHolderConstDerefPointee() {
3333
#endif
3434
}
3535

36+
func testNonCopyableHolderPairedDerefPointee() {
37+
var holder = NonCopyableHolderPairedDeref(11)
38+
_ = borrowNC(holder.pointee) // ok
39+
_ = holder.pointee.method(2)
40+
_ = holder.pointee.x
41+
_ = inoutNC(&holder.pointee)
42+
_ = holder.pointee.mutMethod(1)
43+
holder.pointee.x = 2
44+
consumingNC(holder.pointee)
45+
let consumeVal = holder.pointee
46+
_ = borrowNC(consumeVal)
47+
}
48+
49+
func testNonCopyableHolderMutDerefPointee() {
50+
var holder = NonCopyableHolderMutDeref(11)
51+
_ = borrowNC(holder.pointee) // ok
52+
_ = holder.pointee.method(2)
53+
_ = holder.pointee.x
54+
_ = inoutNC(&holder.pointee)
55+
_ = holder.pointee.mutMethod(1)
56+
holder.pointee.x = 2
57+
consumingNC(holder.pointee)
58+
let consumeVal = holder.pointee
59+
_ = borrowNC(consumeVal)
60+
}
61+
62+
func testNonCopyableHolderMutDerefPointeeLet() {
63+
#if NO_CONSUME
64+
let holder = NonCopyableHolderMutDeref(11) // expected-note {{}}
65+
_ = borrowNC(holder.pointee) // expected-error {{cannot use mutating getter on immutable value: 'holder' is a 'let' constant}}
66+
#endif
67+
}
68+
3669
testNonCopyableHolderConstDerefPointee()
70+
testNonCopyableHolderPairedDerefPointee()
71+
testNonCopyableHolderMutDerefPointee()
72+
testNonCopyableHolderMutDerefPointeeLet()

0 commit comments

Comments
 (0)