Skip to content

Commit 7fa35d4

Browse files
committed
[PrintAsCxx] Fix printing of C++ enum args
Because imported enums are @objc, they were treated as unsupported in C++ and therefore ineligible to be printed in a C++ generated header. Narrow this logic so that only @objc *classes* are excluded, and update related printing logic to support enums correctly. Fixes rdar://124262637.
1 parent 4fc0f3a commit 7fa35d4

File tree

4 files changed

+95
-24
lines changed

4 files changed

+95
-24
lines changed

lib/AST/SwiftNameTranslation.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,6 @@ swift::cxx_translation::getNameForCxx(const ValueDecl *VD,
211211

212212
swift::cxx_translation::DeclRepresentation
213213
swift::cxx_translation::getDeclRepresentation(const ValueDecl *VD) {
214-
if (VD->isObjC())
215-
return {Unsupported, UnrepresentableObjC};
216214
if (getActorIsolation(const_cast<ValueDecl *>(VD)).isActorIsolated())
217215
return {Unsupported, UnrepresentableIsolatedInActor};
218216
if (isa<MacroDecl>(VD))
@@ -238,6 +236,8 @@ swift::cxx_translation::getDeclRepresentation(const ValueDecl *VD) {
238236
// Swift's consume semantics are not yet supported in C++.
239237
if (!typeDecl->canBeCopyable())
240238
return {Unsupported, UnrepresentableMoveOnly};
239+
if (isa<ClassDecl>(VD) && VD->isObjC())
240+
return {Unsupported, UnrepresentableObjC};
241241
if (typeDecl->isGeneric()) {
242242
if (isa<ClassDecl>(VD))
243243
return {Unsupported, UnrepresentableGeneric};

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2925,16 +2925,34 @@ static bool isEnumExposableToCxx(const ValueDecl *VD,
29252925
}
29262926

29272927
bool DeclAndTypePrinter::shouldInclude(const ValueDecl *VD) {
2928-
return !VD->isInvalid() && (!requiresExposedAttribute || hasExposeAttr(VD)) &&
2929-
(outputLang == OutputLanguageMode::Cxx
2930-
? cxx_translation::isVisibleToCxx(VD, minRequiredAccess) &&
2931-
isExposedToThisModule(M, VD, exposedModules) &&
2932-
cxx_translation::isExposableToCxx(VD) &&
2933-
isEnumExposableToCxx(VD, *this)
2934-
: isVisibleToObjC(VD, minRequiredAccess)) &&
2935-
!VD->getAttrs().hasAttribute<ImplementationOnlyAttr>() &&
2936-
!isAsyncAlternativeOfOtherDecl(VD) &&
2937-
!excludeForObjCImplementation(VD);
2928+
if (VD->isInvalid())
2929+
return false;
2930+
2931+
if (requiresExposedAttribute && !hasExposeAttr(VD))
2932+
return false;
2933+
2934+
if (!isVisible(VD))
2935+
return false;
2936+
2937+
if (outputLang == OutputLanguageMode::Cxx) {
2938+
if (!isExposedToThisModule(M, VD, exposedModules))
2939+
return false;
2940+
if (!cxx_translation::isExposableToCxx(VD))
2941+
return false;
2942+
if (!isEnumExposableToCxx(VD, *this))
2943+
return false;
2944+
}
2945+
2946+
if (VD->getAttrs().hasAttribute<ImplementationOnlyAttr>())
2947+
return false;
2948+
2949+
if (isAsyncAlternativeOfOtherDecl(VD))
2950+
return false;
2951+
2952+
if (excludeForObjCImplementation(VD))
2953+
return false;
2954+
2955+
return true;
29382956
}
29392957

29402958
bool DeclAndTypePrinter::isVisible(const ValueDecl *vd) const {

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -102,18 +102,45 @@ struct CFunctionSignatureTypePrinterModifierDelegate {
102102

103103
class ClangTypeHandler {
104104
public:
105-
ClangTypeHandler(const clang::Decl *typeDecl) : typeDecl(typeDecl) {}
105+
ClangTypeHandler(const clang::Decl *typeDecl)
106+
: typeDecl(dyn_cast<clang::TagDecl>(typeDecl)) {}
106107

107108
bool isRepresentable() const {
108-
// We can only return trivial types, or
109-
// types that can be moved or copied.
110-
if (auto *record = dyn_cast<clang::CXXRecordDecl>(typeDecl)) {
111-
return record->isTrivial() || record->hasMoveConstructor() ||
112-
record->hasCopyConstructorWithConstParam();
109+
// We can only return tag types.
110+
if (typeDecl) {
111+
// We can return trivial types.
112+
if (isTrivial(typeDecl))
113+
return true;
114+
115+
// We can return nontrivial types iff they can be moved or copied.
116+
if (auto *record = dyn_cast<clang::CXXRecordDecl>(typeDecl)) {
117+
return record->hasMoveConstructor() ||
118+
record->hasCopyConstructorWithConstParam();
119+
}
113120
}
121+
122+
// Otherwise, we can't return this type.
114123
return false;
115124
}
116125

126+
private:
127+
/// Is the tag type trivial?
128+
static bool isTrivial(const clang::TagDecl *typeDecl) {
129+
if (!typeDecl)
130+
return false;
131+
132+
if (auto *record = dyn_cast<clang::CXXRecordDecl>(typeDecl))
133+
return record->isTrivial();
134+
135+
// FIXME: If we can get plain clang::RecordDecls here, we need to figure out
136+
// how nontrivial (i.e. ARC) fields work.
137+
assert(!isa<clang::RecordDecl>(typeDecl));
138+
139+
// C-family enums are always trivial.
140+
return isa<clang::EnumDecl>(typeDecl);
141+
}
142+
143+
public:
117144
void printTypeName(raw_ostream &os) const {
118145
ClangSyntaxPrinter(os).printClangTypeReference(typeDecl);
119146
}
@@ -133,15 +160,15 @@ class ClangTypeHandler {
133160
llvm::raw_string_ostream typeNameOS(fullQualifiedType);
134161
printTypeName(typeNameOS);
135162
llvm::raw_string_ostream unqualTypeNameOS(typeName);
136-
unqualTypeNameOS << cast<clang::NamedDecl>(typeDecl)->getName();
163+
unqualTypeNameOS << typeDecl->getName();
137164
}
138165
printReturnScaffold(typeDecl, os, fullQualifiedType, typeName,
139166
bodyOfReturn);
140167
}
141168

142169
private:
143170
static void
144-
printReturnScaffold(const clang::Decl *typeDecl, raw_ostream &os,
171+
printReturnScaffold(const clang::TagDecl *typeDecl, raw_ostream &os,
145172
StringRef fullQualifiedType, StringRef typeName,
146173
llvm::function_ref<void(StringRef)> bodyOfReturn) {
147174
os << "alignas(alignof(" << fullQualifiedType << ")) char storage[sizeof("
@@ -150,7 +177,7 @@ class ClangTypeHandler {
150177
<< fullQualifiedType << " *>(storage);\n";
151178
bodyOfReturn("storage");
152179
os << ";\n";
153-
if (typeDecl && cast<clang::CXXRecordDecl>(typeDecl)->isTrivial()) {
180+
if (isTrivial(typeDecl)) {
154181
// Trivial object can be just copied and not destroyed.
155182
os << "return *storageObjectPtr;\n";
156183
return;
@@ -162,7 +189,7 @@ class ClangTypeHandler {
162189
os << "return result;\n";
163190
}
164191

165-
const clang::Decl *typeDecl;
192+
const clang::TagDecl *typeDecl;
166193
};
167194

168195
// Prints types in the C function signature that corresponds to the
@@ -371,6 +398,7 @@ class CFunctionSignatureTypePrinter
371398
return ClangRepresentation::unsupported;
372399

373400
if (decl->hasClangNode()) {
401+
assert(genericArgs.empty() && "this path doesn't support generic args");
374402
ClangTypeHandler handler(decl->getClangDecl());
375403
if (!handler.isRepresentable())
376404
return ClangRepresentation::unsupported;

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

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33

44
// RUN: %target-swift-frontend -typecheck %t/use-cxx-types.swift -typecheck -module-name UseCxxTy -emit-clang-header-path %t/UseCxxTy.h -I %t -enable-experimental-cxx-interop -clang-header-expose-decls=all-public -disable-availability-checking
55

6-
// RUN: %FileCheck %s < %t/UseCxxTy.h
6+
// RUN: %FileCheck %s --input-file %t/UseCxxTy.h
77

88
// RUN: %target-swift-frontend -typecheck %t/use-cxx-types.swift -typecheck -module-name UseCxxTy -emit-clang-header-path %t/UseCxxTyExposeOnly.h -I %t -enable-experimental-cxx-interop -clang-header-expose-decls=has-expose-attr -disable-availability-checking
99

10-
// RUN: %FileCheck %s < %t/UseCxxTyExposeOnly.h
10+
// RUN: %FileCheck %s --input-file %t/UseCxxTyExposeOnly.h
1111

1212
// FIXME: remove once https://github.com/apple/swift/pull/60971 lands.
1313
// RUN: echo "#include \"header.h\"" > %t/full-cxx-swift-cxx-bridging.h
@@ -91,6 +91,9 @@ using anonStructInNS = struct { float row; };
9191

9292
}
9393

94+
enum class SimpleScopedEnum { x = 0, y = 2 };
95+
typedef SimpleScopedEnum SimpleScopedEnumTypedef;
96+
9497
//--- module.modulemap
9598
module CxxTest {
9699
header "header.h"
@@ -130,6 +133,16 @@ public func retNonTrivialTypeAlias() -> ns.TypeAlias {
130133
return ns.TypeAlias()
131134
}
132135

136+
@_expose(Cxx)
137+
public func retSimpleScopedEnum() -> SimpleScopedEnum {
138+
return .x
139+
}
140+
141+
@_expose(Cxx)
142+
public func retSimpleScopedEnumTypedef() -> SimpleScopedEnumTypedef {
143+
return .x
144+
}
145+
133146
@_expose(Cxx)
134147
public func retSimpleTypedef() -> SimpleTypedef {
135148
return SimpleTypedef()
@@ -152,6 +165,10 @@ public func takeImmortalTemplate(_ x: ns.ImmortalCInt) {
152165
public func takeNonTrivial2(_ x: ns.NonTrivialTemplateTrivial) {
153166
}
154167

168+
@_expose(Cxx)
169+
public func takeSimpleScopedEnum(_ x: SimpleScopedEnum) {
170+
}
171+
155172
@_expose(Cxx)
156173
public func takeTrivial(_ x: Trivial) {
157174
}
@@ -275,6 +292,12 @@ public struct Strct {
275292

276293
// CHECK: ns::NonTrivialTemplate<ns::TrivialinNS> retNonTrivialTypeAlias() noexcept SWIFT_SYMBOL({{.*}}) SWIFT_WARN_UNUSED_RESULT {
277294

295+
// CHECK: SimpleScopedEnum retSimpleScopedEnum() noexcept SWIFT_SYMBOL({{.*}}) SWIFT_WARN_UNUSED_RESULT {
296+
297+
// FIXME: Would we prefer to print these with the typedef names?
298+
// CHECK: SimpleScopedEnum retSimpleScopedEnumTypedef() noexcept SWIFT_SYMBOL({{.*}}) SWIFT_WARN_UNUSED_RESULT {
299+
// CHECK: int32_t retSimpleTypedef() noexcept SWIFT_SYMBOL({{.*}}) SWIFT_WARN_UNUSED_RESULT {
300+
278301
// CHECK: SWIFT_INLINE_THUNK Trivial retTrivial() noexcept SWIFT_SYMBOL({{.*}}) SWIFT_WARN_UNUSED_RESULT {
279302
// CHECK-NEXT: alignas(alignof(Trivial)) char storage[sizeof(Trivial)];
280303
// CHECK-NEXT: auto * _Nonnull storageObjectPtr = reinterpret_cast<Trivial *>(storage);
@@ -294,6 +317,8 @@ public struct Strct {
294317
// CHECK-NEXT: _impl::$s8UseCxxTy15takeNonTrivial2yySo2nsO0037NonTrivialTemplateTrivialinNS_CsGGkdcVF(swift::_impl::getOpaquePointer(x));
295318
// CHECK-NEXT: }
296319

320+
// CHECK: SWIFT_INLINE_THUNK void takeSimpleScopedEnum(const SimpleScopedEnum& x) noexcept SWIFT_SYMBOL({{.*}}) {
321+
297322
// CHECK: SWIFT_INLINE_THUNK void takeTrivial(const Trivial& x) noexcept SWIFT_SYMBOL({{.*}}) {
298323
// CHECK-NEXT: _impl::$s8UseCxxTy11takeTrivialyySo0E0VF(_impl::swift_interop_passDirect_UseCxxTy_uint32_t_0_4(reinterpret_cast<const char *>(swift::_impl::getOpaquePointer(x))));
299324
// CHECK-NEXT: }

0 commit comments

Comments
 (0)