Skip to content

Commit 803b537

Browse files
author
Gabor Horvath
committed
[cxx-interop] Fix crashing on recursive enums
Introduce a cache that helps cutting the recursion when we process a type that we already visited before but did not finish processing yet. Fixes #85361 rdar://164153038
1 parent 3dcd9bb commit 803b537

File tree

3 files changed

+28
-2
lines changed

3 files changed

+28
-2
lines changed

lib/PrintAsClang/DeclAndTypePrinter.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515

1616
#include "OutputLanguageMode.h"
1717

18+
#include "PrintClangFunction.h"
1819
#include "swift/AST/Decl.h"
1920
#include "swift/AST/Module.h"
2021
#include "swift/AST/Type.h"
2122
// for OptionalTypeKind
23+
#include "swift/AST/TypeRepr.h"
2224
#include "swift/ClangImporter/ClangImporter.h"
2325
#include "llvm/ADT/StringSet.h"
2426

@@ -56,6 +58,7 @@ class DeclAndTypePrinter {
5658
private:
5759
class Implementation;
5860
friend class Implementation;
61+
friend class DeclAndTypeClangFunctionPrinter;
5962

6063
ModuleDecl &M;
6164
raw_ostream &os;
@@ -69,6 +72,7 @@ class DeclAndTypePrinter {
6972
bool requiresExposedAttribute;
7073
llvm::StringSet<> &exposedModules;
7174
OutputLanguageMode outputLang;
75+
llvm::DenseMap<Type, std::optional<ClangRepresentation>> typeRepresentations;
7276

7377
/// The name 'CFTypeRef'.
7478
///

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1895,13 +1895,27 @@ ClangRepresentation DeclAndTypeClangFunctionPrinter::getTypeRepresentation(
18951895
PrimitiveTypeMapping &typeMapping,
18961896
SwiftToClangInteropContext &interopContext, DeclAndTypePrinter &declPrinter,
18971897
const ModuleDecl *emittedModule, Type ty) {
1898+
auto [it, inserted] = declPrinter.typeRepresentations.try_emplace(ty);
1899+
// If we already seen the type but do not have a representation yet assume
1900+
// representable for now. This can happen for recursive types like:
1901+
//
1902+
// public enum E {
1903+
// case foo([E?])
1904+
// }
1905+
//
1906+
// We make a decision about these types when the function that first
1907+
// encountered them returns.
1908+
if (!inserted)
1909+
return it->second ? (*it->second) : ClangRepresentation::representable;
18981910
CFunctionSignatureTypePrinterModifierDelegate delegate;
18991911
CFunctionSignatureTypePrinter typePrinter(
19001912
llvm::nulls(), llvm::nulls(), typeMapping, OutputLanguageMode::Cxx,
19011913
interopContext, delegate, emittedModule, declPrinter,
19021914
FunctionSignatureTypeUse::TypeReference);
1903-
return typePrinter.visit(ty, OptionalTypeKind::OTK_None,
1904-
/*isInOutParam=*/false);
1915+
auto result = typePrinter.visit(ty, OptionalTypeKind::OTK_None,
1916+
/*isInOutParam=*/false);
1917+
declPrinter.typeRepresentations[ty] = result;
1918+
return result;
19051919
}
19061920

19071921
void DeclAndTypeClangFunctionPrinter::printTypeName(
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend %s -module-name Enums -clang-header-expose-decls=all-public -typecheck -verify -emit-clang-header-path %t/enums.h
3+
4+
// RUN: %check-interop-cxx-header-in-clang(%t/enums.h -Wno-unused-private-field -Wno-unused-function -DSWIFT_CXX_INTEROP_HIDE_STL_OVERLAY)
5+
6+
public enum E {
7+
case foo([E?])
8+
}

0 commit comments

Comments
 (0)