Skip to content

Commit b522a4b

Browse files
committed
[cxx-interop] serialize x-refs for class template specializations
1 parent 8484c61 commit b522a4b

File tree

3 files changed

+67
-3
lines changed

3 files changed

+67
-3
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4837,13 +4837,19 @@ TinyPtrVector<ValueDecl *> CXXNamespaceMemberLookup::evaluate(
48374837
auto &ctx = namespaceDecl->getASTContext();
48384838

48394839
TinyPtrVector<ValueDecl *> result;
4840+
llvm::SmallPtrSet<clang::NamedDecl *, 8> importedDecls;
48404841
for (auto redecl : clangNamespaceDecl->redecls()) {
48414842
auto allResults = evaluateOrDefault(
48424843
ctx.evaluator, ClangDirectLookupRequest({namespaceDecl, redecl, name}),
48434844
{});
48444845

48454846
for (auto found : allResults) {
48464847
auto clangMember = found.get<clang::NamedDecl *>();
4848+
auto it = importedDecls.insert(clangMember);
4849+
// Skip over members already found during lookup in
4850+
// prior redeclarations.
4851+
if (!it.second)
4852+
continue;
48474853
if (auto import =
48484854
ctx.getClangModuleLoader()->importDeclDirectly(clangMember))
48494855
result.push_back(cast<ValueDecl>(import));

lib/Serialization/Deserialization.cpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include "clang/AST/Attr.h"
4444
#include "clang/Basic/SourceManager.h"
4545
#include "clang/Basic/AttributeCommonInfo.h"
46+
#include "clang/Index/USRGeneration.h"
4647
#include "llvm/ADT/Statistic.h"
4748
#include "llvm/Support/Compiler.h"
4849
#include "llvm/Support/Debug.h"
@@ -2424,7 +2425,28 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
24242425
break;
24252426
}
24262427

2427-
if (!privateDiscriminator.empty()) {
2428+
if (importedFromClang &&
2429+
!privateDiscriminator.empty()) {
2430+
// This is a clang imported class template, that's
2431+
// serialized using original template name, and
2432+
// its USR that denotes the specific specialization.
2433+
auto members = nominal->lookupDirect(memberName);
2434+
for (const auto &m: members) {
2435+
if (!m->hasClangNode())
2436+
continue;
2437+
if (auto *ctd = dyn_cast<clang::ClassTemplateDecl>(m->getClangDecl())) {
2438+
for (const auto *spec: ctd->specializations()) {
2439+
llvm::SmallString<128> buffer;
2440+
clang::index::generateUSRForDecl(spec, buffer);
2441+
if (privateDiscriminator.str() == buffer) {
2442+
if (auto import =
2443+
getContext().getClangModuleLoader()->importDeclDirectly(spec))
2444+
values.push_back(cast<ValueDecl>(import));
2445+
}
2446+
}
2447+
}
2448+
}
2449+
} else if (!privateDiscriminator.empty()) {
24282450
ModuleDecl *searchModule = M;
24292451
if (!searchModule)
24302452
searchModule = nominal->getModuleContext();

lib/Serialization/Serialization.cpp

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
#include "swift/Strings.h"
5656
#include "clang/AST/DeclTemplate.h"
5757
#include "clang/Frontend/CompilerInstance.h"
58+
#include "clang/Index/USRGeneration.h"
5859
#include "clang/Serialization/ASTReader.h"
5960
#include "llvm/ADT/SmallSet.h"
6061
#include "llvm/ADT/SmallString.h"
@@ -2116,8 +2117,25 @@ void Serializer::writeCrossReference(const DeclContext *DC, uint32_t pathLen) {
21162117

21172118
bool isProtocolExt = DC->getParent()->getExtendedProtocolDecl();
21182119

2120+
Identifier name = generic->getName();
2121+
if (generic->hasClangNode()) {
2122+
if (auto *ctsd = dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(generic->getClangDecl())) {
2123+
auto it = name.str().find("<");
2124+
if (it != StringRef::npos) {
2125+
// Serialize a C++ class template specialization name as original
2126+
// class template name, and use its USR as the discriminator, that
2127+
// will let Swift find the correct specialization when this cross
2128+
// reference is deserialized.
2129+
name = getASTContext().getIdentifier(name.str().substr(0, it));
2130+
assert(discriminator.empty());
2131+
llvm::SmallString<128> buffer;
2132+
clang::index::generateUSRForDecl(ctsd, buffer);
2133+
discriminator = getASTContext().getIdentifier(buffer.str());
2134+
}
2135+
}
2136+
}
21192137
XRefTypePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode,
2120-
addDeclBaseNameRef(generic->getName()),
2138+
addDeclBaseNameRef(name),
21212139
addDeclBaseNameRef(discriminator),
21222140
isProtocolExt,
21232141
generic->hasClangNode());
@@ -2290,8 +2308,26 @@ void Serializer::writeCrossReference(const Decl *D) {
22902308
discriminator = containingFile->getDiscriminatorForPrivateDecl(type);
22912309
}
22922310

2311+
Identifier name = type->getName();
2312+
if (type->hasClangNode()) {
2313+
if (auto *ctsd = dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(type->getClangDecl())) {
2314+
auto it = name.str().find("<");
2315+
if (it != StringRef::npos) {
2316+
// Serialize a C++ class template specialization name as original
2317+
// class template name, and use its USR as the discriminator, that
2318+
// will let Swift find the correct specialization when this cross
2319+
// reference is deserialized.
2320+
name = getASTContext().getIdentifier(name.str().substr(0, it));
2321+
assert(discriminator.empty());
2322+
llvm::SmallString<128> buffer;
2323+
clang::index::generateUSRForDecl(ctsd, buffer);
2324+
discriminator = getASTContext().getIdentifier(buffer.str());
2325+
}
2326+
}
2327+
}
2328+
22932329
XRefTypePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode,
2294-
addDeclBaseNameRef(type->getName()),
2330+
addDeclBaseNameRef(name),
22952331
addDeclBaseNameRef(discriminator),
22962332
isProtocolExt, D->hasClangNode());
22972333
return;

0 commit comments

Comments
 (0)