Skip to content

Commit 35edc3a

Browse files
author
Gabor Horvath
committed
[cxx-interop] Support optional generic cases in enums
This PR implements proper support for optional generic associated values in enum cases. Most of the code changes are supporting generic types in more contexts in the printer, the rest are making sure we handle the null pointer case when we try to get the declaration from the type that represents a generic parameter. rdar://131112273
1 parent 255a941 commit 35edc3a

File tree

6 files changed

+61
-48
lines changed

6 files changed

+61
-48
lines changed

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 27 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -545,25 +545,29 @@ class DeclAndTypePrinter::Implementation
545545
std::tie(objectType, optKind) = getObjectTypeAndOptionality(
546546
paramType->getNominalOrBoundGenericNominal(), paramType);
547547
auto objectTypeDecl = objectType->getNominalOrBoundGenericNominal();
548+
assert(objectTypeDecl != nullptr || paramType->isOptional());
548549

549-
if (auto knownCxxType =
550-
owningPrinter.typeMapping.getKnownCxxTypeInfo(
551-
objectTypeDecl)) {
550+
if (objectTypeDecl &&
551+
owningPrinter.typeMapping.getKnownCxxTypeInfo(objectTypeDecl)) {
552552
outOfLineOS << " " << types[paramType] << " result;\n";
553553
outOfLineOS << " "
554554
"memcpy(&result, payloadFromDestruction, "
555555
"sizeof(result));\n";
556556
outOfLineOS << " return result;\n ";
557557
} else {
558+
bool isOptional = false;
559+
if (!objectTypeDecl) {
560+
objectTypeDecl = paramType->getNominalOrBoundGenericNominal();
561+
isOptional = true;
562+
}
558563
outOfLineOS << " return swift::";
559564
outOfLineOS << cxx_synthesis::getCxxImplNamespaceName();
560565
outOfLineOS << "::implClassFor<";
561-
outOfLineSyntaxPrinter.printModuleNamespaceQualifiersIfNeeded(
562-
objectTypeDecl->getModuleContext(),
566+
outOfLineSyntaxPrinter.printNominalTypeReference(
567+
objectTypeDecl,
563568
elementDecl->getParentEnum()->getModuleContext());
564-
outOfLineSyntaxPrinter.printBaseName(objectTypeDecl);
565569
outOfLineOS << ">::type";
566-
if (isa<ClassDecl>(objectTypeDecl)) {
570+
if (!isOptional && isa<ClassDecl>(objectTypeDecl)) {
567571
outOfLineOS << "::makeRetained(*reinterpret_cast<void "
568572
"**>(payloadFromDestruction));\n ";
569573
} else {
@@ -572,10 +576,9 @@ class DeclAndTypePrinter::Implementation
572576
outOfLineOS << " swift::"
573577
<< cxx_synthesis::getCxxImplNamespaceName();
574578
outOfLineOS << "::implClassFor<";
575-
outOfLineSyntaxPrinter.printModuleNamespaceQualifiersIfNeeded(
576-
objectTypeDecl->getModuleContext(),
579+
outOfLineSyntaxPrinter.printNominalTypeReference(
580+
objectTypeDecl,
577581
elementDecl->getParentEnum()->getModuleContext());
578-
outOfLineSyntaxPrinter.printBaseName(objectTypeDecl);
579582
outOfLineOS << ">::type";
580583
outOfLineOS << "::initializeWithTake(result, "
581584
"payloadFromDestruction);\n";
@@ -709,14 +712,15 @@ class DeclAndTypePrinter::Implementation
709712
ED, paramType);
710713
auto objectTypeDecl =
711714
objectType->getNominalOrBoundGenericNominal();
712-
assert(objectTypeDecl != nullptr);
715+
assert(objectTypeDecl != nullptr || paramType->isOptional());
713716

714-
if (owningPrinter.typeMapping.getKnownCxxTypeInfo(
717+
if (objectTypeDecl &&
718+
owningPrinter.typeMapping.getKnownCxxTypeInfo(
715719
objectTypeDecl)) {
716720
outOfLineOS
717721
<< " memcpy(result._getOpaquePointer(), &val, "
718722
"sizeof(val));\n";
719-
} else if (isa<ClassDecl>(objectTypeDecl)) {
723+
} else if (isa_and_nonnull<ClassDecl>(objectTypeDecl)) {
720724
outOfLineOS
721725
<< " auto op = swift::"
722726
<< cxx_synthesis::getCxxImplNamespaceName()
@@ -727,46 +731,31 @@ class DeclAndTypePrinter::Implementation
727731
objectTypeDecl =
728732
paramType->getNominalOrBoundGenericNominal();
729733
outOfLineOS << " alignas(";
730-
outOfLineSyntaxPrinter
731-
.printModuleNamespaceQualifiersIfNeeded(
732-
objectTypeDecl->getModuleContext(),
733-
ED->getModuleContext());
734-
outOfLineSyntaxPrinter.printBaseName(objectTypeDecl);
734+
outOfLineSyntaxPrinter.printNominalTypeReference(
735+
objectTypeDecl, ED->getModuleContext());
735736
outOfLineOS << ") unsigned char buffer[sizeof(";
736-
outOfLineSyntaxPrinter
737-
.printModuleNamespaceQualifiersIfNeeded(
738-
objectTypeDecl->getModuleContext(),
739-
ED->getModuleContext());
740-
outOfLineSyntaxPrinter.printBaseName(objectTypeDecl);
737+
outOfLineSyntaxPrinter.printNominalTypeReference(
738+
objectTypeDecl, ED->getModuleContext());
741739
outOfLineOS << ")];\n";
742740
outOfLineOS << " auto *valCopy = new(buffer) ";
743-
outOfLineSyntaxPrinter
744-
.printModuleNamespaceQualifiersIfNeeded(
745-
objectTypeDecl->getModuleContext(),
746-
ED->getModuleContext());
747-
outOfLineSyntaxPrinter.printBaseName(objectTypeDecl);
741+
outOfLineSyntaxPrinter.printNominalTypeReference(
742+
objectTypeDecl, ED->getModuleContext());
748743
outOfLineOS << "(val);\n";
749744
outOfLineOS << " ";
750745
outOfLineOS << cxx_synthesis::getCxxSwiftNamespaceName()
751746
<< "::";
752747
outOfLineOS << cxx_synthesis::getCxxImplNamespaceName();
753748
outOfLineOS << "::implClassFor<";
754-
outOfLineSyntaxPrinter
755-
.printModuleNamespaceQualifiersIfNeeded(
756-
objectTypeDecl->getModuleContext(),
757-
ED->getModuleContext());
758-
outOfLineSyntaxPrinter.printBaseName(objectTypeDecl);
749+
outOfLineSyntaxPrinter.printNominalTypeReference(
750+
objectTypeDecl, ED->getModuleContext());
759751
outOfLineOS << ">::type::initializeWithTake(result._"
760752
"getOpaquePointer(), ";
761753
outOfLineOS << cxx_synthesis::getCxxSwiftNamespaceName()
762754
<< "::";
763755
outOfLineOS << cxx_synthesis::getCxxImplNamespaceName();
764756
outOfLineOS << "::implClassFor<";
765-
outOfLineSyntaxPrinter
766-
.printModuleNamespaceQualifiersIfNeeded(
767-
objectTypeDecl->getModuleContext(),
768-
ED->getModuleContext());
769-
outOfLineSyntaxPrinter.printBaseName(objectTypeDecl);
757+
outOfLineSyntaxPrinter.printNominalTypeReference(
758+
objectTypeDecl, ED->getModuleContext());
770759
outOfLineOS << ">::type::getOpaquePointer(*valCopy)";
771760
outOfLineOS << ");\n";
772761
}
@@ -2914,9 +2903,6 @@ static bool isEnumExposableToCxx(const ValueDecl *VD,
29142903
if (auto *params = elementDecl->getParameterList()) {
29152904
for (const auto *param : *params) {
29162905
auto paramType = param->getInterfaceType();
2917-
// TODO: properly support exporting these optionals. rdar://131112273
2918-
if (paramType->isOptional() && paramType->getOptionalObjectType()->isTypeParameter())
2919-
return false;
29202906
if (DeclAndTypeClangFunctionPrinter::getTypeRepresentation(
29212907
printer.getTypeMapping(), printer.getInteropContext(),
29222908
printer, enumDecl->getModuleContext(), paramType)

lib/PrintAsClang/PrintClangValueType.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -622,7 +622,7 @@ void ClangValueTypePrinter::printTypeGenericTraits(
622622
os << "namespace swift SWIFT_PRIVATE_ATTR {\n";
623623

624624
if (typeDecl->hasClangNode()) {
625-
/// Print a reference to the type metadata fucntion for a C++ type.
625+
/// Print a reference to the type metadata function for a C++ type.
626626
ClangSyntaxPrinter(os).printNamespace(
627627
cxx_synthesis::getCxxImplNamespaceName(), [&](raw_ostream &os) {
628628
ClangSyntaxPrinter(os).printCTypeMetadataTypeFunction(
@@ -696,20 +696,22 @@ void ClangValueTypePrinter::printTypeGenericTraits(
696696
os << "> = true;\n";
697697
}
698698

699-
// FIXME: generic support.
700-
if (!typeDecl->hasClangNode() && typeMetadataFuncRequirements.empty()) {
701-
assert(NTD);
702-
os << "template<>\n";
699+
if (NTD) {
700+
if (printer.printNominalTypeOutsideMemberDeclTemplateSpecifiers(NTD))
701+
os << "template<>\n";
703702
os << "struct";
704703
declAndTypePrinter.printAvailability(os, typeDecl);
705704
os << " implClassFor<";
706705
printer.printBaseName(typeDecl->getModuleContext());
707706
os << "::";
708-
printer.printBaseName(typeDecl);
707+
printer.printNominalTypeReference(NTD, moduleContext);
709708
os << "> { using type = ";
710709
printer.printBaseName(typeDecl->getModuleContext());
711710
os << "::" << cxx_synthesis::getCxxImplNamespaceName() << "::";
712711
printCxxImplClassName(os, NTD);
712+
if (NTD->isGeneric())
713+
printer.printGenericSignatureParams(
714+
NTD->getGenericSignature().getCanonicalSignature());
713715
os << "; };\n";
714716
}
715717
os << "} // namespace\n";

test/Interop/SwiftToCxx/generics/generic-enum-execution.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,13 @@ int main() {
123123
// CHECK-NEXT: after some
124124
// CHECK-NEXT: destroy-TracksDeinit
125125
}
126+
{
127+
auto opt = swift::Optional<int>::some(14);
128+
auto x = GenericCustomType<int>::success(opt);
129+
auto y = x;
130+
assert(y.isSuccess());
131+
assert(y.getSuccess().getSome() == 14);
132+
}
126133
puts("EOF");
127134
// CHECK-NEXT: EOF
128135
return 0;

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %empty-directory(%t)
2-
// RUN: %target-swift-frontend %s -typecheck -module-name Generics -clang-header-expose-decls=all-public -emit-clang-header-path %t/generics.h
2+
// RUN: %target-swift-frontend %s -typecheck -module-name Generics -enable-experimental-cxx-interop -emit-clang-header-path %t/generics.h
33
// RUN: %FileCheck %s < %t/generics.h
44
// RUN: %check-interop-cxx-header-in-clang(%t/generics.h -Wno-reserved-identifier -DSWIFT_CXX_INTEROP_HIDE_STL_OVERLAY)
55

@@ -96,6 +96,16 @@ public func inoutConcreteOpt(_ x: inout GenericOpt<UInt16>) {
9696

9797
// CHECK: namespace Generics SWIFT_PRIVATE_ATTR SWIFT_SYMBOL_MODULE("Generics") {
9898

99+
// CHECK: template<class T_0_0>
100+
// CHECK-NEXT: #ifdef __cpp_concepts
101+
// CHECK-NEXT: requires swift::isUsableInGenericContext<T_0_0>
102+
// CHECK-NEXT: #endif
103+
// CHECK-NEXT: class SWIFT_SYMBOL("s:8Generics17GenericCustomTypeO") GenericCustomType;
104+
105+
// CHECK: static inline const constexpr bool isOpaqueLayout<Generics::GenericCustomType<T_0_0>> = true;
106+
107+
// CHECK: template<class T_0_0>
108+
99109
// CHECK: template<class T_0_0>
100110
// CHECK-NEXT: #ifdef __cpp_concepts
101111
// CHECK-NEXT: requires swift::isUsableInGenericContext<T_0_0>
@@ -218,6 +228,8 @@ public func inoutConcreteOpt(_ x: inout GenericOpt<UInt16>) {
218228
// CHECK-NEXT: _impl::$s8Generics14takeGenericOptyyAA0cD0OyxGlF(_impl::_impl_GenericOpt<T_0_0>::getOpaquePointer(x), swift::TypeMetadataTrait<T_0_0>::getTypeMetadata());
219229
// CHECK-NEXT: }
220230

231+
// CHECK: SWIFT_INLINE_THUNK bool GenericCustomType<T_0_0>::isFailure() const {
232+
221233
// CHECK: template<class T_0_0>
222234
// CHECK-NEXT: #ifdef __cpp_concepts
223235
// CHECK-NEXT: requires swift::isUsableInGenericContext<T_0_0>

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,11 @@ public func inoutConcretePair(_ x: UInt16, _ y: inout GenericPair<UInt16, UInt16
285285
// CHECK-NEXT: requires swift::isUsableInGenericContext<T_0_0> && swift::isUsableInGenericContext<T_0_1>
286286
// CHECK-NEXT: #endif // __cpp_concepts
287287
// CHECK-NEXT: static inline const constexpr bool isOpaqueLayout<Generics::GenericPair<T_0_0, T_0_1>> = true;
288+
// CHECK-NEXT: template<class T_0_0, class T_0_1>
289+
// CHECK-NEXT: #ifdef __cpp_concepts
290+
// CHECK-NEXT: requires swift::isUsableInGenericContext<T_0_0> && swift::isUsableInGenericContext<T_0_1>
291+
// CHECK-NEXT: #endif // __cpp_concepts
292+
// CHECK-NEXT: struct implClassFor<Generics::GenericPair<T_0_0, T_0_1>> { using type = Generics::_impl::_impl_GenericPair<T_0_0, T_0_1>; }
288293
// CHECK-NEXT: } // namespace
289294
// CHECK-NEXT: #pragma clang diagnostic pop
290295
// CHECK-NEXT: } // namespace swift

test/Interop/SwiftToCxx/stdlib/swift-stdlib-in-cxx.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
// CHECK: template<class T_0_0>
4747
// CHECK: template<class T_0_0>
4848

49+
// CHECK: template<class T_0_0>
4950
// CHECK: template<class T_0_0>
5051
// CHECK: template<class T_0_0>
5152
// CHECK-NEXT: #ifdef __cpp_concepts

0 commit comments

Comments
 (0)