Skip to content

Commit bcb553a

Browse files
committed
[cxx-interop][serialization] resolve x-refs to instantiated/synthesized C++ iterator conformance operators
These x-refs are not resolvable using regular lookup from the 'std' module as they're instantiated by the clang importer, and thus they need a different lookup path in order to get resolved. The new lookup uses the clang importer logic that is used during the conformance to the C++ iterator protocol.
1 parent d92f181 commit bcb553a

File tree

5 files changed

+60
-9
lines changed

5 files changed

+60
-9
lines changed

include/swift/ClangImporter/ClangImporter.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,13 @@ bool isCFTypeDecl(const clang::TypedefNameDecl *Decl);
684684
/// Determine the imported CF type for the given typedef-name, or the empty
685685
/// string if this is not an imported CF type name.
686686
llvm::StringRef getCFTypeName(const clang::TypedefNameDecl *decl);
687+
688+
/// Lookup and return the synthesized conformance operator like '==' '-' or '++'
689+
/// for the given type.
690+
ValueDecl *getSynthesizedConformanceOperator(const DeclBaseName &name,
691+
NominalTypeDecl *selfType,
692+
std::optional<Type> parameterType);
693+
687694
} // namespace importer
688695

689696
struct ClangInvocationFileMapping {

lib/ClangImporter/ClangDerivedConformances.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,23 @@ bool swift::isIterator(const clang::CXXRecordDecl *clangDecl) {
394394
return getIteratorCategoryDecl(clangDecl);
395395
}
396396

397+
ValueDecl *swift::importer::getSynthesizedConformanceOperator(const DeclBaseName &name,
398+
NominalTypeDecl *selfType,
399+
std::optional<Type> parameterType) {
400+
assert (name.isOperator());
401+
if (name.getIdentifier() == selfType->getASTContext().Id_EqualsOperator) {
402+
return getEqualEqualOperator(selfType);
403+
}
404+
if (name.getIdentifier() == selfType->getASTContext().getIdentifier("-")) {
405+
return getMinusOperator(selfType);
406+
}
407+
if (name.getIdentifier() == selfType->getASTContext().getIdentifier("+=") &&
408+
parameterType) {
409+
return getPlusEqualOperator(selfType, *parameterType);
410+
}
411+
return nullptr;
412+
}
413+
397414
void swift::conformToCxxIteratorIfNeeded(
398415
ClangImporter::Implementation &impl, NominalTypeDecl *decl,
399416
const clang::CXXRecordDecl *clangDecl) {
@@ -504,6 +521,8 @@ void swift::conformToCxxIteratorIfNeeded(
504521
equalEqual = getEqualEqualOperator(decl);
505522
}
506523
}
524+
if (equalEqual)
525+
equalEqual->setSynthesized();
507526
}
508527
if (!equalEqual)
509528
return;
@@ -539,6 +558,8 @@ void swift::conformToCxxIteratorIfNeeded(
539558
minus = getMinusOperator(decl);
540559
}
541560
}
561+
if (minus)
562+
minus->setSynthesized();
542563
}
543564
if (!minus)
544565
return;
@@ -562,6 +583,8 @@ void swift::conformToCxxIteratorIfNeeded(
562583
plusEqual = getPlusEqualOperator(decl, distanceTy);
563584
}
564585
}
586+
if (plusEqual)
587+
plusEqual->setSynthesized();
565588
}
566589
if (!plusEqual)
567590
return;

lib/Serialization/Deserialization.cpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2001,12 +2001,13 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
20012001
bool inProtocolExt = false;
20022002
bool importedFromClang = false;
20032003
bool isStatic = false;
2004+
bool isSynthesized = false;
20042005
if (isType)
20052006
XRefTypePathPieceLayout::readRecord(scratch, IID, privateDiscriminator,
20062007
inProtocolExt, importedFromClang);
20072008
else
20082009
XRefValuePathPieceLayout::readRecord(scratch, TID, IID, inProtocolExt,
2009-
importedFromClang, isStatic);
2010+
importedFromClang, isStatic, isSynthesized);
20102011

20112012
DeclBaseName name = getDeclBaseName(IID);
20122013
pathTrace.addValue(name);
@@ -2032,6 +2033,23 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
20322033
if (privateDiscriminator) {
20332034
baseModule->lookupMember(values, baseModule, name,
20342035
getIdentifier(privateDiscriminator));
2036+
} else if (isSynthesized && importedFromClang) {
2037+
ValueDecl *synthesizedResult = nullptr;
2038+
if (name.isOperator() && filterTy) {
2039+
// This is a Clang-importer synthesized conformance operator. Resolve it
2040+
// using clang importer lookup logic for the given type.
2041+
if (auto *fty = dyn_cast<AnyFunctionType>(filterTy.getPointer())) {
2042+
if (fty->getNumParams()) {
2043+
auto p = fty->getParams()[0].getParameterType();
2044+
if (auto sty = dyn_cast<NominalType>(p.getPointer()))
2045+
synthesizedResult = importer::getSynthesizedConformanceOperator(name, sty->getDecl(), fty->getNumParams() > 1 ? fty->getParams()[1].getParameterType() : std::optional<Type>{});
2046+
}
2047+
}
2048+
}
2049+
if (!synthesizedResult)
2050+
return llvm::make_error<XRefError>("couldn't find synthesized clang value decl x-ref",
2051+
pathTrace, name);
2052+
values.push_back(synthesizedResult);
20352053
} else {
20362054
baseModule->lookupQualified(baseModule, DeclNameRef(name),
20372055
SourceLoc(), NL_QualifiedDefault,
@@ -2133,7 +2151,7 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
21332151
IdentifierID IID;
21342152
XRefValuePathPieceLayout::readRecord(scratch, std::nullopt, IID,
21352153
std::nullopt, std::nullopt,
2136-
std::nullopt);
2154+
std::nullopt, std::nullopt);
21372155
result = getIdentifier(IID);
21382156
break;
21392157
}
@@ -2200,12 +2218,13 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
22002218
bool inProtocolExt = false;
22012219
bool importedFromClang = false;
22022220
bool isStatic = false;
2221+
bool isSynthesized = false;
22032222
if (isType) {
22042223
XRefTypePathPieceLayout::readRecord(scratch, IID, privateDiscriminator,
22052224
inProtocolExt, importedFromClang);
22062225
} else {
22072226
XRefValuePathPieceLayout::readRecord(scratch, TID, IID, inProtocolExt,
2208-
importedFromClang, isStatic);
2227+
importedFromClang, isStatic, isSynthesized);
22092228
}
22102229

22112230
DeclBaseName name = getDeclBaseName(IID);
@@ -2378,6 +2397,7 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
23782397
bool inProtocolExt = false;
23792398
bool importedFromClang = false;
23802399
bool isStatic = false;
2400+
bool isSynthesized = false;
23812401
switch (recordID) {
23822402
case XREF_TYPE_PATH_PIECE: {
23832403
IdentifierID IID, discriminatorID;
@@ -2392,7 +2412,7 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
23922412
case XREF_VALUE_PATH_PIECE: {
23932413
IdentifierID IID;
23942414
XRefValuePathPieceLayout::readRecord(scratch, TID, IID, inProtocolExt,
2395-
importedFromClang, isStatic);
2415+
importedFromClang, isStatic, isSynthesized);
23962416
memberName = getDeclBaseName(IID);
23972417
break;
23982418
}

lib/Serialization/ModuleFormat.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2089,7 +2089,8 @@ namespace decls_block {
20892089
IdentifierIDField, // name
20902090
BCFixed<1>, // restrict to protocol extension
20912091
BCFixed<1>, // imported from Clang?
2092-
BCFixed<1> // static?
2092+
BCFixed<1>, // static?
2093+
BCFixed<1> // synthesized?
20932094
>;
20942095

20952096
using XRefInitializerPathPieceLayout = BCRecordLayout<

lib/Serialization/Serialization.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2198,7 +2198,7 @@ void Serializer::writeCrossReference(const DeclContext *DC, uint32_t pathLen) {
21982198
XRefValuePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode,
21992199
addTypeRef(ty), SUBSCRIPT_ID,
22002200
isProtocolExt, SD->hasClangNode(),
2201-
SD->isStatic());
2201+
SD->isStatic(), SD->isSynthesized());
22022202
break;
22032203
}
22042204

@@ -2215,7 +2215,7 @@ void Serializer::writeCrossReference(const DeclContext *DC, uint32_t pathLen) {
22152215
addTypeRef(ty), nameID,
22162216
isProtocolExt,
22172217
storage->hasClangNode(),
2218-
storage->isStatic());
2218+
storage->isStatic(), storage->isSynthesized());
22192219

22202220
abbrCode =
22212221
DeclTypeAbbrCodes[XRefOperatorOrAccessorPathPieceLayout::Code];
@@ -2250,7 +2250,7 @@ void Serializer::writeCrossReference(const DeclContext *DC, uint32_t pathLen) {
22502250
addTypeRef(ty),
22512251
addDeclBaseNameRef(fn->getBaseName()),
22522252
isProtocolExt, fn->hasClangNode(),
2253-
fn->isStatic());
2253+
fn->isStatic(), fn->isSynthesized());
22542254

22552255
if (fn->isOperator()) {
22562256
// Encode the fixity as a filter on the func decls, to distinguish prefix
@@ -2357,7 +2357,7 @@ void Serializer::writeCrossReference(const Decl *D) {
23572357
IdentifierID iid = addDeclBaseNameRef(val->getBaseName());
23582358
XRefValuePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode,
23592359
addTypeRef(ty), iid, isProtocolExt,
2360-
D->hasClangNode(), val->isStatic());
2360+
D->hasClangNode(), val->isStatic(), val->isSynthesized());
23612361
}
23622362

23632363
/// Translate from the AST associativity enum to the Serialization enum

0 commit comments

Comments
 (0)