Skip to content

Commit 6e7f1ec

Browse files
committed
[cxx-interop] serialize x-refs for class template specializations
Fixes #70253
1 parent 8484c61 commit 6e7f1ec

File tree

4 files changed

+150
-8
lines changed

4 files changed

+150
-8
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: 24 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,29 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
24242425
break;
24252426
}
24262427

2427-
if (!privateDiscriminator.empty()) {
2428+
if (importedFromClang && !privateDiscriminator.empty()) {
2429+
// This is a clang imported class template, that's
2430+
// serialized using original template name, and
2431+
// its USR that denotes the specific specialization.
2432+
auto members = nominal->lookupDirect(memberName);
2433+
for (const auto &m : members) {
2434+
if (!m->hasClangNode())
2435+
continue;
2436+
if (auto *ctd =
2437+
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(
2444+
spec))
2445+
values.push_back(cast<ValueDecl>(import));
2446+
}
2447+
}
2448+
}
2449+
}
2450+
} else if (!privateDiscriminator.empty()) {
24282451
ModuleDecl *searchModule = M;
24292452
if (!searchModule)
24302453
searchModule = nominal->getModuleContext();

lib/Serialization/Serialization.cpp

Lines changed: 42 additions & 7 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"
@@ -2060,6 +2061,23 @@ getStableClangDeclPathComponentKind(
20602061
llvm_unreachable("bad kind");
20612062
}
20622063

2064+
static Identifier getClangTemplateSpecializationXRefDiscriminator(
2065+
ASTContext &ctx, Identifier &name,
2066+
const clang::ClassTemplateSpecializationDecl *ctsd) {
2067+
auto it = name.str().find("<");
2068+
if (it != StringRef::npos) {
2069+
// Serialize a C++ class template specialization name as original
2070+
// class template name, and use its USR as the discriminator, that
2071+
// will let Swift find the correct specialization when this cross
2072+
// reference is deserialized.
2073+
name = ctx.getIdentifier(name.str().substr(0, it));
2074+
llvm::SmallString<128> buffer;
2075+
clang::index::generateUSRForDecl(ctsd, buffer);
2076+
return ctx.getIdentifier(buffer.str());
2077+
}
2078+
return Identifier();
2079+
}
2080+
20632081
void Serializer::writeCrossReference(const DeclContext *DC, uint32_t pathLen) {
20642082
using namespace decls_block;
20652083

@@ -2116,11 +2134,19 @@ void Serializer::writeCrossReference(const DeclContext *DC, uint32_t pathLen) {
21162134

21172135
bool isProtocolExt = DC->getParent()->getExtendedProtocolDecl();
21182136

2137+
Identifier name = generic->getName();
2138+
if (generic->hasClangNode()) {
2139+
if (auto *ctsd = dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(
2140+
generic->getClangDecl())) {
2141+
assert(discriminator.empty());
2142+
discriminator = getClangTemplateSpecializationXRefDiscriminator(
2143+
getASTContext(), name, ctsd);
2144+
}
2145+
}
21192146
XRefTypePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode,
2120-
addDeclBaseNameRef(generic->getName()),
2147+
addDeclBaseNameRef(name),
21212148
addDeclBaseNameRef(discriminator),
2122-
isProtocolExt,
2123-
generic->hasClangNode());
2149+
isProtocolExt, generic->hasClangNode());
21242150
break;
21252151
}
21262152

@@ -2290,10 +2316,19 @@ void Serializer::writeCrossReference(const Decl *D) {
22902316
discriminator = containingFile->getDiscriminatorForPrivateDecl(type);
22912317
}
22922318

2293-
XRefTypePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode,
2294-
addDeclBaseNameRef(type->getName()),
2295-
addDeclBaseNameRef(discriminator),
2296-
isProtocolExt, D->hasClangNode());
2319+
Identifier name = type->getName();
2320+
if (type->hasClangNode()) {
2321+
if (auto *ctsd = dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(
2322+
type->getClangDecl())) {
2323+
assert(discriminator.empty());
2324+
discriminator = getClangTemplateSpecializationXRefDiscriminator(
2325+
getASTContext(), name, ctsd);
2326+
}
2327+
}
2328+
2329+
XRefTypePathPieceLayout::emitRecord(
2330+
Out, ScratchRecord, abbrCode, addDeclBaseNameRef(name),
2331+
addDeclBaseNameRef(discriminator), isProtocolExt, D->hasClangNode());
22972332
return;
22982333
}
22992334

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
// RUN: %target-swiftxx-frontend -emit-module %t/Inputs/test.swift -module-name TestA -I %t/Inputs -o %t/test-part.swiftmodule
4+
// RUN: %target-swiftxx-frontend -merge-modules -emit-module %t/test-part.swiftmodule -module-name TestA -I %t/Inputs -o %t/TestA.swiftmodule -sil-verify-none
5+
// RUN: %target-swift-ide-test -print-module -module-to-print=TestA -I %t/ -source-filename=test -enable-experimental-cxx-interop | %FileCheck %s
6+
7+
//--- Inputs/module.modulemap
8+
module CxxHeader {
9+
header "header.h"
10+
requires cplusplus
11+
}
12+
13+
//--- Inputs/header.h
14+
15+
#include <stdint.h>
16+
17+
namespace std2 {
18+
19+
template<class T>
20+
class vec {
21+
public:
22+
using Element = T;
23+
using RawIterator = const T * _Nonnull;
24+
vec() {}
25+
vec(const vec<T> &other) : items(other.items) { }
26+
~vec() {}
27+
28+
T * _Nonnull begin() {
29+
return items;
30+
}
31+
T * _Nonnull end() {
32+
return items + 10;
33+
}
34+
RawIterator begin() const {
35+
return items;
36+
}
37+
RawIterator end() const {
38+
return items + 10;
39+
}
40+
size_t size() const {
41+
return 10;
42+
}
43+
44+
private:
45+
T items[10];
46+
};
47+
48+
} // namespace std2
49+
50+
namespace ns2 {
51+
52+
class App {
53+
public:
54+
55+
inline std2::vec<App> getApps() const {
56+
return {};
57+
}
58+
int x = 0;
59+
};
60+
61+
} // namespace ns2
62+
63+
using vec2Apps = std2::vec<ns2::App>;
64+
65+
//--- Inputs/test.swift
66+
67+
import Cxx
68+
import CxxHeader
69+
70+
extension vec2Apps : CxxSequence {
71+
}
72+
73+
public func testFunction() -> [Int] {
74+
let applications = ns2.App().getApps()
75+
return applications.map { Int($0.x) }
76+
}
77+
78+
// CHECK: func testFunction() -> [Int]

0 commit comments

Comments
 (0)