mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[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.
This commit is contained in:
@@ -211,8 +211,6 @@ swift::cxx_translation::getNameForCxx(const ValueDecl *VD,
|
|||||||
|
|
||||||
swift::cxx_translation::DeclRepresentation
|
swift::cxx_translation::DeclRepresentation
|
||||||
swift::cxx_translation::getDeclRepresentation(const ValueDecl *VD) {
|
swift::cxx_translation::getDeclRepresentation(const ValueDecl *VD) {
|
||||||
if (VD->isObjC())
|
|
||||||
return {Unsupported, UnrepresentableObjC};
|
|
||||||
if (getActorIsolation(const_cast<ValueDecl *>(VD)).isActorIsolated())
|
if (getActorIsolation(const_cast<ValueDecl *>(VD)).isActorIsolated())
|
||||||
return {Unsupported, UnrepresentableIsolatedInActor};
|
return {Unsupported, UnrepresentableIsolatedInActor};
|
||||||
if (isa<MacroDecl>(VD))
|
if (isa<MacroDecl>(VD))
|
||||||
@@ -238,6 +236,8 @@ swift::cxx_translation::getDeclRepresentation(const ValueDecl *VD) {
|
|||||||
// Swift's consume semantics are not yet supported in C++.
|
// Swift's consume semantics are not yet supported in C++.
|
||||||
if (!typeDecl->canBeCopyable())
|
if (!typeDecl->canBeCopyable())
|
||||||
return {Unsupported, UnrepresentableMoveOnly};
|
return {Unsupported, UnrepresentableMoveOnly};
|
||||||
|
if (isa<ClassDecl>(VD) && VD->isObjC())
|
||||||
|
return {Unsupported, UnrepresentableObjC};
|
||||||
if (typeDecl->isGeneric()) {
|
if (typeDecl->isGeneric()) {
|
||||||
if (isa<ClassDecl>(VD))
|
if (isa<ClassDecl>(VD))
|
||||||
return {Unsupported, UnrepresentableGeneric};
|
return {Unsupported, UnrepresentableGeneric};
|
||||||
|
|||||||
@@ -2925,16 +2925,34 @@ static bool isEnumExposableToCxx(const ValueDecl *VD,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool DeclAndTypePrinter::shouldInclude(const ValueDecl *VD) {
|
bool DeclAndTypePrinter::shouldInclude(const ValueDecl *VD) {
|
||||||
return !VD->isInvalid() && (!requiresExposedAttribute || hasExposeAttr(VD)) &&
|
if (VD->isInvalid())
|
||||||
(outputLang == OutputLanguageMode::Cxx
|
return false;
|
||||||
? cxx_translation::isVisibleToCxx(VD, minRequiredAccess) &&
|
|
||||||
isExposedToThisModule(M, VD, exposedModules) &&
|
if (requiresExposedAttribute && !hasExposeAttr(VD))
|
||||||
cxx_translation::isExposableToCxx(VD) &&
|
return false;
|
||||||
isEnumExposableToCxx(VD, *this)
|
|
||||||
: isVisibleToObjC(VD, minRequiredAccess)) &&
|
if (!isVisible(VD))
|
||||||
!VD->getAttrs().hasAttribute<ImplementationOnlyAttr>() &&
|
return false;
|
||||||
!isAsyncAlternativeOfOtherDecl(VD) &&
|
|
||||||
!excludeForObjCImplementation(VD);
|
if (outputLang == OutputLanguageMode::Cxx) {
|
||||||
|
if (!isExposedToThisModule(M, VD, exposedModules))
|
||||||
|
return false;
|
||||||
|
if (!cxx_translation::isExposableToCxx(VD))
|
||||||
|
return false;
|
||||||
|
if (!isEnumExposableToCxx(VD, *this))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VD->getAttrs().hasAttribute<ImplementationOnlyAttr>())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (isAsyncAlternativeOfOtherDecl(VD))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (excludeForObjCImplementation(VD))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeclAndTypePrinter::isVisible(const ValueDecl *vd) const {
|
bool DeclAndTypePrinter::isVisible(const ValueDecl *vd) const {
|
||||||
|
|||||||
@@ -102,18 +102,45 @@ struct CFunctionSignatureTypePrinterModifierDelegate {
|
|||||||
|
|
||||||
class ClangTypeHandler {
|
class ClangTypeHandler {
|
||||||
public:
|
public:
|
||||||
ClangTypeHandler(const clang::Decl *typeDecl) : typeDecl(typeDecl) {}
|
ClangTypeHandler(const clang::Decl *typeDecl)
|
||||||
|
: typeDecl(dyn_cast<clang::TagDecl>(typeDecl)) {}
|
||||||
|
|
||||||
bool isRepresentable() const {
|
bool isRepresentable() const {
|
||||||
// We can only return trivial types, or
|
// We can only return tag types.
|
||||||
// types that can be moved or copied.
|
if (typeDecl) {
|
||||||
if (auto *record = dyn_cast<clang::CXXRecordDecl>(typeDecl)) {
|
// We can return trivial types.
|
||||||
return record->isTrivial() || record->hasMoveConstructor() ||
|
if (isTrivial(typeDecl))
|
||||||
record->hasCopyConstructorWithConstParam();
|
return true;
|
||||||
|
|
||||||
|
// We can return nontrivial types iff they can be moved or copied.
|
||||||
|
if (auto *record = dyn_cast<clang::CXXRecordDecl>(typeDecl)) {
|
||||||
|
return record->hasMoveConstructor() ||
|
||||||
|
record->hasCopyConstructorWithConstParam();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Otherwise, we can't return this type.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Is the tag type trivial?
|
||||||
|
static bool isTrivial(const clang::TagDecl *typeDecl) {
|
||||||
|
if (!typeDecl)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (auto *record = dyn_cast<clang::CXXRecordDecl>(typeDecl))
|
||||||
|
return record->isTrivial();
|
||||||
|
|
||||||
|
// FIXME: If we can get plain clang::RecordDecls here, we need to figure out
|
||||||
|
// how nontrivial (i.e. ARC) fields work.
|
||||||
|
assert(!isa<clang::RecordDecl>(typeDecl));
|
||||||
|
|
||||||
|
// C-family enums are always trivial.
|
||||||
|
return isa<clang::EnumDecl>(typeDecl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
void printTypeName(raw_ostream &os) const {
|
void printTypeName(raw_ostream &os) const {
|
||||||
ClangSyntaxPrinter(os).printClangTypeReference(typeDecl);
|
ClangSyntaxPrinter(os).printClangTypeReference(typeDecl);
|
||||||
}
|
}
|
||||||
@@ -133,7 +160,7 @@ public:
|
|||||||
llvm::raw_string_ostream typeNameOS(fullQualifiedType);
|
llvm::raw_string_ostream typeNameOS(fullQualifiedType);
|
||||||
printTypeName(typeNameOS);
|
printTypeName(typeNameOS);
|
||||||
llvm::raw_string_ostream unqualTypeNameOS(typeName);
|
llvm::raw_string_ostream unqualTypeNameOS(typeName);
|
||||||
unqualTypeNameOS << cast<clang::NamedDecl>(typeDecl)->getName();
|
unqualTypeNameOS << typeDecl->getName();
|
||||||
}
|
}
|
||||||
printReturnScaffold(typeDecl, os, fullQualifiedType, typeName,
|
printReturnScaffold(typeDecl, os, fullQualifiedType, typeName,
|
||||||
bodyOfReturn);
|
bodyOfReturn);
|
||||||
@@ -141,7 +168,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static void
|
static void
|
||||||
printReturnScaffold(const clang::Decl *typeDecl, raw_ostream &os,
|
printReturnScaffold(const clang::TagDecl *typeDecl, raw_ostream &os,
|
||||||
StringRef fullQualifiedType, StringRef typeName,
|
StringRef fullQualifiedType, StringRef typeName,
|
||||||
llvm::function_ref<void(StringRef)> bodyOfReturn) {
|
llvm::function_ref<void(StringRef)> bodyOfReturn) {
|
||||||
os << "alignas(alignof(" << fullQualifiedType << ")) char storage[sizeof("
|
os << "alignas(alignof(" << fullQualifiedType << ")) char storage[sizeof("
|
||||||
@@ -150,7 +177,7 @@ private:
|
|||||||
<< fullQualifiedType << " *>(storage);\n";
|
<< fullQualifiedType << " *>(storage);\n";
|
||||||
bodyOfReturn("storage");
|
bodyOfReturn("storage");
|
||||||
os << ";\n";
|
os << ";\n";
|
||||||
if (typeDecl && cast<clang::CXXRecordDecl>(typeDecl)->isTrivial()) {
|
if (isTrivial(typeDecl)) {
|
||||||
// Trivial object can be just copied and not destroyed.
|
// Trivial object can be just copied and not destroyed.
|
||||||
os << "return *storageObjectPtr;\n";
|
os << "return *storageObjectPtr;\n";
|
||||||
return;
|
return;
|
||||||
@@ -162,7 +189,7 @@ private:
|
|||||||
os << "return result;\n";
|
os << "return result;\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
const clang::Decl *typeDecl;
|
const clang::TagDecl *typeDecl;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Prints types in the C function signature that corresponds to the
|
// Prints types in the C function signature that corresponds to the
|
||||||
@@ -371,6 +398,7 @@ public:
|
|||||||
return ClangRepresentation::unsupported;
|
return ClangRepresentation::unsupported;
|
||||||
|
|
||||||
if (decl->hasClangNode()) {
|
if (decl->hasClangNode()) {
|
||||||
|
assert(genericArgs.empty() && "this path doesn't support generic args");
|
||||||
ClangTypeHandler handler(decl->getClangDecl());
|
ClangTypeHandler handler(decl->getClangDecl());
|
||||||
if (!handler.isRepresentable())
|
if (!handler.isRepresentable())
|
||||||
return ClangRepresentation::unsupported;
|
return ClangRepresentation::unsupported;
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
|
|
||||||
// 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
|
// 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
|
||||||
|
|
||||||
// RUN: %FileCheck %s < %t/UseCxxTy.h
|
// RUN: %FileCheck %s --input-file %t/UseCxxTy.h
|
||||||
|
|
||||||
// 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
|
// 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
|
||||||
|
|
||||||
// RUN: %FileCheck %s < %t/UseCxxTyExposeOnly.h
|
// RUN: %FileCheck %s --input-file %t/UseCxxTyExposeOnly.h
|
||||||
|
|
||||||
// FIXME: remove once https://github.com/apple/swift/pull/60971 lands.
|
// FIXME: remove once https://github.com/apple/swift/pull/60971 lands.
|
||||||
// RUN: echo "#include \"header.h\"" > %t/full-cxx-swift-cxx-bridging.h
|
// RUN: echo "#include \"header.h\"" > %t/full-cxx-swift-cxx-bridging.h
|
||||||
@@ -91,6 +91,9 @@ using anonStructInNS = struct { float row; };
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class SimpleScopedEnum { x = 0, y = 2 };
|
||||||
|
typedef SimpleScopedEnum SimpleScopedEnumTypedef;
|
||||||
|
|
||||||
//--- module.modulemap
|
//--- module.modulemap
|
||||||
module CxxTest {
|
module CxxTest {
|
||||||
header "header.h"
|
header "header.h"
|
||||||
@@ -130,6 +133,16 @@ public func retNonTrivialTypeAlias() -> ns.TypeAlias {
|
|||||||
return ns.TypeAlias()
|
return ns.TypeAlias()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@_expose(Cxx)
|
||||||
|
public func retSimpleScopedEnum() -> SimpleScopedEnum {
|
||||||
|
return .x
|
||||||
|
}
|
||||||
|
|
||||||
|
@_expose(Cxx)
|
||||||
|
public func retSimpleScopedEnumTypedef() -> SimpleScopedEnumTypedef {
|
||||||
|
return .x
|
||||||
|
}
|
||||||
|
|
||||||
@_expose(Cxx)
|
@_expose(Cxx)
|
||||||
public func retSimpleTypedef() -> SimpleTypedef {
|
public func retSimpleTypedef() -> SimpleTypedef {
|
||||||
return SimpleTypedef()
|
return SimpleTypedef()
|
||||||
@@ -152,6 +165,10 @@ public func takeImmortalTemplate(_ x: ns.ImmortalCInt) {
|
|||||||
public func takeNonTrivial2(_ x: ns.NonTrivialTemplateTrivial) {
|
public func takeNonTrivial2(_ x: ns.NonTrivialTemplateTrivial) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@_expose(Cxx)
|
||||||
|
public func takeSimpleScopedEnum(_ x: SimpleScopedEnum) {
|
||||||
|
}
|
||||||
|
|
||||||
@_expose(Cxx)
|
@_expose(Cxx)
|
||||||
public func takeTrivial(_ x: Trivial) {
|
public func takeTrivial(_ x: Trivial) {
|
||||||
}
|
}
|
||||||
@@ -275,6 +292,12 @@ public struct Strct {
|
|||||||
|
|
||||||
// CHECK: ns::NonTrivialTemplate<ns::TrivialinNS> retNonTrivialTypeAlias() noexcept SWIFT_SYMBOL({{.*}}) SWIFT_WARN_UNUSED_RESULT {
|
// CHECK: ns::NonTrivialTemplate<ns::TrivialinNS> retNonTrivialTypeAlias() noexcept SWIFT_SYMBOL({{.*}}) SWIFT_WARN_UNUSED_RESULT {
|
||||||
|
|
||||||
|
// CHECK: SimpleScopedEnum retSimpleScopedEnum() noexcept SWIFT_SYMBOL({{.*}}) SWIFT_WARN_UNUSED_RESULT {
|
||||||
|
|
||||||
|
// FIXME: Would we prefer to print these with the typedef names?
|
||||||
|
// CHECK: SimpleScopedEnum retSimpleScopedEnumTypedef() noexcept SWIFT_SYMBOL({{.*}}) SWIFT_WARN_UNUSED_RESULT {
|
||||||
|
// CHECK: int32_t retSimpleTypedef() noexcept SWIFT_SYMBOL({{.*}}) SWIFT_WARN_UNUSED_RESULT {
|
||||||
|
|
||||||
// CHECK: SWIFT_INLINE_THUNK Trivial retTrivial() noexcept SWIFT_SYMBOL({{.*}}) SWIFT_WARN_UNUSED_RESULT {
|
// CHECK: SWIFT_INLINE_THUNK Trivial retTrivial() noexcept SWIFT_SYMBOL({{.*}}) SWIFT_WARN_UNUSED_RESULT {
|
||||||
// CHECK-NEXT: alignas(alignof(Trivial)) char storage[sizeof(Trivial)];
|
// CHECK-NEXT: alignas(alignof(Trivial)) char storage[sizeof(Trivial)];
|
||||||
// CHECK-NEXT: auto * _Nonnull storageObjectPtr = reinterpret_cast<Trivial *>(storage);
|
// CHECK-NEXT: auto * _Nonnull storageObjectPtr = reinterpret_cast<Trivial *>(storage);
|
||||||
@@ -294,6 +317,8 @@ public struct Strct {
|
|||||||
// CHECK-NEXT: _impl::$s8UseCxxTy15takeNonTrivial2yySo2nsO0037NonTrivialTemplateTrivialinNS_CsGGkdcVF(swift::_impl::getOpaquePointer(x));
|
// CHECK-NEXT: _impl::$s8UseCxxTy15takeNonTrivial2yySo2nsO0037NonTrivialTemplateTrivialinNS_CsGGkdcVF(swift::_impl::getOpaquePointer(x));
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
|
|
||||||
|
// CHECK: SWIFT_INLINE_THUNK void takeSimpleScopedEnum(const SimpleScopedEnum& x) noexcept SWIFT_SYMBOL({{.*}}) {
|
||||||
|
|
||||||
// CHECK: SWIFT_INLINE_THUNK void takeTrivial(const Trivial& x) noexcept SWIFT_SYMBOL({{.*}}) {
|
// CHECK: SWIFT_INLINE_THUNK void takeTrivial(const Trivial& x) noexcept SWIFT_SYMBOL({{.*}}) {
|
||||||
// CHECK-NEXT: _impl::$s8UseCxxTy11takeTrivialyySo0E0VF(_impl::swift_interop_passDirect_UseCxxTy_uint32_t_0_4(reinterpret_cast<const char *>(swift::_impl::getOpaquePointer(x))));
|
// CHECK-NEXT: _impl::$s8UseCxxTy11takeTrivialyySo0E0VF(_impl::swift_interop_passDirect_UseCxxTy_uint32_t_0_4(reinterpret_cast<const char *>(swift::_impl::getOpaquePointer(x))));
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
|
|||||||
Reference in New Issue
Block a user