[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:
Becca Royal-Gordon
2024-06-17 10:17:55 -07:00
parent 4fc0f3ab61
commit 7fa35d4d6a
4 changed files with 95 additions and 24 deletions

View File

@@ -102,18 +102,45 @@ struct CFunctionSignatureTypePrinterModifierDelegate {
class ClangTypeHandler {
public:
ClangTypeHandler(const clang::Decl *typeDecl) : typeDecl(typeDecl) {}
ClangTypeHandler(const clang::Decl *typeDecl)
: typeDecl(dyn_cast<clang::TagDecl>(typeDecl)) {}
bool isRepresentable() const {
// We can only return trivial types, or
// types that can be moved or copied.
if (auto *record = dyn_cast<clang::CXXRecordDecl>(typeDecl)) {
return record->isTrivial() || record->hasMoveConstructor() ||
record->hasCopyConstructorWithConstParam();
// We can only return tag types.
if (typeDecl) {
// We can return trivial types.
if (isTrivial(typeDecl))
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;
}
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 {
ClangSyntaxPrinter(os).printClangTypeReference(typeDecl);
}
@@ -133,7 +160,7 @@ public:
llvm::raw_string_ostream typeNameOS(fullQualifiedType);
printTypeName(typeNameOS);
llvm::raw_string_ostream unqualTypeNameOS(typeName);
unqualTypeNameOS << cast<clang::NamedDecl>(typeDecl)->getName();
unqualTypeNameOS << typeDecl->getName();
}
printReturnScaffold(typeDecl, os, fullQualifiedType, typeName,
bodyOfReturn);
@@ -141,7 +168,7 @@ public:
private:
static void
printReturnScaffold(const clang::Decl *typeDecl, raw_ostream &os,
printReturnScaffold(const clang::TagDecl *typeDecl, raw_ostream &os,
StringRef fullQualifiedType, StringRef typeName,
llvm::function_ref<void(StringRef)> bodyOfReturn) {
os << "alignas(alignof(" << fullQualifiedType << ")) char storage[sizeof("
@@ -150,7 +177,7 @@ private:
<< fullQualifiedType << " *>(storage);\n";
bodyOfReturn("storage");
os << ";\n";
if (typeDecl && cast<clang::CXXRecordDecl>(typeDecl)->isTrivial()) {
if (isTrivial(typeDecl)) {
// Trivial object can be just copied and not destroyed.
os << "return *storageObjectPtr;\n";
return;
@@ -162,7 +189,7 @@ private:
os << "return result;\n";
}
const clang::Decl *typeDecl;
const clang::TagDecl *typeDecl;
};
// Prints types in the C function signature that corresponds to the
@@ -371,6 +398,7 @@ public:
return ClangRepresentation::unsupported;
if (decl->hasClangNode()) {
assert(genericArgs.empty() && "this path doesn't support generic args");
ClangTypeHandler handler(decl->getClangDecl());
if (!handler.isRepresentable())
return ClangRepresentation::unsupported;