Skip to content

Commit f55f713

Browse files
committed
[cxx-interop] Import using decls that refer to member operators of a base class
This is required for proper support for `std::vector::iterator` on Windows. rdar://118657936 / resolves #69990 Cherrypick commit ece33a4 Cherrypick PR #69991
1 parent b5229ea commit f55f713

File tree

7 files changed

+96
-57
lines changed

7 files changed

+96
-57
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 56 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2292,53 +2292,6 @@ namespace {
22922292
}
22932293

22942294
if (auto MD = dyn_cast<FuncDecl>(member)) {
2295-
if (auto cxxMethod = dyn_cast<clang::CXXMethodDecl>(m)) {
2296-
ImportedName methodImportedName =
2297-
Impl.importFullName(cxxMethod, getActiveSwiftVersion());
2298-
auto cxxOperatorKind = cxxMethod->getOverloadedOperator();
2299-
2300-
if (cxxOperatorKind == clang::OverloadedOperatorKind::OO_PlusPlus) {
2301-
// Make sure the type is not a foreign reference type.
2302-
// We cannot handle `operator++` for those types, since the
2303-
// current implementation creates a new instance of the type.
2304-
if (cxxMethod->param_empty() && !isa<ClassDecl>(result)) {
2305-
// This is a pre-increment operator. We synthesize a
2306-
// non-mutating function called `successor() -> Self`.
2307-
FuncDecl *successorFunc = synthesizer.makeSuccessorFunc(MD);
2308-
result->addMember(successorFunc);
2309-
2310-
Impl.markUnavailable(MD, "use .successor()");
2311-
} else {
2312-
Impl.markUnavailable(MD, "unable to create .successor() func");
2313-
}
2314-
MD->overwriteAccess(AccessLevel::Private);
2315-
}
2316-
// Check if this method _is_ an overloaded operator but is not a
2317-
// call / subscript / dereference / increment. Those
2318-
// operators do not need static versions.
2319-
else if (cxxOperatorKind !=
2320-
clang::OverloadedOperatorKind::OO_None &&
2321-
cxxOperatorKind !=
2322-
clang::OverloadedOperatorKind::OO_PlusPlus &&
2323-
cxxOperatorKind !=
2324-
clang::OverloadedOperatorKind::OO_Call &&
2325-
!methodImportedName.isSubscriptAccessor() &&
2326-
!methodImportedName.isDereferenceAccessor()) {
2327-
2328-
auto opFuncDecl = synthesizer.makeOperator(MD, cxxMethod);
2329-
2330-
Impl.addAlternateDecl(MD, opFuncDecl);
2331-
2332-
auto msg = "use " + std::string{clang::getOperatorSpelling(cxxOperatorKind)} + " instead";
2333-
Impl.markUnavailable(MD,msg);
2334-
2335-
// Make the actual member operator private.
2336-
MD->overwriteAccess(AccessLevel::Private);
2337-
2338-
// Make sure the synthesized decl can be found by lookupDirect.
2339-
result->addMemberToLookupTable(opFuncDecl);
2340-
}
2341-
}
23422295
methods.push_back(MD);
23432296
continue;
23442297
}
@@ -3272,12 +3225,19 @@ namespace {
32723225
}
32733226

32743227
/// Handles special functions such as subscripts and dereference operators.
3275-
bool processSpecialImportedFunc(FuncDecl *func, ImportedName importedName) {
3228+
bool
3229+
processSpecialImportedFunc(FuncDecl *func, ImportedName importedName,
3230+
clang::OverloadedOperatorKind cxxOperatorKind) {
3231+
if (cxxOperatorKind == clang::OverloadedOperatorKind::OO_None)
3232+
return true;
3233+
32763234
auto dc = func->getDeclContext();
3235+
auto typeDecl = dc->getSelfNominalTypeDecl();
3236+
if (!typeDecl)
3237+
return true;
32773238

32783239
if (importedName.isSubscriptAccessor()) {
32793240
assert(func->getParameters()->size() == 1);
3280-
auto typeDecl = dc->getSelfNominalTypeDecl();
32813241
auto parameter = func->getParameters()->get(0);
32823242
auto parameterType = parameter->getTypeInContext();
32833243
if (!typeDecl || !parameterType)
@@ -3307,10 +3267,10 @@ namespace {
33073267
}
33083268

33093269
Impl.markUnavailable(func, "use subscript");
3270+
return true;
33103271
}
33113272

33123273
if (importedName.isDereferenceAccessor()) {
3313-
auto typeDecl = dc->getSelfNominalTypeDecl();
33143274
auto &getterAndSetter = Impl.cxxDereferenceOperators[typeDecl];
33153275

33163276
switch (importedName.getAccessorKind()) {
@@ -3325,6 +3285,42 @@ namespace {
33253285
}
33263286

33273287
Impl.markUnavailable(func, "use .pointee property");
3288+
return true;
3289+
}
3290+
3291+
if (cxxOperatorKind == clang::OverloadedOperatorKind::OO_PlusPlus) {
3292+
// Make sure the type is not a foreign reference type.
3293+
// We cannot handle `operator++` for those types, since the
3294+
// current implementation creates a new instance of the type.
3295+
if (func->getParameters()->size() == 0 && !isa<ClassDecl>(typeDecl)) {
3296+
// This is a pre-increment operator. We synthesize a
3297+
// non-mutating function called `successor() -> Self`.
3298+
FuncDecl *successorFunc = synthesizer.makeSuccessorFunc(func);
3299+
typeDecl->addMember(successorFunc);
3300+
3301+
Impl.markUnavailable(func, "use .successor()");
3302+
} else {
3303+
Impl.markUnavailable(func, "unable to create .successor() func");
3304+
}
3305+
func->overwriteAccess(AccessLevel::Private);
3306+
return true;
3307+
}
3308+
3309+
// Check if this method _is_ an overloaded operator but is not a
3310+
// call / subscript / dereference / increment. Those
3311+
// operators do not need static versions.
3312+
if (cxxOperatorKind != clang::OverloadedOperatorKind::OO_Call) {
3313+
auto opFuncDecl = synthesizer.makeOperator(func, cxxOperatorKind);
3314+
Impl.addAlternateDecl(func, opFuncDecl);
3315+
3316+
Impl.markUnavailable(
3317+
func, (Twine("use ") + clang::getOperatorSpelling(cxxOperatorKind) +
3318+
" instead")
3319+
.str());
3320+
3321+
// Make sure the synthesized decl can be found by lookupDirect.
3322+
typeDecl->addMemberToLookupTable(opFuncDecl);
3323+
return true;
33283324
}
33293325

33303326
return true;
@@ -3654,7 +3650,8 @@ namespace {
36543650
func->setAccess(AccessLevel::Public);
36553651

36563652
if (!importFuncWithoutSignature) {
3657-
bool success = processSpecialImportedFunc(func, importedName);
3653+
bool success = processSpecialImportedFunc(
3654+
func, importedName, decl->getOverloadedOperator());
36583655
if (!success)
36593656
return nullptr;
36603657
}
@@ -4010,6 +4007,12 @@ namespace {
40104007
if (!importedDC)
40114008
return nullptr;
40124009

4010+
// While importing the DeclContext, we might have imported the decl
4011+
// itself.
4012+
auto known = Impl.importDeclCached(decl, getVersion());
4013+
if (known.has_value())
4014+
return known.value();
4015+
40134016
if (isa<clang::TypeDecl>(decl->getTargetDecl())) {
40144017
Decl *SwiftDecl = Impl.importDecl(decl->getUnderlyingDecl(), getActiveSwiftVersion());
40154018
if (!SwiftDecl)
@@ -4058,7 +4061,8 @@ namespace {
40584061
if (!clonedMethod)
40594062
return nullptr;
40604063

4061-
bool success = processSpecialImportedFunc(clonedMethod, importedName);
4064+
bool success = processSpecialImportedFunc(
4065+
clonedMethod, importedName, targetMethod->getOverloadedOperator());
40624066
if (!success)
40634067
return nullptr;
40644068

lib/ClangImporter/SwiftDeclSynthesizer.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1899,9 +1899,7 @@ synthesizeOperatorMethodBody(AbstractFunctionDecl *afd, void *context) {
18991899

19001900
FuncDecl *
19011901
SwiftDeclSynthesizer::makeOperator(FuncDecl *operatorMethod,
1902-
clang::CXXMethodDecl *clangOperator) {
1903-
clang::OverloadedOperatorKind opKind = clangOperator->getOverloadedOperator();
1904-
1902+
clang::OverloadedOperatorKind opKind) {
19051903
assert(opKind != clang::OverloadedOperatorKind::OO_None &&
19061904
"expected a C++ operator");
19071905

@@ -1959,7 +1957,8 @@ SwiftDeclSynthesizer::makeOperator(FuncDecl *operatorMethod,
19591957
operatorMethod);
19601958

19611959
// If this is a unary prefix operator (e.g. `!`), add a `prefix` attribute.
1962-
if (clangOperator->param_empty()) {
1960+
size_t numParams = operatorMethod->getParameters()->size();
1961+
if (numParams == 0 || (operatorMethod->isStatic() && numParams == 1)) {
19631962
topLevelStaticFuncDecl->getAttrs().add(new (ctx) PrefixAttr(SourceLoc()));
19641963
}
19651964

lib/ClangImporter/SwiftDeclSynthesizer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ class SwiftDeclSynthesizer {
285285
FuncDecl *makeSuccessorFunc(FuncDecl *incrementFunc);
286286

287287
FuncDecl *makeOperator(FuncDecl *operatorMethod,
288-
clang::CXXMethodDecl *clangOperator);
288+
clang::OverloadedOperatorKind opKind);
289289

290290
VarDecl *makeComputedPropertyFromCXXMethods(FuncDecl *getter,
291291
FuncDecl *setter);

test/Interop/Cxx/operators/Inputs/member-inline.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,4 +440,16 @@ struct DerivedFromAmbiguousOperatorStarPrivatelyWithUsingDecl
440440
using AmbiguousOperatorStar::operator*;
441441
};
442442

443+
struct DerivedFromLoadableIntWrapperWithUsingDecl : private LoadableIntWrapper {
444+
using LoadableIntWrapper::operator-;
445+
using LoadableIntWrapper::operator+=;
446+
447+
int getValue() const {
448+
return value;
449+
}
450+
void setValue(int v) {
451+
this->value = v;
452+
}
453+
};
454+
443455
#endif

test/Interop/Cxx/operators/member-inline-module-interface.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,15 @@
265265
// CHECK-NEXT: @available(*, unavailable, message: "use .pointee property")
266266
// CHECK-NEXT: func __operatorStar() -> UnsafePointer<Int32>
267267
// CHECK-NEXT: }
268+
269+
// CHECK: struct DerivedFromLoadableIntWrapperWithUsingDecl {
270+
// CHECK-NEXT: init()
271+
// CHECK-NEXT: static func - (lhs: inout DerivedFromLoadableIntWrapperWithUsingDecl, rhs: LoadableIntWrapper) -> LoadableIntWrapper
272+
// CHECK-NEXT: @available(*, unavailable, message: "use - instead")
273+
// CHECK-NEXT: mutating func __operatorMinus(_ rhs: LoadableIntWrapper) -> LoadableIntWrapper
274+
// CHECK-NEXT: static func += (lhs: inout DerivedFromLoadableIntWrapperWithUsingDecl, rhs: LoadableIntWrapper)
275+
// CHECK-NEXT: @available(*, unavailable, message: "use += instead")
276+
// CHECK-NEXT: mutating func __operatorPlusEqual(_ rhs: LoadableIntWrapper)
277+
// CHECK-NEXT: func getValue() -> Int32
278+
// CHECK-NEXT: mutating func setValue(_ v: Int32)
279+
// CHECK-NEXT: }

test/Interop/Cxx/operators/member-inline-typechecker.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,6 @@ derivedConstIter.pointee // expected-error {{value of type 'DerivedFromConstIter
7373

7474
let derivedConstIterWithUD = DerivedFromConstIteratorPrivatelyWithUsingDecl()
7575
let _ = derivedConstIterWithUD.pointee
76+
77+
var derivedIntWrapper = DerivedFromLoadableIntWrapperWithUsingDecl()
78+
derivedIntWrapper += LoadableIntWrapper()

test/Interop/Cxx/operators/member-inline.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,4 +395,13 @@ OperatorsTestSuite.test("DerivedFromAmbiguousOperatorStarPrivatelyWithUsingDecl.
395395
expectEqual(567, res)
396396
}
397397

398+
OperatorsTestSuite.test("DerivedFromLoadableIntWrapperWithUsingDecl") {
399+
var d = DerivedFromLoadableIntWrapperWithUsingDecl()
400+
d.setValue(123)
401+
var d1 = LoadableIntWrapper()
402+
d1.value = 543
403+
d += d1
404+
expectEqual(666, d.getValue())
405+
}
406+
398407
runAllTests()

0 commit comments

Comments
 (0)