Skip to content

Commit f371c43

Browse files
committed
[interop][SwiftToCxx] pass boxed resilient value types to generic functions correctly
1 parent c537cd2 commit f371c43

File tree

6 files changed

+82
-14
lines changed

6 files changed

+82
-14
lines changed

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -451,13 +451,8 @@ void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse(
451451
if (type->getAs<ArchetypeType>() && type->getAs<ArchetypeType>()
452452
->getInterfaceType()
453453
->is<GenericTypeParamType>()) {
454-
// FIXME: NEED to handle boxed resilient type.
455-
// os << "swift::" << cxx_synthesis::getCxxImplNamespaceName() <<
456-
// "::getOpaquePointer(";
457-
os << "reinterpret_cast<";
458-
if (!isInOut)
459-
os << "const ";
460-
os << "void *>(&";
454+
os << "swift::" << cxx_synthesis::getCxxImplNamespaceName()
455+
<< "::getOpaquePointer(";
461456
namePrinter();
462457
os << ')';
463458
return;

lib/PrintAsClang/PrintClangValueType.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,14 @@ void ClangValueTypePrinter::printTypeGenericTraits(
499499
os << "::";
500500
printer.printBaseName(typeDecl);
501501
os << "> = true;\n";
502+
if (typeDecl->isResilient()) {
503+
os << "template<>\n";
504+
os << "static inline const constexpr bool isOpaqueLayout<";
505+
printer.printBaseName(typeDecl->getModuleContext());
506+
os << "::";
507+
printer.printBaseName(typeDecl);
508+
os << "> = true;\n";
509+
}
502510
}
503511

504512
os << "template<>\n";

stdlib/public/SwiftShims/_SwiftCxxInteroperability.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,24 @@ template <class T> struct implClassFor {
154154
/// True if the given type is a Swift value type.
155155
template <class T> static inline const constexpr bool isValueType = false;
156156

157+
/// True if the given type is a Swift value type with opaque layout that can be
158+
/// boxed.
159+
template <class T> static inline const constexpr bool isOpaqueLayout = false;
160+
161+
/// Returns the opaque pointer to the given value.
162+
template <class T>
163+
inline const void *_Nonnull getOpaquePointer(const T &value) {
164+
if constexpr (isOpaqueLayout<T>)
165+
return reinterpret_cast<const OpaqueStorage &>(value).getOpaquePointer();
166+
return reinterpret_cast<const void *>(&value);
167+
}
168+
169+
template <class T> inline void *_Nonnull getOpaquePointer(T &value) {
170+
if constexpr (isOpaqueLayout<T>)
171+
return reinterpret_cast<OpaqueStorage &>(value).getOpaquePointer();
172+
return reinterpret_cast<void *>(&value);
173+
}
174+
157175
} // namespace _impl
158176

159177
#pragma clang diagnostic pop

test/Interop/SwiftToCxx/generics/generic-function-in-cxx.swift

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
// RUN: %check-generic-interop-cxx-header-in-clang(%t/functions.h -Wno-unused-function)
66

7+
// RUN: %target-swift-frontend %s -typecheck -module-name Functions -enable-library-evolution -clang-header-expose-public-decls -emit-clang-header-path %t/functions-evo.h
8+
// RUN: %FileCheck %s < %t/functions-evo.h
9+
10+
// RUN: %check-generic-interop-cxx-header-in-clang(%t/functions-evo.h -Wno-unused-function)
711

812
public func genericPrintFunctionTwoArg<T>(_ x: T, _ y: Int) {
913
print("X:", x)
@@ -87,43 +91,43 @@ public func createTestSmallStruct(_ x: UInt32) -> TestSmallStruct {
8791
// CHECK: template<class T>
8892
// CHECK-NEXT: requires swift::isUsableInGenericContext<T>
8993
// CHECK-NEXT: inline void genericPrintFunction(const T & x) noexcept {
90-
// CHECK-NEXT: return _impl::$s9Functions20genericPrintFunctionyyxlF(reinterpret_cast<const void *>(&x), swift::getTypeMetadata<T>());
94+
// CHECK-NEXT: return _impl::$s9Functions20genericPrintFunctionyyxlF(swift::_impl::getOpaquePointer(x), swift::getTypeMetadata<T>());
9195
// CHECK-NEXT: }
9296

9397

9498
// CHECK: template<class T1, class T2>
9599
// CHECK-NEXT: requires swift::isUsableInGenericContext<T1> && swift::isUsableInGenericContext<T2>
96100
// CHECK-NEXT: inline void genericPrintFunctionMultiGeneric(swift::Int x, const T1 & t1, const T1 & t1p, swift::Int y, const T2 & t2) noexcept {
97-
// CHECK-NEXT: return _impl::$s9Functions32genericPrintFunctionMultiGenericyySi_xxSiq_tr0_lF(x, reinterpret_cast<const void *>(&t1), reinterpret_cast<const void *>(&t1p), y, reinterpret_cast<const void *>(&t2), swift::getTypeMetadata<T1>(), swift::getTypeMetadata<T2>());
101+
// CHECK-NEXT: return _impl::$s9Functions32genericPrintFunctionMultiGenericyySi_xxSiq_tr0_lF(x, swift::_impl::getOpaquePointer(t1), swift::_impl::getOpaquePointer(t1p), y, swift::_impl::getOpaquePointer(t2), swift::getTypeMetadata<T1>(), swift::getTypeMetadata<T2>());
98102
// CHECK-NEXT: }
99103

100104

101105
// CHECK: template<class T>
102106
// CHECK-NEXT: requires swift::isUsableInGenericContext<T>
103107
// CHECK-NEXT: inline void genericPrintFunctionTwoArg(const T & x, swift::Int y) noexcept {
104-
// CHECK-NEXT: return _impl::$s9Functions26genericPrintFunctionTwoArgyyx_SitlF(reinterpret_cast<const void *>(&x), y, swift::getTypeMetadata<T>());
108+
// CHECK-NEXT: return _impl::$s9Functions26genericPrintFunctionTwoArgyyx_SitlF(swift::_impl::getOpaquePointer(x), y, swift::getTypeMetadata<T>());
105109
// CHECK-NEXT: }
106110

107111
// CHECK: template<class T>
108112
// CHECK-NEXT: requires swift::isUsableInGenericContext<T>
109113
// CHECK-NEXT: inline T genericRet(const T & x) noexcept SWIFT_WARN_UNUSED_RESULT {
110114
// CHECK-NEXT: if constexpr (std::is_base_of<::swift::_impl::RefCountedClass, T>::value) {
111115
// CHECK-NEXT: void *returnValue;
112-
// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(reinterpret_cast<void *>(&returnValue), reinterpret_cast<const void *>(&x), swift::getTypeMetadata<T>());
116+
// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(reinterpret_cast<void *>(&returnValue), swift::_impl::getOpaquePointer(x), swift::getTypeMetadata<T>());
113117
// CHECK-NEXT: return ::swift::_impl::implClassFor<T>::type::makeRetained(returnValue);
114118
// CHECK-NEXT: } else if constexpr (::swift::_impl::isValueType<T>) {
115119
// CHECK-NEXT: return ::swift::_impl::implClassFor<T>::type::returnNewValue([&](void * _Nonnull returnValue) {
116-
// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(returnValue, reinterpret_cast<const void *>(&x), swift::getTypeMetadata<T>());
120+
// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(returnValue, swift::_impl::getOpaquePointer(x), swift::getTypeMetadata<T>());
117121
// CHECK-NEXT: });
118122
// CHECK-NEXT: } else {
119123
// CHECK-NEXT: T returnValue;
120-
// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(reinterpret_cast<void *>(&returnValue), reinterpret_cast<const void *>(&x), swift::getTypeMetadata<T>());
124+
// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(reinterpret_cast<void *>(&returnValue), swift::_impl::getOpaquePointer(x), swift::getTypeMetadata<T>());
121125
// CHECK-NEXT: return returnValue;
122126
// CHECK-NEXT: }
123127
// CHECK-NEXT: }
124128

125129
// CHECK: template<class T>
126130
// CHECK-NEXT: requires swift::isUsableInGenericContext<T>
127131
// CHECK-NEXT: inline void genericSwap(T & x, T & y) noexcept {
128-
// CHECK-NEXT: return _impl::$s9Functions11genericSwapyyxz_xztlF(reinterpret_cast<void *>(&x), reinterpret_cast<void *>(&y), swift::getTypeMetadata<T>());
132+
// CHECK-NEXT: return _impl::$s9Functions11genericSwapyyxz_xztlF(swift::_impl::getOpaquePointer(x), swift::_impl::getOpaquePointer(y), swift::getTypeMetadata<T>());
129133
// CHECK-NEXT: }
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend %S/generic-function-in-cxx.swift -typecheck -module-name Functions -enable-library-evolution -clang-header-expose-public-decls -emit-clang-header-path %t/functions.h
4+
5+
// RUN: %target-interop-build-clangxx -std=gnu++20 -c %s -I %t -o %t/swift-functions-execution.o
6+
// RUN: %target-interop-build-swift %S/generic-function-in-cxx.swift -o %t/swift-functions-execution -Xlinker %t/swift-functions-execution.o -enable-library-evolution -module-name Functions -Xfrontend -entry-point-function-name -Xfrontend swiftMain
7+
8+
// RUN: %target-codesign %t/swift-functions-execution
9+
// RUN: %target-run %t/swift-functions-execution | %FileCheck %S/generic-function-execution.cpp
10+
11+
// REQUIRES: executable_test
12+
13+
#include "generic-function-execution.cpp"

test/Interop/SwiftToCxx/structs/resilient-struct-in-cxx.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,36 @@ public struct FirstSmallStruct {
5959
// CHECK-NEXT: friend class _impl::_impl_FirstSmallStruct;
6060
// CHECK-NEXT:};
6161

62+
// CHECK: class _impl_FirstSmallStruct {
63+
// CHECK: };
64+
// CHECK-EMPTY:
65+
// CHECK-NEXT: }
66+
67+
// CHECK-EMPTY:
68+
// CHECK-NEXT: } // end namespace
69+
// CHECK-EMPTY:
70+
// CHECK-NEXT: namespace swift {
71+
// CHECK-NEXT: #pragma clang diagnostic push
72+
// CHECK-NEXT: #pragma clang diagnostic ignored "-Wc++17-extensions"
73+
// CHECK-NEXT: template<>
74+
// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext<Structs::FirstSmallStruct> = true;
75+
// CHECK-NEXT: template<>
76+
// CHECK-NEXT: inline void * _Nonnull getTypeMetadata<Structs::FirstSmallStruct>() {
77+
// CHECK-NEXT: return Structs::_impl::$s7Structs16FirstSmallStructVMa(0)._0;
78+
// CHECK-NEXT: }
79+
// CHECK-NEXT: namespace _impl{
80+
// CHECK-NEXT: template<>
81+
// CHECK-NEXT: static inline const constexpr bool isValueType<Structs::FirstSmallStruct> = true;
82+
// CHECK-NEXT: template<>
83+
// CHECK-NEXT: static inline const constexpr bool isOpaqueLayout<Structs::FirstSmallStruct> = true;
84+
// CHECK-NEXT: template<>
85+
// CHECK-NEXT: struct implClassFor<Structs::FirstSmallStruct> { using type = Structs::_impl::_impl_FirstSmallStruct; };
86+
// CHECK-NEXT: } // namespace
87+
// CHECK-NEXT: #pragma clang diagnostic pop
88+
// CHECK-NEXT: } // namespace swift
89+
// CHECK-EMPTY:
90+
// CHECK-NEXT: namespace Structs {
91+
6292
// CHECK: inline uint32_t FirstSmallStruct::getX() const {
6393
// CHECK-NEXT: return _impl::$s7Structs16FirstSmallStructV1xs6UInt32Vvg(_getOpaquePointer());
6494
// CHECK-NEXT: }

0 commit comments

Comments
 (0)