Skip to content

Commit 26358c4

Browse files
authored
Import member operator functions as static members (#32293)
This adds support to `ClangImporter` to import C++ member function operators as static methods into Swift, which is part of SR-12748. The left-hand-side operand, which gets passed as the `this` pointer to the C++ function is represented as an additional first parameter in the Swift method. It gets mapped back in SILGen. Two of the tests are disabled on Windows because we can't yet call member functions correctly on Windows (SR-13129).
1 parent 45b3aa0 commit 26358c4

16 files changed

+341
-16
lines changed

include/swift/SIL/AbstractionPattern.h

Lines changed: 84 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -179,15 +179,26 @@ class AbstractionPattern {
179179
/// type. ObjCMethod is valid. OtherData is an encoded foreign
180180
/// error index.
181181
ObjCMethodType,
182-
/// The uncurried imported type of a C++ method. OrigType is valid and is a
183-
/// function type. CXXMethod is valid.
182+
/// The uncurried imported type of a C++ non-operator non-static member
183+
/// function. OrigType is valid and is a function type. CXXMethod is valid.
184184
CXXMethodType,
185-
/// The curried imported type of a C++ method. OrigType is valid and is a
186-
/// function type. CXXMethod is valid.
185+
/// The curried imported type of a C++ non-operator non-static member
186+
/// function. OrigType is valid and is a function type. CXXMethod is valid.
187187
CurriedCXXMethodType,
188-
/// The partially-applied curried imported type of a C++ method. OrigType is
189-
/// valid and is a function type. CXXMethod is valid.
188+
/// The partially-applied curried imported type of a C++ non-operator
189+
/// non-static member function. OrigType is valid and is a function type.
190+
/// CXXMethod is valid.
190191
PartialCurriedCXXMethodType,
192+
/// The uncurried imported type of a C++ operator non-static member
193+
/// function. OrigType is valid and is a function type. CXXMethod is valid.
194+
CXXOperatorMethodType,
195+
/// The curried imported type of a C++ operator non-static member function.
196+
/// OrigType is valid and is a function type. CXXMethod is valid.
197+
CurriedCXXOperatorMethodType,
198+
/// The partially-applied curried imported type of a C++ operator non-static
199+
/// member function. OrigType is valid and is a function type. CXXMethod is
200+
/// valid.
201+
PartialCurriedCXXOperatorMethodType,
191202
/// A Swift function whose parameters and results are opaque. This is
192203
/// like `AP::Type<T>((T) -> T)`, except that the number of parameters is
193204
/// unspecified.
@@ -341,6 +352,9 @@ class AbstractionPattern {
341352
case Kind::CXXMethodType:
342353
case Kind::CurriedCXXMethodType:
343354
case Kind::PartialCurriedCXXMethodType:
355+
case Kind::CXXOperatorMethodType:
356+
case Kind::CurriedCXXOperatorMethodType:
357+
case Kind::PartialCurriedCXXOperatorMethodType:
344358
return true;
345359

346360
default:
@@ -465,6 +479,9 @@ class AbstractionPattern {
465479
case Kind::CXXMethodType:
466480
case Kind::CurriedCXXMethodType:
467481
case Kind::PartialCurriedCXXMethodType:
482+
case Kind::CXXOperatorMethodType:
483+
case Kind::CurriedCXXOperatorMethodType:
484+
case Kind::PartialCurriedCXXOperatorMethodType:
468485
return true;
469486
case Kind::Invalid:
470487
case Kind::Opaque:
@@ -541,6 +558,10 @@ class AbstractionPattern {
541558
static AbstractionPattern
542559
getCurriedCXXMethod(CanType origType, const AbstractFunctionDecl *function);
543560

561+
static AbstractionPattern
562+
getCurriedCXXOperatorMethod(CanType origType,
563+
const AbstractFunctionDecl *function);
564+
544565
/// Return an abstraction pattern for the uncurried type of a C++ method.
545566
///
546567
/// For example, if the original function is:
@@ -556,6 +577,15 @@ class AbstractionPattern {
556577
return pattern;
557578
}
558579

580+
static AbstractionPattern
581+
getCXXOperatorMethod(CanType origType, const clang::CXXMethodDecl *method) {
582+
assert(isa<AnyFunctionType>(origType));
583+
AbstractionPattern pattern;
584+
pattern.initCXXMethod(nullptr, origType, method,
585+
Kind::CXXOperatorMethodType);
586+
return pattern;
587+
}
588+
559589
/// Return an abstraction pattern for the curried type of a C++ method.
560590
///
561591
/// For example, if the original function is:
@@ -572,6 +602,16 @@ class AbstractionPattern {
572602
return pattern;
573603
}
574604

605+
static AbstractionPattern
606+
getCurriedCXXOperatorMethod(CanType origType,
607+
const clang::CXXMethodDecl *method) {
608+
assert(isa<AnyFunctionType>(origType));
609+
AbstractionPattern pattern;
610+
pattern.initCXXMethod(nullptr, origType, method,
611+
Kind::CurriedCXXOperatorMethodType);
612+
return pattern;
613+
}
614+
575615
/// For a C-function-as-method pattern,
576616
/// get the index of the C function parameter that was imported as the
577617
/// `self` parameter of the imported method, or None if this is a static
@@ -678,6 +718,17 @@ class AbstractionPattern {
678718
return pattern;
679719
}
680720

721+
static AbstractionPattern
722+
getPartialCurriedCXXOperatorMethod(CanGenericSignature signature,
723+
CanType origType,
724+
const clang::CXXMethodDecl *method) {
725+
assert(isa<AnyFunctionType>(origType));
726+
AbstractionPattern pattern;
727+
pattern.initCXXMethod(signature, origType, method,
728+
Kind::PartialCurriedCXXOperatorMethodType);
729+
return pattern;
730+
}
731+
681732
public:
682733
/// Return an abstraction pattern for the type of an Objective-C method.
683734
static AbstractionPattern
@@ -813,6 +864,9 @@ class AbstractionPattern {
813864
case Kind::CXXMethodType:
814865
case Kind::CurriedCXXMethodType:
815866
case Kind::PartialCurriedCXXMethodType:
867+
case Kind::CXXOperatorMethodType:
868+
case Kind::CurriedCXXOperatorMethodType:
869+
case Kind::PartialCurriedCXXOperatorMethodType:
816870
case Kind::Type:
817871
case Kind::Discard:
818872
return OrigType;
@@ -849,6 +903,9 @@ class AbstractionPattern {
849903
case Kind::CXXMethodType:
850904
case Kind::CurriedCXXMethodType:
851905
case Kind::PartialCurriedCXXMethodType:
906+
case Kind::CXXOperatorMethodType:
907+
case Kind::CurriedCXXOperatorMethodType:
908+
case Kind::PartialCurriedCXXOperatorMethodType:
852909
case Kind::Type:
853910
case Kind::Discard:
854911
assert(signature || !type->hasTypeParameter());
@@ -886,6 +943,9 @@ class AbstractionPattern {
886943
case Kind::CXXMethodType:
887944
case Kind::CurriedCXXMethodType:
888945
case Kind::PartialCurriedCXXMethodType:
946+
case Kind::CXXOperatorMethodType:
947+
case Kind::CurriedCXXOperatorMethodType:
948+
case Kind::PartialCurriedCXXOperatorMethodType:
889949
return true;
890950
}
891951
llvm_unreachable("bad kind");
@@ -923,7 +983,9 @@ class AbstractionPattern {
923983
/// If so, it is legal to call getCXXMethod().
924984
bool isCXXMethod() const {
925985
return (getKind() == Kind::CXXMethodType ||
926-
getKind() == Kind::CurriedCXXMethodType);
986+
getKind() == Kind::CurriedCXXMethodType ||
987+
getKind() == Kind::CXXOperatorMethodType ||
988+
getKind() == Kind::CurriedCXXOperatorMethodType);
927989
}
928990

929991
const clang::CXXMethodDecl *getCXXMethod() const {
@@ -958,6 +1020,9 @@ class AbstractionPattern {
9581020
case Kind::CXXMethodType:
9591021
case Kind::CurriedCXXMethodType:
9601022
case Kind::PartialCurriedCXXMethodType:
1023+
case Kind::CXXOperatorMethodType:
1024+
case Kind::CurriedCXXOperatorMethodType:
1025+
case Kind::PartialCurriedCXXOperatorMethodType:
9611026
case Kind::OpaqueFunction:
9621027
case Kind::OpaqueDerivativeFunction:
9631028
return false;
@@ -994,6 +1059,9 @@ class AbstractionPattern {
9941059
case Kind::CXXMethodType:
9951060
case Kind::CurriedCXXMethodType:
9961061
case Kind::PartialCurriedCXXMethodType:
1062+
case Kind::CXXOperatorMethodType:
1063+
case Kind::CurriedCXXOperatorMethodType:
1064+
case Kind::PartialCurriedCXXOperatorMethodType:
9971065
case Kind::Type:
9981066
case Kind::Discard:
9991067
return dyn_cast<TYPE>(getType());
@@ -1022,6 +1090,9 @@ class AbstractionPattern {
10221090
case Kind::CXXMethodType:
10231091
case Kind::CurriedCXXMethodType:
10241092
case Kind::PartialCurriedCXXMethodType:
1093+
case Kind::CXXOperatorMethodType:
1094+
case Kind::CurriedCXXOperatorMethodType:
1095+
case Kind::PartialCurriedCXXOperatorMethodType:
10251096
case Kind::OpaqueFunction:
10261097
case Kind::OpaqueDerivativeFunction:
10271098
// We assume that the Clang type might provide additional structure.
@@ -1051,6 +1122,9 @@ class AbstractionPattern {
10511122
case Kind::CXXMethodType:
10521123
case Kind::CurriedCXXMethodType:
10531124
case Kind::PartialCurriedCXXMethodType:
1125+
case Kind::CXXOperatorMethodType:
1126+
case Kind::CurriedCXXOperatorMethodType:
1127+
case Kind::PartialCurriedCXXOperatorMethodType:
10541128
case Kind::OpaqueFunction:
10551129
case Kind::OpaqueDerivativeFunction:
10561130
return false;
@@ -1078,6 +1152,9 @@ class AbstractionPattern {
10781152
case Kind::CXXMethodType:
10791153
case Kind::CurriedCXXMethodType:
10801154
case Kind::PartialCurriedCXXMethodType:
1155+
case Kind::CXXOperatorMethodType:
1156+
case Kind::CurriedCXXOperatorMethodType:
1157+
case Kind::PartialCurriedCXXOperatorMethodType:
10811158
case Kind::OpaqueFunction:
10821159
case Kind::OpaqueDerivativeFunction:
10831160
llvm_unreachable("pattern is not a tuple");

lib/ClangImporter/ClangImporter.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3591,6 +3591,18 @@ void ClangImporter::Implementation::lookupValue(
35913591
auto &clangCtx = getClangASTContext();
35923592
auto clangTU = clangCtx.getTranslationUnitDecl();
35933593

3594+
// For operators we have to look up static member functions in addition to the
3595+
// top-level function lookup below.
3596+
if (name.isOperator()) {
3597+
for (auto entry : table.lookupMemberOperators(name.getBaseName())) {
3598+
if (isVisibleClangEntry(entry)) {
3599+
if (auto decl = dyn_cast<ValueDecl>(
3600+
importDeclReal(entry->getMostRecentDecl(), CurrentVersion)))
3601+
consumer.foundDecl(decl, DeclVisibilityKind::VisibleAtTopLevel);
3602+
}
3603+
}
3604+
}
3605+
35943606
for (auto entry : table.lookup(name.getBaseName(), clangTU)) {
35953607
// If the entry is not visible, skip it.
35963608
if (!isVisibleClangEntry(entry)) continue;

lib/ClangImporter/ImportDecl.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3801,14 +3801,20 @@ namespace {
38013801
decl->isVariadic(), isInSystemModule(dc), name, bodyParams);
38023802

38033803
if (auto *mdecl = dyn_cast<clang::CXXMethodDecl>(decl)) {
3804-
if (!mdecl->isStatic()) {
3804+
if (mdecl->isStatic() ||
3805+
// C++ operators that are implemented as non-static member
3806+
// functions get imported into Swift as static member functions
3807+
// that use an additional parameter for the left-hand side operand
3808+
// instead of the receiver object.
3809+
mdecl->getDeclName().getNameKind() ==
3810+
clang::DeclarationName::CXXOperatorName) {
3811+
selfIdx = None;
3812+
} else {
38053813
selfIdx = 0;
38063814
// Workaround until proper const support is handled: Force
38073815
// everything to be mutating. This implicitly makes the parameter
38083816
// indirect.
38093817
selfIsInOut = true;
3810-
} else {
3811-
selfIdx = None;
38123818
}
38133819
}
38143820
}

lib/ClangImporter/ImportName.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "swift/ClangImporter/ClangImporterOptions.h"
3333
#include "swift/Parse/Parser.h"
3434
#include "clang/AST/ASTContext.h"
35+
#include "clang/AST/DeclCXX.h"
3536
#include "clang/Basic/IdentifierTable.h"
3637
#include "clang/Basic/Module.h"
3738
#include "clang/Basic/OperatorKinds.h"
@@ -1439,7 +1440,13 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
14391440
if (auto FD = dyn_cast<clang::FunctionDecl>(D)) {
14401441
baseName = clang::getOperatorSpelling(op);
14411442
isFunction = true;
1442-
argumentNames.resize(FD->param_size());
1443+
argumentNames.resize(
1444+
FD->param_size() +
1445+
// C++ operators that are implemented as non-static member functions
1446+
// get imported into Swift as static member functions that use an
1447+
// additional parameter for the left-hand side operand instead of
1448+
// the receiver object.
1449+
(isa<clang::CXXMethodDecl>(D) ? 1 : 0));
14431450
} else {
14441451
// This can happen for example for templated operators functions.
14451452
// We don't support those, yet.

lib/ClangImporter/ImportType.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,13 @@
2727
#include "swift/AST/Module.h"
2828
#include "swift/AST/NameLookup.h"
2929
#include "swift/AST/ParameterList.h"
30+
#include "swift/AST/Type.h"
3031
#include "swift/AST/Types.h"
3132
#include "swift/ClangImporter/ClangModule.h"
3233
#include "swift/Parse/Token.h"
3334
#include "swift/Strings.h"
3435
#include "clang/AST/ASTContext.h"
36+
#include "clang/AST/DeclCXX.h"
3537
#include "clang/AST/TypeVisitor.h"
3638
#include "clang/Basic/Builtins.h"
3739
#include "clang/Lex/Preprocessor.h"
@@ -1708,6 +1710,30 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList(
17081710
unsigned index = 0;
17091711
SmallBitVector nonNullArgs = getNonNullArgs(clangDecl, params);
17101712

1713+
// C++ operators that are implemented as non-static member functions get
1714+
// imported into Swift as static methods that have an additional
1715+
// parameter for the left-hand side operand instead of the receiver object.
1716+
if (auto CMD = dyn_cast<clang::CXXMethodDecl>(clangDecl)) {
1717+
if (clangDecl->isOverloadedOperator()) {
1718+
auto param = new (SwiftContext)
1719+
ParamDecl(SourceLoc(), SourceLoc(), Identifier(), SourceLoc(),
1720+
SwiftContext.getIdentifier("lhs"), dc);
1721+
1722+
auto parent = CMD->getParent();
1723+
auto parentType = importType(
1724+
parent->getASTContext().getRecordType(parent),
1725+
ImportTypeKind::Parameter, allowNSUIntegerAsInt, Bridgeability::None);
1726+
1727+
param->setInterfaceType(parentType.getType());
1728+
1729+
// Workaround until proper const support is handled: Force everything to
1730+
// be mutating. This implicitly makes the parameter indirect.
1731+
param->setSpecifier(ParamSpecifier::InOut);
1732+
1733+
parameters.push_back(param);
1734+
}
1735+
}
1736+
17111737
for (auto param : params) {
17121738
auto paramTy = param->getType();
17131739
if (paramTy->isVoidType()) {

lib/ClangImporter/SwiftLookupTable.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/AST/DiagnosticsClangImporter.h"
2121
#include "swift/Basic/STLExtras.h"
2222
#include "swift/Basic/Version.h"
23+
#include "clang/AST/DeclCXX.h"
2324
#include "clang/AST/DeclObjC.h"
2425
#include "clang/Lex/MacroInfo.h"
2526
#include "clang/Lex/Preprocessor.h"
@@ -795,6 +796,35 @@ SwiftLookupTable::lookupObjCMembers(SerializedSwiftName baseName) {
795796
return result;
796797
}
797798

799+
SmallVector<clang::NamedDecl *, 4>
800+
SwiftLookupTable::lookupMemberOperators(SerializedSwiftName baseName) {
801+
SmallVector<clang::NamedDecl *, 4> result;
802+
803+
// Find the lookup table entry for this base name.
804+
auto known = findOrCreate(LookupTable, baseName,
805+
[](auto &results, auto &Reader, auto Name) {
806+
return (void)Reader.lookup(Name, results);
807+
});
808+
if (known == LookupTable.end())
809+
return result;
810+
811+
// Walk each of the entries.
812+
for (auto &entry : known->second) {
813+
// We're only looking for C++ operators
814+
if (entry.Context.first != ContextKind::Tag) {
815+
continue;
816+
}
817+
818+
// Map each of the declarations.
819+
for (auto &stored : entry.DeclsOrMacros) {
820+
assert(isDeclEntry(stored) && "Not a declaration?");
821+
result.push_back(mapStoredDecl(stored));
822+
}
823+
}
824+
825+
return result;
826+
}
827+
798828
ArrayRef<clang::ObjCCategoryDecl *> SwiftLookupTable::categories() {
799829
if (!Categories.empty() || !Reader) return Categories;
800830

lib/ClangImporter/SwiftLookupTable.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,10 @@ class SwiftLookupTable {
528528
SmallVector<clang::NamedDecl *, 4>
529529
lookupObjCMembers(SerializedSwiftName baseName);
530530

531+
/// Lookup member operators with the given base name, regardless of context.
532+
SmallVector<clang::NamedDecl *, 4>
533+
lookupMemberOperators(SerializedSwiftName baseName);
534+
531535
/// Retrieve the set of Objective-C categories and extensions.
532536
ArrayRef<clang::ObjCCategoryDecl *> categories();
533537

0 commit comments

Comments
 (0)