Skip to content

Commit ece33a4

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
1 parent 0b69eb5 commit ece33a4

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
@@ -2294,53 +2294,6 @@ namespace {
22942294
}
22952295

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

32773230
/// Handles special functions such as subscripts and dereference operators.
3278-
bool processSpecialImportedFunc(FuncDecl *func, ImportedName importedName) {
3231+
bool
3232+
processSpecialImportedFunc(FuncDecl *func, ImportedName importedName,
3233+
clang::OverloadedOperatorKind cxxOperatorKind) {
3234+
if (cxxOperatorKind == clang::OverloadedOperatorKind::OO_None)
3235+
return true;
3236+
32793237
auto dc = func->getDeclContext();
3238+
auto typeDecl = dc->getSelfNominalTypeDecl();
3239+
if (!typeDecl)
3240+
return true;
32803241

32813242
if (importedName.isSubscriptAccessor()) {
32823243
assert(func->getParameters()->size() == 1);
3283-
auto typeDecl = dc->getSelfNominalTypeDecl();
32843244
auto parameter = func->getParameters()->get(0);
32853245
auto parameterType = parameter->getTypeInContext();
32863246
if (!typeDecl || !parameterType)
@@ -3310,10 +3270,10 @@ namespace {
33103270
}
33113271

33123272
Impl.markUnavailable(func, "use subscript");
3273+
return true;
33133274
}
33143275

33153276
if (importedName.isDereferenceAccessor()) {
3316-
auto typeDecl = dc->getSelfNominalTypeDecl();
33173277
auto &getterAndSetter = Impl.cxxDereferenceOperators[typeDecl];
33183278

33193279
switch (importedName.getAccessorKind()) {
@@ -3328,6 +3288,42 @@ namespace {
33283288
}
33293289

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

33333329
return true;
@@ -3656,7 +3652,8 @@ namespace {
36563652
func->setAccess(AccessLevel::Public);
36573653

36583654
if (!importFuncWithoutSignature) {
3659-
bool success = processSpecialImportedFunc(func, importedName);
3655+
bool success = processSpecialImportedFunc(
3656+
func, importedName, decl->getOverloadedOperator());
36603657
if (!success)
36613658
return nullptr;
36623659
}
@@ -4012,6 +4009,12 @@ namespace {
40124009
if (!importedDC)
40134010
return nullptr;
40144011

4012+
// While importing the DeclContext, we might have imported the decl
4013+
// itself.
4014+
auto known = Impl.importDeclCached(decl, getVersion());
4015+
if (known.has_value())
4016+
return known.value();
4017+
40154018
if (isa<clang::TypeDecl>(decl->getTargetDecl())) {
40164019
Decl *SwiftDecl = Impl.importDecl(decl->getUnderlyingDecl(), getActiveSwiftVersion());
40174020
if (!SwiftDecl)
@@ -4060,7 +4063,8 @@ namespace {
40604063
if (!clonedMethod)
40614064
return nullptr;
40624065

4063-
bool success = processSpecialImportedFunc(clonedMethod, importedName);
4066+
bool success = processSpecialImportedFunc(
4067+
clonedMethod, importedName, targetMethod->getOverloadedOperator());
40644068
if (!success)
40654069
return nullptr;
40664070

lib/ClangImporter/SwiftDeclSynthesizer.cpp

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

19111911
FuncDecl *
19121912
SwiftDeclSynthesizer::makeOperator(FuncDecl *operatorMethod,
1913-
clang::CXXMethodDecl *clangOperator) {
1914-
clang::OverloadedOperatorKind opKind = clangOperator->getOverloadedOperator();
1915-
1913+
clang::OverloadedOperatorKind opKind) {
19161914
assert(opKind != clang::OverloadedOperatorKind::OO_None &&
19171915
"expected a C++ operator");
19181916

@@ -1970,7 +1968,8 @@ SwiftDeclSynthesizer::makeOperator(FuncDecl *operatorMethod,
19701968
operatorMethod);
19711969

19721970
// If this is a unary prefix operator (e.g. `!`), add a `prefix` attribute.
1973-
if (clangOperator->param_empty()) {
1971+
size_t numParams = operatorMethod->getParameters()->size();
1972+
if (numParams == 0 || (operatorMethod->isStatic() && numParams == 1)) {
19741973
topLevelStaticFuncDecl->getAttrs().add(new (ctx) PrefixAttr(SourceLoc()));
19751974
}
19761975

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)