Skip to content

Commit 16a8ae4

Browse files
committed
[cxx-interop] fix the use of '.pointee' with address accessors for derived-to-base synthesized accessors
1 parent 6a47011 commit 16a8ae4

File tree

5 files changed

+124
-27
lines changed

5 files changed

+124
-27
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "ClangDiagnosticConsumer.h"
2020
#include "ClangIncludePaths.h"
2121
#include "ImporterImpl.h"
22+
#include "SwiftDeclSynthesizer.h"
2223
#include "swift/AST/ASTContext.h"
2324
#include "swift/AST/Builtins.h"
2425
#include "swift/AST/ClangModuleLoader.h"
@@ -4948,6 +4949,18 @@ const clang::CXXMethodDecl *getCalledBaseCxxMethod(FuncDecl *baseMember) {
49484949
if (!returnStmt)
49494950
return nullptr;
49504951
Expr *returnExpr = returnStmt->getResult();
4952+
// Look through a potential 'reinterpresetCast' that can be used
4953+
// to cast UnsafeMutablePointer to UnsafePointer in the synthesized
4954+
// Swift body for `.pointee`.
4955+
if (auto *ce = dyn_cast<CallExpr>(returnExpr)) {
4956+
if (auto *v = ce->getCalledValue()) {
4957+
if (v->getModuleContext() ==
4958+
baseMember->getASTContext().TheBuiltinModule &&
4959+
v->getBaseName().getIdentifier().str() == "reinterpretCast") {
4960+
returnExpr = ce->getArgs()->get(0).getExpr();
4961+
}
4962+
}
4963+
}
49514964
// A member ref expr for `.pointee` access can be wrapping a call
49524965
// when looking through the synthesized Swift body for `.pointee`
49534966
// accessor.
@@ -5325,10 +5338,22 @@ synthesizeBaseClassFieldGetterOrAddressGetterBody(AbstractFunctionDecl *afd,
53255338

53265339
auto *baseMemberCallExpr =
53275340
CallExpr::createImplicit(ctx, baseMemberDotCallExpr, argumentList);
5328-
baseMemberCallExpr->setType(baseGetterMethod->getResultInterfaceType());
5341+
Type resultType = baseGetterMethod->getResultInterfaceType();
5342+
if (kind == AccessorKind::Address && resultType->isUnsafeMutablePointer()) {
5343+
resultType = getterDecl->getResultInterfaceType();
5344+
}
5345+
baseMemberCallExpr->setType(resultType);
53295346
baseMemberCallExpr->setThrows(nullptr);
53305347

5331-
auto returnStmt = new (ctx) ReturnStmt(SourceLoc(), baseMemberCallExpr,
5348+
Expr *returnExpr = baseMemberCallExpr;
5349+
// Cast an 'address' result from a mutable pointer if needed.
5350+
if (kind == AccessorKind::Address &&
5351+
baseGetterMethod->getResultInterfaceType()->isUnsafeMutablePointer())
5352+
returnExpr = SwiftDeclSynthesizer::synthesizeReturnReinterpretCast(
5353+
ctx, baseGetterMethod->getResultInterfaceType(), resultType,
5354+
returnExpr);
5355+
5356+
auto returnStmt = new (ctx) ReturnStmt(SourceLoc(), returnExpr,
53325357
/*implicit=*/true);
53335358

53345359
auto body = BraceStmt::create(ctx, SourceLoc(), {returnStmt}, SourceLoc(),
@@ -5613,10 +5638,11 @@ cloneBaseMemberDecl(ValueDecl *decl, DeclContext *newContext) {
56135638
? StorageIsNotMutable : StorageIsMutable;
56145639
out->setImplInfo(
56155640
accessors[0]->getAccessorKind() == AccessorKind::Address
5616-
? (accessors[1] ? StorageImplInfo(ReadImplKind::Address,
5617-
WriteImplKind::MutableAddress,
5618-
ReadWriteImplKind::MutableAddress)
5619-
: StorageImplInfo(ReadImplKind::Address))
5641+
? (accessors.size() > 1
5642+
? StorageImplInfo(ReadImplKind::Address,
5643+
WriteImplKind::MutableAddress,
5644+
ReadWriteImplKind::MutableAddress)
5645+
: StorageImplInfo(ReadImplKind::Address))
56205646
: StorageImplInfo::getComputed(isMutable));
56215647
out->setIsSetterMutating(true);
56225648
return out;

lib/ClangImporter/SwiftDeclSynthesizer.cpp

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,29 @@ AccessorDecl *SwiftDeclSynthesizer::buildSubscriptSetterDecl(
14961496

14971497
// MARK: C++ subscripts
14981498

1499+
Expr *SwiftDeclSynthesizer::synthesizeReturnReinterpretCast(ASTContext &ctx,
1500+
Type givenType,
1501+
Type exprType,
1502+
Expr *baseExpr) {
1503+
auto reinterpretCast = cast<FuncDecl>(
1504+
getBuiltinValueDecl(ctx, ctx.getIdentifier("reinterpretCast")));
1505+
SubstitutionMap subMap = SubstitutionMap::get(
1506+
reinterpretCast->getGenericSignature(), {givenType, exprType}, {});
1507+
ConcreteDeclRef concreteDeclRef(reinterpretCast, subMap);
1508+
auto reinterpretCastRef =
1509+
new (ctx) DeclRefExpr(concreteDeclRef, DeclNameLoc(), /*implicit*/ true);
1510+
FunctionType::ExtInfo info;
1511+
reinterpretCastRef->setType(
1512+
FunctionType::get({FunctionType::Param(givenType)}, exprType, info));
1513+
1514+
auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {baseExpr});
1515+
auto reinterpreted =
1516+
CallExpr::createImplicit(ctx, reinterpretCastRef, argList);
1517+
reinterpreted->setType(exprType);
1518+
reinterpreted->setThrows(nullptr);
1519+
return reinterpreted;
1520+
}
1521+
14991522
/// Synthesizer callback for a subscript getter or a getter for a
15001523
/// dereference property (`var pointee`). If the getter's implementation returns
15011524
/// an UnsafePointer or UnsafeMutablePointer, it unwraps the pointer and returns
@@ -1544,27 +1567,9 @@ synthesizeUnwrappingGetterOrAddressGetterBody(AbstractFunctionDecl *afd,
15441567
}
15451568
// Cast an 'address' result from a mutable pointer if needed.
15461569
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-
}
1570+
getterImpl->getResultInterfaceType()->isUnsafeMutablePointer())
1571+
propertyExpr = SwiftDeclSynthesizer::synthesizeReturnReinterpretCast(
1572+
ctx, getterImpl->getResultInterfaceType(), elementTy, propertyExpr);
15681573

15691574
auto returnStmt = new (ctx) ReturnStmt(SourceLoc(), propertyExpr,
15701575
/*implicit*/ true);

lib/ClangImporter/SwiftDeclSynthesizer.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ class SwiftDeclSynthesizer {
6060
VarDecl::Introducer introducer, bool isImplicit,
6161
AccessLevel access, AccessLevel setterAccess);
6262

63+
/// Create a reinterpretCast from the `exprType`, to the `givenType`.
64+
static Expr *synthesizeReturnReinterpretCast(ASTContext &ctx, Type givenType,
65+
Type exprType, Expr *baseExpr);
66+
6367
/// Create a new named constant with the given value.
6468
///
6569
/// \param name The name of the constant.

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,18 @@ class NonCopyableHolderValueMutDeref {
6060
inline NonCopyable operator *() { return NonCopyable(x.x); }
6161
};
6262

63+
template<class T>
64+
class OneDerived: public T {
65+
public:
66+
OneDerived(int x) : T(x) {}
67+
};
68+
69+
using NonCopyableHolderConstDerefDerivedDerived = OneDerived<OneDerived<NonCopyableHolderConstDeref>>;
70+
71+
using NonCopyableHolderPairedDerefDerivedDerived = OneDerived<OneDerived<NonCopyableHolderPairedDeref>>;
72+
73+
using NonCopyableHolderMutDerefDerivedDerived = OneDerived<OneDerived<NonCopyableHolderMutDeref>>;
74+
75+
using NonCopyableHolderValueConstDerefDerivedDerived = OneDerived<OneDerived<NonCopyableHolderValueConstDeref>>;
76+
6377
#endif // TEST_INTEROP_CXX_OPERATORS_MOVE_ONLY_OPS_H

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

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,52 @@ MoveOnlyCxxOperators.test("testNonCopyableHolderValueMutDeref pointee value") {
8181
expectEqual(k.x, k2.x)
8282
}
8383

84+
MoveOnlyCxxOperators.test("NonCopyableHolderConstDerefDerivedDerived pointee borrow") {
85+
let holder = NonCopyableHolderConstDerefDerivedDerived(11)
86+
var k = borrowNC(holder.pointee)
87+
expectEqual(k, 33)
88+
k = holder.pointee.method(2)
89+
expectEqual(k, 22)
90+
k = holder.pointee.x
91+
expectEqual(k, 11)
92+
}
93+
94+
MoveOnlyCxxOperators.test("testNonCopyableHolderPairedDerefDerivedDerived pointee borrow") {
95+
var holder = NonCopyableHolderPairedDerefDerivedDerived(11)
96+
var k = borrowNC(holder.pointee)
97+
expectEqual(k, 33)
98+
k = holder.pointee.method(2)
99+
expectEqual(k, 22)
100+
k = holder.pointee.x
101+
expectEqual(k, 11)
102+
k = inoutNC(&holder.pointee, -1)
103+
expectEqual(k, -1)
104+
expectEqual(holder.pointee.x, -1)
105+
holder.pointee.mutMethod(3)
106+
expectEqual(holder.pointee.x, 3)
107+
holder.pointee.x = 34
108+
expectEqual(holder.pointee.x, 34)
109+
consumingNC(holder.pointee)
110+
expectEqual(holder.pointee.x, 0)
111+
}
112+
113+
MoveOnlyCxxOperators.test("testNonCopyableHolderMutDerefDerivedDerived pointee borrow") {
114+
var holder = NonCopyableHolderMutDerefDerivedDerived(11)
115+
var k = borrowNC(holder.pointee)
116+
expectEqual(k, 33)
117+
k = holder.pointee.method(2)
118+
expectEqual(k, 22)
119+
k = holder.pointee.x
120+
expectEqual(k, 11)
121+
k = inoutNC(&holder.pointee, -1)
122+
expectEqual(k, -1)
123+
expectEqual(holder.pointee.x, -1)
124+
holder.pointee.mutMethod(3)
125+
expectEqual(holder.pointee.x, 3)
126+
holder.pointee.x = 34
127+
expectEqual(holder.pointee.x, 34)
128+
consumingNC(holder.pointee)
129+
expectEqual(holder.pointee.x, 0)
130+
}
131+
84132
runAllTests()

0 commit comments

Comments
 (0)