Skip to content

Commit 4967cd5

Browse files
authored
Merge pull request swiftlang#58910 from Huddie/update-cxx-operator-impl
2 parents 9a0978a + e7f8a99 commit 4967cd5

26 files changed

+263
-134
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,13 @@
7272
#include "llvm/Support/FileSystem.h"
7373
#include "llvm/Support/Memory.h"
7474
#include "llvm/Support/Path.h"
75+
#include "llvm/Support/VirtualFileSystem.h"
7576
#include "llvm/Support/YAMLParser.h"
7677
#include "llvm/Support/YAMLTraits.h"
77-
#include "llvm/Support/VirtualFileSystem.h"
7878
#include <algorithm>
79+
#include <string>
7980
#include <memory>
81+
#include <string>
8082

8183
using namespace swift;
8284
using namespace importer;
@@ -87,6 +89,17 @@ using clang::CompilerInvocation;
8789

8890
#pragma mark Internal data structures
8991

92+
namespace {
93+
static std::string getOperatorNameForToken(std::string OperatorToken) {
94+
#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \
95+
if (OperatorToken == Spelling) { \
96+
return #Name; \
97+
};
98+
#include "clang/Basic/OperatorKinds.def"
99+
return "None";
100+
}
101+
} // namespace
102+
90103
namespace {
91104
class HeaderImportCallbacks : public clang::PPCallbacks {
92105
ClangImporter::Implementation &Impl;
@@ -2745,6 +2758,11 @@ ClangImporter::Implementation::lookupTypedef(clang::DeclarationName name) {
27452758

27462759
static bool isDeclaredInModule(const ClangModuleUnit *ModuleFilter,
27472760
const Decl *VD) {
2761+
// Sometimes imported decls get put into the clang header module. If we
2762+
// found one of these decls, don't filter it out.
2763+
if (VD->getModuleContext()->getName().str() == CLANG_HEADER_MODULE_NAME) {
2764+
return true;
2765+
}
27482766
auto ContainingUnit = VD->getDeclContext()->getModuleScopeContext();
27492767
return ModuleFilter == ContainingUnit;
27502768
}
@@ -2802,7 +2820,6 @@ static bool isVisibleFromModule(const ClangModuleUnit *ModuleFilter,
28022820

28032821
const clang::Decl *D = ClangNode.castAsDecl();
28042822
auto &ClangASTContext = ModuleFilter->getClangASTContext();
2805-
28062823
// We don't handle Clang submodules; pop everything up to the top-level
28072824
// module.
28082825
auto OwningClangModule = getClangTopLevelOwningModule(ClangNode,
@@ -2875,7 +2892,7 @@ class FilteringVisibleDeclConsumer : public swift::VisibleDeclConsumer {
28752892

28762893
void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason,
28772894
DynamicLookupInfo dynamicLookupInfo) override {
2878-
if (isVisibleFromModule(ModuleFilter, VD))
2895+
if (!VD->hasClangNode() || isVisibleFromModule(ModuleFilter, VD))
28792896
NextConsumer.foundDecl(VD, Reason, dynamicLookupInfo);
28802897
}
28812898
};
@@ -2893,11 +2910,9 @@ class FilteringDeclaredDeclConsumer : public swift::VisibleDeclConsumer {
28932910

28942911
void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason,
28952912
DynamicLookupInfo dynamicLookupInfo) override {
2896-
if (isDeclaredInModule(ModuleFilter, VD) ||
2897-
// Sometimes imported decls get put into the clang header module. If we
2898-
// found one of these decls, don't filter it out.
2899-
VD->getModuleContext()->getName().str() == CLANG_HEADER_MODULE_NAME)
2913+
if (isDeclaredInModule(ModuleFilter, VD)) {
29002914
NextConsumer.foundDecl(VD, Reason, dynamicLookupInfo);
2915+
}
29012916
}
29022917
};
29032918

@@ -4111,22 +4126,42 @@ bool ClangImporter::Implementation::forEachLookupTable(
41114126
bool ClangImporter::Implementation::lookupValue(SwiftLookupTable &table,
41124127
DeclName name,
41134128
VisibleDeclConsumer &consumer) {
4129+
41144130
auto &clangCtx = getClangASTContext();
41154131
auto clangTU = clangCtx.getTranslationUnitDecl();
41164132

41174133
bool declFound = false;
41184134

4119-
// For operators we have to look up static member functions in addition to the
4120-
// top-level function lookup below.
41214135
if (name.isOperator()) {
4122-
for (auto entry : table.lookupMemberOperators(name.getBaseName())) {
4123-
if (isVisibleClangEntry(entry)) {
4124-
if (auto decl = dyn_cast_or_null<ValueDecl>(
4125-
importDeclReal(entry->getMostRecentDecl(), CurrentVersion))) {
4126-
consumer.foundDecl(decl, DeclVisibilityKind::VisibleAtTopLevel);
4127-
declFound = true;
4136+
4137+
auto findAndConsumeBaseNameFromTable = [this, &table, &consumer, &declFound,
4138+
&name](DeclBaseName declBaseName) {
4139+
for (auto entry : table.lookupMemberOperators(declBaseName)) {
4140+
if (isVisibleClangEntry(entry)) {
4141+
if (auto decl = dyn_cast_or_null<ValueDecl>(
4142+
importDeclReal(entry->getMostRecentDecl(), CurrentVersion))) {
4143+
consumer.foundDecl(decl, DeclVisibilityKind::VisibleAtTopLevel);
4144+
declFound = true;
4145+
for (auto alternate : getAlternateDecls(decl)) {
4146+
if (alternate->getName().matchesRef(name)) {
4147+
consumer.foundDecl(alternate, DeclVisibilityKind::DynamicLookup,
4148+
DynamicLookupInfo::AnyObject);
4149+
}
4150+
}
4151+
}
41284152
}
41294153
}
4154+
};
4155+
4156+
findAndConsumeBaseNameFromTable(name.getBaseName());
4157+
4158+
// If CXXInterop is enabled we need to check the modified operator name as
4159+
// well
4160+
if (SwiftContext.LangOpts.EnableCXXInterop) {
4161+
auto declBaseName = DeclBaseName(SwiftContext.getIdentifier(
4162+
"__operator" + getOperatorNameForToken(
4163+
name.getBaseName().getIdentifier().str().str())));
4164+
findAndConsumeBaseNameFromTable(declBaseName);
41304165
}
41314166
}
41324167

lib/ClangImporter/ImportDecl.cpp

Lines changed: 152 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3593,6 +3593,26 @@ namespace {
35933593
// by changing the name of one. That changed method needs to be added
35943594
// to the lookup table since it cannot be found lazily.
35953595
if (auto cxxMethod = dyn_cast<clang::CXXMethodDecl>(m)) {
3596+
auto cxxOperatorKind = cxxMethod->getOverloadedOperator();
3597+
3598+
// Check if this method _is_ an overloaded operator but is not a
3599+
// call / subscript. Those 2 operators do not need static versions
3600+
if (cxxOperatorKind != clang::OverloadedOperatorKind::OO_None &&
3601+
cxxOperatorKind != clang::OverloadedOperatorKind::OO_Call &&
3602+
cxxOperatorKind !=
3603+
clang::OverloadedOperatorKind::OO_Subscript) {
3604+
3605+
auto opFuncDecl = makeOperator(MD, cxxMethod);
3606+
3607+
Impl.addAlternateDecl(MD, opFuncDecl);
3608+
3609+
auto msg = "use " + std::string{clang::getOperatorSpelling(cxxOperatorKind)} + " instead";
3610+
Impl.markUnavailable(MD,msg);
3611+
3612+
// Make the actual member operator private.
3613+
MD->overwriteAccess(AccessLevel::Private);
3614+
}
3615+
35963616
if (cxxMethod->getDeclName().isIdentifier()) {
35973617
auto &mutableFuncPtrs = Impl.cxxMethods[cxxMethod->getName()].second;
35983618
if(mutableFuncPtrs.contains(cxxMethod)) {
@@ -4133,11 +4153,6 @@ namespace {
41334153
if (!dc)
41344154
return nullptr;
41354155

4136-
// Support for importing operators is temporarily disabled: rdar://91070109
4137-
if (decl->getDeclName().getNameKind() == clang::DeclarationName::CXXOperatorName &&
4138-
decl->getDeclName().getCXXOverloadedOperator() != clang::OO_Subscript)
4139-
return nullptr;
4140-
41414156
// Handle cases where 2 CXX methods differ strictly in "constness"
41424157
// In such a case append a suffix ("Mutating") to the mutable version
41434158
// of the method when importing to swift
@@ -4285,16 +4300,7 @@ namespace {
42854300
templateParams);
42864301

42874302
if (auto *mdecl = dyn_cast<clang::CXXMethodDecl>(decl)) {
4288-
// Subscripts and call operators are imported as normal methods.
4289-
bool staticOperator = mdecl->isOverloadedOperator() &&
4290-
mdecl->getOverloadedOperator() != clang::OO_Call &&
4291-
mdecl->getOverloadedOperator() != clang::OO_Subscript;
4292-
if (mdecl->isStatic() ||
4293-
// C++ operators that are implemented as non-static member
4294-
// functions get imported into Swift as static member functions
4295-
// that use an additional parameter for the left-hand side operand
4296-
// instead of the receiver object.
4297-
staticOperator) {
4303+
if (mdecl->isStatic()) {
42984304
selfIdx = None;
42994305
} else {
43004306
// Swift imports the "self" param last, even for clang functions.
@@ -5393,9 +5399,13 @@ namespace {
53935399
/// \param setter function returning `UnsafeMutablePointer<T>`
53945400
/// \return subscript declaration
53955401
SubscriptDecl *makeSubscript(FuncDecl *getter, FuncDecl *setter);
5402+
FuncDecl *makeOperator(FuncDecl *operatorMethod,
5403+
clang::CXXMethodDecl *clangOperator);
5404+
53965405
VarDecl *makeComputedPropertyFromCXXMethods(FuncDecl *getter,
53975406
FuncDecl *setter);
53985407

5408+
53995409
/// Import the accessor and its attributes.
54005410
AccessorDecl *importAccessor(const clang::ObjCMethodDecl *clangAccessor,
54015411
AbstractStorageDecl *storage,
@@ -8080,6 +8090,133 @@ SwiftDeclConverter::makeSubscript(FuncDecl *getter, FuncDecl *setter) {
80808090
return subscript;
80818091
}
80828092

8093+
static std::pair<BraceStmt *, bool>
8094+
synthesizeOperatorMethodBody(AbstractFunctionDecl *afd, void *context) {
8095+
ASTContext &ctx = afd->getASTContext();
8096+
8097+
auto funcDecl = cast<FuncDecl>(afd);
8098+
auto methodDecl =
8099+
static_cast<FuncDecl *>(context); /* Swift version of CXXMethod */
8100+
8101+
SmallVector<Expr *, 8> forwardingParams;
8102+
8103+
// We start from +1 since the first param is our lhs. All other params are
8104+
// forwarded
8105+
for (auto itr = funcDecl->getParameters()->begin() + 1;
8106+
itr != funcDecl->getParameters()->end(); itr++) {
8107+
auto param = *itr;
8108+
Expr *paramRefExpr =
8109+
new (ctx) DeclRefExpr(param, DeclNameLoc(), /*Implicit=*/true);
8110+
paramRefExpr->setType(param->getType());
8111+
8112+
if (param->isInOut()) {
8113+
paramRefExpr->setType(LValueType::get(param->getType()));
8114+
8115+
paramRefExpr = new (ctx) InOutExpr(SourceLoc(), paramRefExpr,
8116+
param->getType(), /*isImplicit*/ true);
8117+
paramRefExpr->setType(InOutType::get(param->getType()));
8118+
}
8119+
8120+
forwardingParams.push_back(paramRefExpr);
8121+
}
8122+
8123+
auto methodExpr =
8124+
new (ctx) DeclRefExpr(methodDecl, DeclNameLoc(), /*implicit*/ true);
8125+
methodExpr->setType(methodDecl->getInterfaceType());
8126+
8127+
// Lhs parameter
8128+
auto baseParam = funcDecl->getParameters()->front();
8129+
Expr *baseExpr =
8130+
new (ctx) DeclRefExpr(baseParam, DeclNameLoc(), /*implicit*/ true);
8131+
baseExpr->setType(baseParam->getType());
8132+
if (baseParam->isInOut()) {
8133+
baseExpr->setType(LValueType::get(baseParam->getType()));
8134+
8135+
baseExpr = new (ctx) InOutExpr(SourceLoc(), baseExpr, baseParam->getType(),
8136+
/*isImplicit*/ true);
8137+
baseExpr->setType(InOutType::get(baseParam->getType()));
8138+
}
8139+
8140+
auto dotCallExpr =
8141+
DotSyntaxCallExpr::create(ctx, methodExpr, SourceLoc(), baseExpr);
8142+
dotCallExpr->setType(methodDecl->getMethodInterfaceType());
8143+
dotCallExpr->setThrows(false);
8144+
8145+
auto *argList = ArgumentList::forImplicitUnlabeled(ctx, forwardingParams);
8146+
auto callExpr = CallExpr::createImplicit(ctx, dotCallExpr, argList);
8147+
callExpr->setType(funcDecl->getResultInterfaceType());
8148+
callExpr->setThrows(false);
8149+
8150+
auto returnStmt = new (ctx) ReturnStmt(SourceLoc(), callExpr,
8151+
/*implicit=*/true);
8152+
8153+
auto body = BraceStmt::create(ctx, SourceLoc(), {returnStmt}, SourceLoc(),
8154+
/*implicit=*/true);
8155+
return {body, /*isTypeChecked=*/true};
8156+
}
8157+
8158+
FuncDecl *
8159+
SwiftDeclConverter::makeOperator(FuncDecl *operatorMethod,
8160+
clang::CXXMethodDecl *clangOperator) {
8161+
auto &ctx = Impl.SwiftContext;
8162+
auto opName =
8163+
clang::getOperatorSpelling(clangOperator->getOverloadedOperator());
8164+
auto paramList = operatorMethod->getParameters();
8165+
auto genericParamList = operatorMethod->getGenericParams();
8166+
8167+
auto opId = ctx.getIdentifier(opName);
8168+
8169+
auto parentCtx = operatorMethod->getDeclContext();
8170+
8171+
auto lhsParam = new (ctx) ParamDecl(
8172+
SourceLoc(),
8173+
SourceLoc(),Identifier(),
8174+
SourceLoc(),ctx.getIdentifier("lhs"),
8175+
parentCtx);
8176+
8177+
lhsParam->setInterfaceType(operatorMethod->getDeclContext()->getSelfInterfaceType());
8178+
8179+
if (operatorMethod->isMutating()) {
8180+
// This implicitly makes the parameter indirect.
8181+
lhsParam->setSpecifier(ParamSpecifier::InOut);
8182+
} else {
8183+
lhsParam->setSpecifier(ParamSpecifier::Default);
8184+
}
8185+
8186+
SmallVector<ParamDecl *, 4> newParams;
8187+
newParams.push_back(lhsParam);
8188+
8189+
for (auto param : *paramList) {
8190+
newParams.push_back(param);
8191+
}
8192+
8193+
auto oldArgNames = operatorMethod->getName().getArgumentNames();
8194+
SmallVector<Identifier, 4> newArgNames;
8195+
newArgNames.push_back(Identifier());
8196+
8197+
for (auto id : oldArgNames) {
8198+
newArgNames.push_back(id);
8199+
}
8200+
8201+
auto opDeclName = DeclName(
8202+
ctx,opId,
8203+
{newArgNames.begin(), newArgNames.end()});
8204+
8205+
auto topLevelStaticFuncDecl = FuncDecl::createImplicit(
8206+
ctx, StaticSpellingKind::None, opDeclName, SourceLoc(),
8207+
/*Async*/ false, /*Throws*/ false, genericParamList,
8208+
ParameterList::create(ctx, newParams),
8209+
operatorMethod->getResultInterfaceType(), parentCtx);
8210+
8211+
topLevelStaticFuncDecl->setAccess(AccessLevel::Public);
8212+
topLevelStaticFuncDecl->setIsDynamic(false);
8213+
topLevelStaticFuncDecl->setStatic();
8214+
topLevelStaticFuncDecl->setBodySynthesizer(synthesizeOperatorMethodBody,
8215+
operatorMethod);
8216+
8217+
return topLevelStaticFuncDecl;
8218+
}
8219+
80838220
void SwiftDeclConverter::addProtocols(
80848221
ProtocolDecl *protocol, SmallVectorImpl<ProtocolDecl *> &protocols,
80858222
llvm::SmallPtrSetImpl<ProtocolDecl *> &known) {

lib/ClangImporter/ImportName.cpp

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,20 @@ using namespace importer;
5757
using clang::CompilerInstance;
5858
using clang::CompilerInvocation;
5959

60+
static const char *getOperatorName(clang::OverloadedOperatorKind Operator) {
61+
switch (Operator) {
62+
case clang::OO_None:
63+
case clang::NUM_OVERLOADED_OPERATORS:
64+
return nullptr;
65+
66+
#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \
67+
case clang::OO_##Name: \
68+
return #Name;
69+
#include "clang/Basic/OperatorKinds.def"
70+
}
71+
72+
llvm_unreachable("Invalid OverloadedOperatorKind!");
73+
}
6074

6175
/// Determine whether the given Clang selector matches the given
6276
/// selector pieces.
@@ -1501,14 +1515,14 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
15011515
completionHandlerParamIndex =
15021516
swiftAsyncAttr->getCompletionHandlerIndex().getASTIndex();
15031517
}
1504-
1518+
15051519
if (const auto *asyncErrorAttr = D->getAttr<clang::SwiftAsyncErrorAttr>()) {
15061520
switch (auto convention = asyncErrorAttr->getConvention()) {
15071521
// No flag parameter in these cases.
15081522
case clang::SwiftAsyncErrorAttr::NonNullError:
15091523
case clang::SwiftAsyncErrorAttr::None:
15101524
break;
1511-
1525+
15121526
// Get the flag argument index and polarity from the attribute.
15131527
case clang::SwiftAsyncErrorAttr::NonZeroArgument:
15141528
case clang::SwiftAsyncErrorAttr::ZeroArgument:
@@ -1842,17 +1856,15 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
18421856
case clang::OverloadedOperatorKind::OO_LessEqual:
18431857
case clang::OverloadedOperatorKind::OO_GreaterEqual:
18441858
case clang::OverloadedOperatorKind::OO_AmpAmp:
1845-
case clang::OverloadedOperatorKind::OO_PipePipe:
1846-
baseName = clang::getOperatorSpelling(op);
1859+
case clang::OverloadedOperatorKind::OO_PipePipe: {
1860+
auto operatorName = isa<clang::CXXMethodDecl>(functionDecl)
1861+
? "__operator" + std::string{getOperatorName(op)}
1862+
: clang::getOperatorSpelling(op);
1863+
baseName = swiftCtx.getIdentifier(operatorName).str();
18471864
isFunction = true;
1848-
argumentNames.resize(
1849-
functionDecl->param_size() +
1850-
// C++ operators that are implemented as non-static member functions
1851-
// get imported into Swift as static member functions that use an
1852-
// additional parameter for the left-hand side operand instead of
1853-
// the receiver object.
1854-
(isa<clang::CXXMethodDecl>(D) ? 1 : 0));
1865+
addEmptyArgNamesForClangFunction(functionDecl, argumentNames);
18551866
break;
1867+
}
18561868
case clang::OverloadedOperatorKind::OO_Call:
18571869
baseName = "callAsFunction";
18581870
isFunction = true;

0 commit comments

Comments
 (0)