Skip to content

Commit 88913c1

Browse files
committed
[interop][SwiftToCxx] expose generic type traits for C++ types in generated header before it's used first
1 parent 8c48d26 commit 88913c1

File tree

6 files changed

+90
-55
lines changed

6 files changed

+90
-55
lines changed

lib/PrintAsClang/ModuleContentsWriter.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ class ModuleWriter {
126126
ModuleDecl &M;
127127

128128
llvm::DenseMap<const TypeDecl *, std::pair<EmissionState, bool>> seenTypes;
129+
llvm::DenseSet<const NominalTypeDecl *> seenClangTypes;
129130
std::vector<const Decl *> declsToWrite;
130131
DelayedMemberSet delayedMembers;
131132
PrimitiveTypeMapping typeMapping;
@@ -267,13 +268,22 @@ class ModuleWriter {
267268
});
268269
}
269270

271+
void emitReferencedClangTypeMetadata(const NominalTypeDecl *typeDecl) {
272+
auto it = seenClangTypes.insert(typeDecl);
273+
if (it.second)
274+
ClangValueTypePrinter::printClangTypeSwiftGenericTraits(os, typeDecl, &M);
275+
}
276+
270277
void forwardDeclareType(const TypeDecl *TD) {
271278
if (outputLangMode == OutputLanguageMode::Cxx) {
272279
if (isa<StructDecl>(TD) || isa<EnumDecl>(TD)) {
273280
auto *NTD = cast<NominalTypeDecl>(TD);
274281
if (!addImport(NTD)) {
275282
forwardDeclare(
276283
NTD, [&]() { ClangValueTypePrinter::forwardDeclType(os, NTD); });
284+
} else {
285+
if (isa<StructDecl>(TD) && NTD->hasClangNode())
286+
emitReferencedClangTypeMetadata(NTD);
277287
}
278288
}
279289
return;
@@ -703,11 +713,6 @@ class ModuleWriter {
703713

704714
// Print any out of line definitions.
705715
os << outOfLineDefinitionsOS.str();
706-
707-
// Print any additional metadata for referenced C++ types.
708-
for (const auto *typeDecl :
709-
printer.getInteropContext().getEmittedClangTypeDecls())
710-
ClangValueTypePrinter::printClangTypeSwiftGenericTraits(os, typeDecl, &M);
711716
}
712717
};
713718
} // end anonymous namespace

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,6 @@ class CFunctionSignatureTypePrinter
312312
handler.printTypeName(os);
313313
if (typeUseKind == FunctionSignatureTypeUse::ParamType)
314314
os << '&';
315-
interopContext.recordEmittedClangTypeDecl(decl);
316315
return ClangRepresentation::representable;
317316
}
318317

lib/PrintAsClang/SwiftToClangInteropContext.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,6 @@ void SwiftToClangInteropContext::runIfStubForDeclNotEmitted(
3535
function();
3636
}
3737

38-
void SwiftToClangInteropContext::recordEmittedClangTypeDecl(
39-
const NominalTypeDecl *typeDecl) {
40-
assert(typeDecl->hasClangNode());
41-
referencedClangTypeDecls.insert(typeDecl);
42-
}
43-
4438
void SwiftToClangInteropContext::recordExtensions(
4539
const NominalTypeDecl *typeDecl, const ExtensionDecl *ext) {
4640
auto it = extensions.insert(

lib/PrintAsClang/SwiftToClangInteropContext.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
#include "llvm/ADT/DenseMap.h"
1818
#include "llvm/ADT/Optional.h"
1919
#include "llvm/ADT/STLExtras.h"
20-
#include "llvm/ADT/SetVector.h"
2120
#include "llvm/ADT/StringSet.h"
2221
#include <memory>
2322

@@ -46,15 +45,6 @@ class SwiftToClangInteropContext {
4645
void runIfStubForDeclNotEmitted(llvm::StringRef stubName,
4746
llvm::function_ref<void(void)> function);
4847

49-
/// Records that the given nominal type decl that has a clang declaration was
50-
/// emitted in the generated header.
51-
void recordEmittedClangTypeDecl(const NominalTypeDecl *typeDecl);
52-
53-
inline const llvm::SetVector<const NominalTypeDecl *> &
54-
getEmittedClangTypeDecls() const {
55-
return referencedClangTypeDecls;
56-
}
57-
5848
void recordExtensions(const NominalTypeDecl *typeDecl,
5949
const ExtensionDecl *ext);
6050

@@ -66,7 +56,6 @@ class SwiftToClangInteropContext {
6656
const IRGenOptions &irGenOpts;
6757
std::unique_ptr<IRABIDetailsProvider> irABIDetails;
6858
llvm::StringSet<> emittedStubs;
69-
llvm::SetVector<const NominalTypeDecl *> referencedClangTypeDecls;
7059
llvm::DenseMap<const NominalTypeDecl *, std::vector<const ExtensionDecl *>>
7160
extensions;
7261
};

test/Interop/CxxToSwiftToCxx/bridge-cxx-struct-back-to-cxx-execution.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// RUN: %empty-directory(%t)
22
// RUN: split-file %s %t
33

4+
// RUN: %target-swift-frontend -parse-as-library %platform-module-dir/Swift.swiftmodule/%module-target-triple.swiftinterface -enable-library-evolution -disable-objc-attr-requires-foundation-module -typecheck -module-name Swift -parse-stdlib -enable-experimental-cxx-interop -emit-clang-header-path %t/Swift.h -experimental-skip-all-function-bodies
5+
46
// RUN: %target-swift-frontend -typecheck %t/use-cxx-types.swift -typecheck -module-name UseCxx -emit-clang-header-path %t/UseCxx.h -I %t -enable-experimental-cxx-interop -clang-header-expose-public-decls
57

68
// RUN: %target-interop-build-clangxx -std=c++20 -c %t/use-swift-cxx-types.cpp -I %t -o %t/swift-cxx-execution.o -g
@@ -88,9 +90,14 @@ public func retPassThroughGeneric<T>(_ x: T) -> T {
8890
return x
8991
}
9092

93+
public func retArrayNonTrivial(_ x: CInt) -> [NonTrivialTemplate<Trivial>] {
94+
return [NonTrivialTemplate<Trivial>(Trivial(x, -x))]
95+
}
96+
9197
//--- use-swift-cxx-types.cpp
9298

9399
#include "header.h"
100+
#include "Swift.h"
94101
#include "UseCxx.h"
95102
#include <assert.h>
96103

@@ -134,7 +141,6 @@ int main() {
134141
}
135142
puts("secondon non trivial");
136143
}
137-
puts("EndOfTest");
138144
// CHECK-NEXT: create NonTrivialTemplate
139145
// CHECK-NEXT: move NonTrivialTemplate
140146
// CHECK-NEXT: ~NonTrivialTemplate
@@ -158,6 +164,19 @@ int main() {
158164
// CHECK-NEXT: ~NonTrivialTemplate
159165
// CHECK-NEXT: secondon non trivial
160166
// CHECK-NEXT: ~NonTrivialTemplate
167+
{
168+
auto arr = UseCxx::retArrayNonTrivial(1234);
169+
auto val = arr[0];
170+
assert(val.x.x == 1234);
171+
assert(val.x.y == -1234);
172+
}
173+
// CHECK-NEXT: create NonTrivialTemplate
174+
// CHECK-NEXT: copy NonTrivialTemplate
175+
// CHECK-NEXT: move NonTrivialTemplate
176+
// CHECK-NEXT: ~NonTrivialTemplate
177+
// CHECK-NEXT: ~NonTrivialTemplate
178+
// CHECK-NEXT: ~NonTrivialTemplate
179+
puts("EndOfTest");
161180
// CHECK-NEXT: EndOfTest
162181
return 0;
163182
}

test/Interop/CxxToSwiftToCxx/bridge-cxx-struct-back-to-cxx.swift

Lines changed: 60 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,36 @@ public func takeTrivialInout(_ x: inout Trivial) {
9292
// CHECK: SWIFT_EXTERN void $s8UseCxxTy13retNonTrivialSo2nsO02__b18TemplateInstN2ns18efH4IiEEVyF(SWIFT_INDIRECT_RESULT void * _Nonnull) SWIFT_NOEXCEPT SWIFT_CALL; // retNonTrivial()
9393
// CHECK: SWIFT_EXTERN struct swift_interop_returnStub_UseCxxTy_uint32_t_0_4 $s8UseCxxTy10retTrivialSo0E0VyF(void) SWIFT_NOEXCEPT SWIFT_CALL; // retTrivial()
9494

95+
// CHECK: } // end namespace
96+
// CHECK-EMPTY:
97+
// CHECK-NEXT: namespace swift {
98+
// CHECK-NEXT: namespace _impl {
99+
// CHECK-EMPTY:
100+
// CHECK-NEXT: // Type metadata accessor for __CxxTemplateInstN2ns18NonTrivialTemplateIiEE
101+
// CHECK-NEXT: SWIFT_EXTERN swift::_impl::MetadataResponseTy $sSo2nsO033__CxxTemplateInstN2ns18NonTrivialC4IiEEVMa(swift::_impl::MetadataRequestTy) SWIFT_NOEXCEPT SWIFT_CALL;
102+
// CHECK-EMPTY:
103+
// CHECK-EMPTY:
104+
// CHECK-NEXT: } // namespace _impl
105+
// CHECK-EMPTY:
106+
// CHECK-NEXT: #pragma clang diagnostic push
107+
// CHECK-NEXT: #pragma clang diagnostic ignored "-Wc++17-extensions"
108+
// CHECK-NEXT: template<>
109+
// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext<ns::NonTrivialTemplate<int>> = true;
110+
// CHECK-NEXT: template<>
111+
// CHECK-NEXT: struct TypeMetadataTrait<ns::NonTrivialTemplate<int>> {
112+
// CHECK-NEXT: static inline void * _Nonnull getTypeMetadata() {
113+
// CHECK-NEXT: return _impl::$sSo2nsO033__CxxTemplateInstN2ns18NonTrivialC4IiEEVMa(0)._0;
114+
// CHECK-NEXT: }
115+
// CHECK-NEXT: };
116+
// CHECK-NEXT: namespace _impl{
117+
// CHECK-NEXT: template<>
118+
// CHECK-NEXT: static inline const constexpr bool isSwiftBridgedCxxRecord<ns::NonTrivialTemplate<int>> = true;
119+
// CHECK-NEXT: } // namespace
120+
// CHECK-NEXT: #pragma clang diagnostic pop
121+
// CHECK-NEXT: } // namespace swift
122+
// CHECK-EMPTY:
123+
// CHECK-NEXT: namespace UseCxxTy {
124+
95125
// CHECK: inline ns::NonTrivialTemplate<int> retNonTrivial() noexcept SWIFT_WARN_UNUSED_RESULT {
96126
// CHECK-NEXT: alignas(alignof(ns::NonTrivialTemplate<int>)) char storage[sizeof(ns::NonTrivialTemplate<int>)];
97127
// CHECK-NEXT: auto * _Nonnull storageObjectPtr = reinterpret_cast<ns::NonTrivialTemplate<int> *>(storage);
@@ -101,8 +131,37 @@ public func takeTrivialInout(_ x: inout Trivial) {
101131
// CHECK-NEXT: return result;
102132
// CHECK-NEXT: }
103133
// CHECK-EMPTY:
134+
// CHECK-NEXT: } // end namespace
135+
// CHECK-EMPTY:
136+
// CHECK-NEXT: namespace swift {
137+
// CHECK-NEXT: namespace _impl {
138+
// CHECK-EMPTY:
139+
// CHECK-NEXT: // Type metadata accessor for __CxxTemplateInstN2ns18NonTrivialTemplateINS_11TrivialinNSEEE
140+
// CHECK-NEXT: SWIFT_EXTERN swift::_impl::MetadataResponseTy $sSo2nsO033__CxxTemplateInstN2ns18NonTrivialC20INS_11TrivialinNSEEEVMa(swift::_impl::MetadataRequestTy) SWIFT_NOEXCEPT SWIFT_CALL;
141+
// CHECK-EMPTY:
142+
// CHECK-EMPTY:
143+
// CHECK-NEXT: } // namespace _impl
144+
// CHECK-EMPTY:
145+
// CHECK-NEXT: #pragma clang diagnostic push
146+
// CHECK-NEXT: #pragma clang diagnostic ignored "-Wc++17-extensions"
147+
// CHECK-NEXT: template<>
148+
// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext<ns::NonTrivialTemplate<ns::TrivialinNS>> = true;
149+
// CHECK-NEXT: template<>
150+
// CHECK-NEXT: struct TypeMetadataTrait<ns::NonTrivialTemplate<ns::TrivialinNS>> {
151+
// CHECK-NEXT: static inline void * _Nonnull getTypeMetadata() {
152+
// CHECK-NEXT: return _impl::$sSo2nsO033__CxxTemplateInstN2ns18NonTrivialC20INS_11TrivialinNSEEEVMa(0)._0;
153+
// CHECK-NEXT: }
154+
// CHECK-NEXT: };
155+
// CHECK-NEXT: namespace _impl{
156+
// CHECK-NEXT: template<>
157+
// CHECK-NEXT: static inline const constexpr bool isSwiftBridgedCxxRecord<ns::NonTrivialTemplate<ns::TrivialinNS>> = true;
158+
// CHECK-NEXT: } // namespace
159+
// CHECK-NEXT: #pragma clang diagnostic pop
160+
// CHECK-NEXT: } // namespace swift
161+
// CHECK-EMPTY:
162+
// CHECK-NEXT: namespace UseCxxTy {
104163
// CHECK-EMPTY:
105-
// CHECK: inline ns::NonTrivialTemplate<ns::TrivialinNS> retNonTrivial2() noexcept SWIFT_WARN_UNUSED_RESULT {
164+
// CHECK-NEXT: inline ns::NonTrivialTemplate<ns::TrivialinNS> retNonTrivial2() noexcept SWIFT_WARN_UNUSED_RESULT {
106165
// CHECK-NEXT: alignas(alignof(ns::NonTrivialTemplate<ns::TrivialinNS>)) char storage[sizeof(ns::NonTrivialTemplate<ns::TrivialinNS>)];
107166
// CHECK-NEXT: auto * _Nonnull storageObjectPtr = reinterpret_cast<ns::NonTrivialTemplate<ns::TrivialinNS> *>(storage);
108167
// CHECK-NEXT: _impl::$s8UseCxxTy14retNonTrivial2So2nsO02__b18TemplateInstN2ns18e7TrivialH20INS_11TrivialinNSEEEVyF(storage);
@@ -140,33 +199,3 @@ public func takeTrivialInout(_ x: inout Trivial) {
140199
// CHECK: inline void takeTrivialInout(Trivial& x) noexcept {
141200
// CHECK-NEXT: return _impl::$s8UseCxxTy16takeTrivialInoutyySo0E0VzF(swift::_impl::getOpaquePointer(x));
142201
// CHECK-NEXT: }
143-
144-
// CHECK: } // end namespace
145-
// CHECK-EMPTY:
146-
// CHECK-NEXT: namespace swift {
147-
// CHECK-NEXT: namespace _impl {
148-
// CHECK-EMPTY:
149-
// CHECK-NEXT: // Type metadata accessor for __CxxTemplateInstN2ns18NonTrivialTemplateIiEE
150-
// CHECK-NEXT: SWIFT_EXTERN swift::_impl::MetadataResponseTy $sSo2nsO033__CxxTemplateInstN2ns18NonTrivialC4IiEEVMa(swift::_impl::MetadataRequestTy) SWIFT_NOEXCEPT SWIFT_CALL;
151-
// CHECK-EMPTY:
152-
// CHECK-EMPTY:
153-
// CHECK-NEXT: } // namespace _impl
154-
// CHECK-EMPTY:
155-
// CHECK-NEXT: #pragma clang diagnostic push
156-
// CHECK-NEXT: #pragma clang diagnostic ignored "-Wc++17-extensions"
157-
// CHECK-NEXT: template<>
158-
// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext<ns::NonTrivialTemplate<int>> = true;
159-
// CHECK-NEXT: template<>
160-
// CHECK-NEXT: struct TypeMetadataTrait<ns::NonTrivialTemplate<int>> {
161-
// CHECK-NEXT: static inline void * _Nonnull getTypeMetadata() {
162-
// CHECK-NEXT: return _impl::$sSo2nsO033__CxxTemplateInstN2ns18NonTrivialC4IiEEVMa(0)._0;
163-
// CHECK-NEXT: }
164-
// CHECK-NEXT: };
165-
// CHECK-NEXT: namespace _impl{
166-
// CHECK-NEXT: template<>
167-
// CHECK-NEXT: static inline const constexpr bool isSwiftBridgedCxxRecord<ns::NonTrivialTemplate<int>> = true;
168-
// CHECK-NEXT: } // namespace
169-
// CHECK-NEXT: #pragma clang diagnostic pop
170-
// CHECK-NEXT: } // namespace swift
171-
// CHECK-EMPTY:
172-
// CHECK-NEXT: namespace UseCxxTy {

0 commit comments

Comments
 (0)