Skip to content

Commit be34674

Browse files
authored
Merge pull request swiftlang#67375 from apple/egorzhdan/mutable-var-pointee
[cxx-interop] Import mutating dereference operators
2 parents ca9cac4 + 8832d27 commit be34674

11 files changed

+213
-65
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2186,17 +2186,6 @@ namespace {
21862186
// The name of every member.
21872187
llvm::DenseSet<StringRef> allMemberNames;
21882188

2189-
bool hasConstOperatorStar = false;
2190-
for (auto member : decl->decls()) {
2191-
if (auto method = dyn_cast<clang::CXXMethodDecl>(member)) {
2192-
if (method->getOverloadedOperator() ==
2193-
clang::OverloadedOperatorKind::OO_Star &&
2194-
method->param_empty() && method->isConst())
2195-
hasConstOperatorStar = true;
2196-
}
2197-
}
2198-
bool hasSynthesizedPointeeProperty = false;
2199-
22002189
// FIXME: Import anonymous union fields and support field access when
22012190
// it is nested in a struct.
22022191
for (auto m : decl->decls()) {
@@ -2275,26 +2264,11 @@ namespace {
22752264

22762265
if (auto MD = dyn_cast<FuncDecl>(member)) {
22772266
if (auto cxxMethod = dyn_cast<clang::CXXMethodDecl>(m)) {
2267+
ImportedName methodImportedName =
2268+
Impl.importFullName(cxxMethod, getActiveSwiftVersion());
22782269
auto cxxOperatorKind = cxxMethod->getOverloadedOperator();
22792270

2280-
if (cxxOperatorKind == clang::OO_Star && cxxMethod->param_empty()) {
2281-
// This is a dereference operator. We synthesize a computed
2282-
// property called `pointee` for it.
2283-
2284-
// If this record has multiple overloads of `operator*`, prefer
2285-
// the const overload if it exists.
2286-
if ((cxxMethod->isConst() || !hasConstOperatorStar) &&
2287-
!hasSynthesizedPointeeProperty) {
2288-
VarDecl *pointeeProperty =
2289-
synthesizer.makeDereferencedPointeeProperty(MD);
2290-
result->addMember(pointeeProperty);
2291-
hasSynthesizedPointeeProperty = true;
2292-
}
2293-
2294-
Impl.markUnavailable(MD, "use .pointee property");
2295-
MD->overwriteAccess(AccessLevel::Private);
2296-
} else if (cxxOperatorKind ==
2297-
clang::OverloadedOperatorKind::OO_PlusPlus) {
2271+
if (cxxOperatorKind == clang::OverloadedOperatorKind::OO_PlusPlus) {
22982272
// Make sure the type is not a foreign reference type.
22992273
// We cannot handle `operator++` for those types, since the
23002274
// current implementation creates a new instance of the type.
@@ -2319,8 +2293,8 @@ namespace {
23192293
clang::OverloadedOperatorKind::OO_PlusPlus &&
23202294
cxxOperatorKind !=
23212295
clang::OverloadedOperatorKind::OO_Call &&
2322-
cxxOperatorKind !=
2323-
clang::OverloadedOperatorKind::OO_Subscript) {
2296+
!methodImportedName.isSubscriptAccessor() &&
2297+
!methodImportedName.isDereferenceAccessor()) {
23242298

23252299
auto opFuncDecl = synthesizer.makeOperator(MD, cxxMethod);
23262300

@@ -2545,6 +2519,18 @@ namespace {
25452519
auto *subscriptImpl = getterAndSetter.first ? getterAndSetter.first : getterAndSetter.second;
25462520
Impl.addAlternateDecl(subscriptImpl, subscript);
25472521
}
2522+
2523+
if (Impl.cxxDereferenceOperators.find(result) !=
2524+
Impl.cxxDereferenceOperators.end()) {
2525+
// If this type has a dereference operator, synthesize a computed
2526+
// property called `pointee` for it.
2527+
auto getterAndSetter = Impl.cxxDereferenceOperators[result];
2528+
2529+
VarDecl *pointeeProperty =
2530+
synthesizer.makeDereferencedPointeeProperty(
2531+
getterAndSetter.first, getterAndSetter.second);
2532+
result->addMember(pointeeProperty);
2533+
}
25482534
}
25492535

25502536
result->setMemberLoader(&Impl, 0);
@@ -3185,6 +3171,8 @@ namespace {
31853171
case ImportedAccessorKind::None:
31863172
case ImportedAccessorKind::SubscriptGetter:
31873173
case ImportedAccessorKind::SubscriptSetter:
3174+
case ImportedAccessorKind::DereferenceGetter:
3175+
case ImportedAccessorKind::DereferenceSetter:
31883176
break;
31893177

31903178
case ImportedAccessorKind::PropertyGetter: {
@@ -3525,6 +3513,8 @@ namespace {
35253513
}
35263514
}
35273515

3516+
bool makePrivate = false;
3517+
35283518
if (importedName.isSubscriptAccessor() && !importFuncWithoutSignature) {
35293519
assert(func->getParameters()->size() == 1);
35303520
auto typeDecl = dc->getSelfNominalTypeDecl();
@@ -3552,8 +3542,32 @@ namespace {
35523542

35533543
Impl.markUnavailable(func, "use subscript");
35543544
}
3555-
// Someday, maybe this will need to be 'open' for C++ virtual methods.
3556-
func->setAccess(AccessLevel::Public);
3545+
3546+
if (importedName.isDereferenceAccessor() &&
3547+
!importFuncWithoutSignature) {
3548+
auto typeDecl = dc->getSelfNominalTypeDecl();
3549+
auto &getterAndSetter = Impl.cxxDereferenceOperators[typeDecl];
3550+
3551+
switch (importedName.getAccessorKind()) {
3552+
case ImportedAccessorKind::DereferenceGetter:
3553+
getterAndSetter.first = func;
3554+
break;
3555+
case ImportedAccessorKind::DereferenceSetter:
3556+
getterAndSetter.second = func;
3557+
break;
3558+
default:
3559+
llvm_unreachable("invalid dereference operator kind");
3560+
}
3561+
3562+
Impl.markUnavailable(func, "use .pointee property");
3563+
makePrivate = true;
3564+
}
3565+
3566+
if (makePrivate)
3567+
func->setAccess(AccessLevel::Private);
3568+
else
3569+
// Someday, maybe this will need to be 'open' for C++ virtual methods.
3570+
func->setAccess(AccessLevel::Public);
35573571
}
35583572

35593573
result->setIsObjC(false);
@@ -3977,6 +3991,10 @@ namespace {
39773991
case ImportedAccessorKind::SubscriptSetter:
39783992
case ImportedAccessorKind::None:
39793993
return importObjCMethodDecl(decl, dc, llvm::None);
3994+
3995+
case ImportedAccessorKind::DereferenceGetter:
3996+
case ImportedAccessorKind::DereferenceSetter:
3997+
llvm_unreachable("dereference operators only exist in C++");
39803998
}
39813999
}
39824000

@@ -6039,6 +6057,8 @@ SwiftDeclConverter::getImplicitProperty(ImportedName importedName,
60396057
case ImportedAccessorKind::None:
60406058
case ImportedAccessorKind::SubscriptGetter:
60416059
case ImportedAccessorKind::SubscriptSetter:
6060+
case ImportedAccessorKind::DereferenceGetter:
6061+
case ImportedAccessorKind::DereferenceSetter:
60426062
llvm_unreachable("Not a property accessor");
60436063

60446064
case ImportedAccessorKind::PropertyGetter:

lib/ClangImporter/ImportName.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,8 @@ void ClangImporter::Implementation::printSwiftName(ImportedName name,
334334
bool isSetter = false;
335335
switch (name.getAccessorKind()) {
336336
case ImportedAccessorKind::None:
337+
case ImportedAccessorKind::DereferenceGetter:
338+
case ImportedAccessorKind::DereferenceSetter:
337339
break;
338340

339341
case ImportedAccessorKind::PropertyGetter:
@@ -1916,6 +1918,15 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
19161918
baseName = swiftCtx.getIdentifier(operatorName).str();
19171919
isFunction = true;
19181920
addEmptyArgNamesForClangFunction(functionDecl, argumentNames);
1921+
if (auto cxxMethod = dyn_cast<clang::CXXMethodDecl>(functionDecl)) {
1922+
if (op == clang::OverloadedOperatorKind::OO_Star &&
1923+
cxxMethod->param_empty()) {
1924+
if (cxxMethod->isConst())
1925+
result.info.accessorKind = ImportedAccessorKind::DereferenceGetter;
1926+
else
1927+
result.info.accessorKind = ImportedAccessorKind::DereferenceSetter;
1928+
}
1929+
}
19191930
break;
19201931
}
19211932
case clang::OverloadedOperatorKind::OO_Call:

lib/ClangImporter/ImportName.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ enum class ImportedAccessorKind : unsigned {
3838
PropertySetter,
3939
SubscriptGetter,
4040
SubscriptSetter,
41+
DereferenceGetter,
42+
DereferenceSetter,
4143
};
4244
enum { NumImportedAccessorKindBits = 3 };
4345

@@ -324,6 +326,8 @@ class ImportedName {
324326
case ImportedAccessorKind::None:
325327
case ImportedAccessorKind::SubscriptGetter:
326328
case ImportedAccessorKind::SubscriptSetter:
329+
case ImportedAccessorKind::DereferenceGetter:
330+
case ImportedAccessorKind::DereferenceSetter:
327331
return false;
328332

329333
case ImportedAccessorKind::PropertyGetter:
@@ -338,6 +342,8 @@ class ImportedName {
338342
case ImportedAccessorKind::None:
339343
case ImportedAccessorKind::PropertyGetter:
340344
case ImportedAccessorKind::PropertySetter:
345+
case ImportedAccessorKind::DereferenceGetter:
346+
case ImportedAccessorKind::DereferenceSetter:
341347
return false;
342348

343349
case ImportedAccessorKind::SubscriptGetter:
@@ -347,6 +353,23 @@ class ImportedName {
347353

348354
llvm_unreachable("Invalid ImportedAccessorKind.");
349355
}
356+
357+
bool isDereferenceAccessor() const {
358+
switch (getAccessorKind()) {
359+
case ImportedAccessorKind::None:
360+
case ImportedAccessorKind::PropertyGetter:
361+
case ImportedAccessorKind::PropertySetter:
362+
case ImportedAccessorKind::SubscriptGetter:
363+
case ImportedAccessorKind::SubscriptSetter:
364+
return false;
365+
366+
case ImportedAccessorKind::DereferenceGetter:
367+
case ImportedAccessorKind::DereferenceSetter:
368+
return true;
369+
}
370+
371+
llvm_unreachable("Invalid ImportedAccessorKind.");
372+
}
350373
};
351374

352375
/// Strips a trailing "Notification", if present. Returns {} if name doesn't end

lib/ClangImporter/ImporterImpl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,9 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
642642
llvm::MapVector<std::pair<NominalTypeDecl *, Type>,
643643
std::pair<FuncDecl *, FuncDecl *>> cxxSubscripts;
644644

645+
llvm::MapVector<NominalTypeDecl *, std::pair<FuncDecl *, FuncDecl *>>
646+
cxxDereferenceOperators;
647+
645648
llvm::SmallPtrSet<const clang::Decl *, 1> synthesizedAndAlwaysVisibleDecls;
646649

647650
private:

lib/ClangImporter/SwiftDeclSynthesizer.cpp

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,17 +1538,22 @@ synthesizeUnwrappingGetterBody(AbstractFunctionDecl *afd, void *context) {
15381538
return {body, /*isTypeChecked*/ true};
15391539
}
15401540

1541-
/// Synthesizer callback for a subscript setter.
1541+
/// Synthesizer callback for a subscript setter or a setter for a dereference
1542+
/// property (`var pointee`).
15421543
static std::pair<BraceStmt *, bool>
1543-
synthesizeSubscriptSetterBody(AbstractFunctionDecl *afd, void *context) {
1544+
synthesizeUnwrappingSetterBody(AbstractFunctionDecl *afd, void *context) {
15441545
auto setterDecl = cast<AccessorDecl>(afd);
15451546
auto setterImpl = static_cast<FuncDecl *>(context);
15461547

15471548
ASTContext &ctx = setterDecl->getASTContext();
15481549

15491550
auto selfArg = createSelfArg(setterDecl);
15501551
DeclRefExpr *valueParamRefExpr = createParamRefExpr(setterDecl, 0);
1551-
DeclRefExpr *keyParamRefExpr = createParamRefExpr(setterDecl, 1);
1552+
// For a subscript this decl will have two parameters, for a pointee property
1553+
// it will only have one.
1554+
DeclRefExpr *keyParamRefExpr = setterDecl->getParameters()->size() == 1
1555+
? nullptr
1556+
: createParamRefExpr(setterDecl, 1);
15521557

15531558
Type elementTy = valueParamRefExpr->getDecl()->getInterfaceType();
15541559

@@ -1644,7 +1649,7 @@ SubscriptDecl *SwiftDeclSynthesizer::makeSubscript(FuncDecl *getter,
16441649
setterDecl->setImplicit();
16451650
setterDecl->setIsDynamic(false);
16461651
setterDecl->setIsTransparent(true);
1647-
setterDecl->setBodySynthesizer(synthesizeSubscriptSetterBody, setterImpl);
1652+
setterDecl->setBodySynthesizer(synthesizeUnwrappingSetterBody, setterImpl);
16481653

16491654
if (setterImpl->isMutating()) {
16501655
setterDecl->setSelfAccessKind(SelfAccessKind::Mutating);
@@ -1663,28 +1668,34 @@ SubscriptDecl *SwiftDeclSynthesizer::makeSubscript(FuncDecl *getter,
16631668

16641669
// MARK: C++ dereference operator
16651670

1666-
VarDecl *SwiftDeclSynthesizer::makeDereferencedPointeeProperty(
1667-
FuncDecl *dereferenceFunc) {
1671+
VarDecl *
1672+
SwiftDeclSynthesizer::makeDereferencedPointeeProperty(FuncDecl *getter,
1673+
FuncDecl *setter) {
1674+
assert((getter || setter) &&
1675+
"getter or setter required to generate a pointee property");
1676+
16681677
auto &ctx = ImporterImpl.SwiftContext;
1669-
auto dc = dereferenceFunc->getDeclContext();
1678+
FuncDecl *getterImpl = getter ? getter : setter;
1679+
FuncDecl *setterImpl = setter;
1680+
auto dc = getterImpl->getDeclContext();
16701681

16711682
// Get the return type wrapped in `Unsafe(Mutable)Pointer<T>`.
1672-
const auto rawElementTy = dereferenceFunc->getResultInterfaceType();
1683+
const auto rawElementTy = getterImpl->getResultInterfaceType();
16731684
// Unwrap `T`. Use rawElementTy for return by value.
16741685
const auto elementTy = rawElementTy->getAnyPointerElementType()
16751686
? rawElementTy->getAnyPointerElementType()
16761687
: rawElementTy;
16771688

16781689
auto result = new (ctx)
16791690
VarDecl(/*isStatic*/ false, VarDecl::Introducer::Var,
1680-
dereferenceFunc->getStartLoc(), ctx.getIdentifier("pointee"), dc);
1691+
getterImpl->getStartLoc(), ctx.getIdentifier("pointee"), dc);
16811692
result->setInterfaceType(elementTy);
16821693
result->setAccess(AccessLevel::Public);
16831694
result->setImplInfo(StorageImplInfo::getImmutableComputed());
16841695

16851696
AccessorDecl *getterDecl = AccessorDecl::create(
1686-
ctx, dereferenceFunc->getLoc(), dereferenceFunc->getLoc(),
1687-
AccessorKind::Get, result, SourceLoc(), StaticSpellingKind::None,
1697+
ctx, getterImpl->getLoc(), getterImpl->getLoc(), AccessorKind::Get,
1698+
result, SourceLoc(), StaticSpellingKind::None,
16881699
/*async*/ false, SourceLoc(),
16891700
/*throws*/ false, SourceLoc(), ParameterList::createEmpty(ctx), elementTy,
16901701
dc);
@@ -1693,14 +1704,43 @@ VarDecl *SwiftDeclSynthesizer::makeDereferencedPointeeProperty(
16931704
getterDecl->setIsDynamic(false);
16941705
getterDecl->setIsTransparent(true);
16951706
getterDecl->setBodySynthesizer(synthesizeUnwrappingGetterBody,
1696-
dereferenceFunc);
1707+
getterImpl);
16971708

1698-
if (dereferenceFunc->isMutating()) {
1709+
if (getterImpl->isMutating()) {
16991710
getterDecl->setSelfAccessKind(SelfAccessKind::Mutating);
17001711
result->setIsGetterMutating(true);
17011712
}
17021713

1703-
ImporterImpl.makeComputed(result, getterDecl, /*setter*/ nullptr);
1714+
AccessorDecl *setterDecl = nullptr;
1715+
if (setterImpl) {
1716+
auto paramVarDecl =
1717+
new (ctx) ParamDecl(SourceLoc(), SourceLoc(), Identifier(), SourceLoc(),
1718+
ctx.getIdentifier("newValue"), dc);
1719+
paramVarDecl->setSpecifier(ParamSpecifier::Default);
1720+
paramVarDecl->setInterfaceType(elementTy);
1721+
1722+
auto setterParamList =
1723+
ParameterList::create(ctx, {paramVarDecl});
1724+
1725+
setterDecl = AccessorDecl::create(
1726+
ctx, setterImpl->getLoc(), setterImpl->getLoc(), AccessorKind::Set,
1727+
result, SourceLoc(), StaticSpellingKind::None,
1728+
/*async*/ false, SourceLoc(),
1729+
/*throws*/ false, SourceLoc(), setterParamList,
1730+
TupleType::getEmpty(ctx), dc);
1731+
setterDecl->setAccess(AccessLevel::Public);
1732+
setterDecl->setImplicit();
1733+
setterDecl->setIsDynamic(false);
1734+
setterDecl->setIsTransparent(true);
1735+
setterDecl->setBodySynthesizer(synthesizeUnwrappingSetterBody, setterImpl);
1736+
1737+
if (setterImpl->isMutating()) {
1738+
setterDecl->setSelfAccessKind(SelfAccessKind::Mutating);
1739+
result->setIsSetterMutating(true);
1740+
}
1741+
}
1742+
1743+
ImporterImpl.makeComputed(result, getterDecl, setterDecl);
17041744
return result;
17051745
}
17061746

lib/ClangImporter/SwiftDeclSynthesizer.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,9 +275,10 @@ class SwiftDeclSynthesizer {
275275
/// Given an imported C++ dereference operator (`operator*()`), create a
276276
/// `pointee` computed property.
277277
///
278-
/// \param dereferenceFunc function returning `Unsafe(Mutable)?Pointer<T>`
278+
/// \param getter function returning `UnsafePointer<T>`
279+
/// \param setter function returning `UnsafeMutablePointer<T>`
279280
/// \return computed property declaration
280-
VarDecl *makeDereferencedPointeeProperty(FuncDecl *dereferenceFunc);
281+
VarDecl *makeDereferencedPointeeProperty(FuncDecl *getter, FuncDecl *setter);
281282

282283
/// Given a C++ pre-increment operator (`operator++()`). create a non-mutating
283284
/// function `successor() -> Self`.

0 commit comments

Comments
 (0)