Skip to content

[cxx-interop][rebranch] Handle clang elaborated types properly #62190

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5659,6 +5659,8 @@ SwiftDeclConverter::getImplicitProperty(ImportedName importedName,
getAccessorPropertyType(getter, false, getterName.getSelfIndex());
if (propertyType.isNull())
return nullptr;
if (auto elaborated = dyn_cast<clang::ElaboratedType>(propertyType))
propertyType = elaborated->desugar();

// If there is a setter, check that the property it implies
// matches that of the getter.
Expand Down Expand Up @@ -7133,6 +7135,8 @@ canSkipOverTypedef(ClangImporter::Implementation &Impl,
return nullptr;

clang::QualType UnderlyingType = ClangTypedef->getUnderlyingType();
if (auto elaborated = dyn_cast<clang::ElaboratedType>(UnderlyingType))
UnderlyingType = elaborated->desugar();

// A typedef to a typedef should get imported as a typealias.
auto *TypedefT = UnderlyingType->getAs<clang::TypedefType>();
Expand Down Expand Up @@ -8456,6 +8460,8 @@ void ClangImporter::Implementation::loadAllMembersOfRecordDecl(
clang::QualType baseType = base.getType();
if (auto spectType = dyn_cast<clang::TemplateSpecializationType>(baseType))
baseType = spectType->desugar();
if (auto elaborated = dyn_cast<clang::ElaboratedType>(baseType))
baseType = elaborated->desugar();
if (!isa<clang::RecordType>(baseType))
continue;

Expand Down
16 changes: 12 additions & 4 deletions lib/ClangImporter/ImportEnumInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,12 @@ void EnumInfo::classifyEnum(const clang::EnumDecl *decl,
// name for the Swift type.
if (!decl->hasNameForLinkage()) {
// If this enum comes from a typedef, we can find a name.
if (!isa<clang::TypedefType>(decl->getIntegerType().getTypePtr()) ||
const clang::Type *underlyingType = getUnderlyingType(decl);
if (!isa<clang::TypedefType>(underlyingType) ||
// If the typedef is available in Swift, the user will get ambiguity.
// It also means they may not have intended this API to be imported like this.
!importer::isUnavailableInSwift(
cast<clang::TypedefType>(decl->getIntegerType().getTypePtr())->getDecl(),
cast<clang::TypedefType>(underlyingType)->getDecl(),
nullptr, true)) {
kind = EnumKind::Constants;
return;
Expand Down Expand Up @@ -241,6 +242,13 @@ StringRef importer::getCommonPluralPrefix(StringRef singular,
return commonPrefix;
}

const clang::Type *importer::getUnderlyingType(const clang::EnumDecl *decl) {
const clang::Type *underlyingType = decl->getIntegerType().getTypePtr();
if (auto elaborated = dyn_cast<clang::ElaboratedType>(underlyingType))
underlyingType = elaborated->desugar().getTypePtr();
return underlyingType;
}

/// Determine the prefix to be stripped from the names of the enum constants
/// within the given enum.
void EnumInfo::determineConstantNamePrefix(const clang::EnumDecl *decl) {
Expand Down Expand Up @@ -350,8 +358,8 @@ void EnumInfo::determineConstantNamePrefix(const clang::EnumDecl *decl) {
StringRef enumNameStr;
// If there's no name, this must be typedef. So use the typedef's name.
if (!decl->hasNameForLinkage()) {
auto typedefDecl = cast<clang::TypedefType>(
decl->getIntegerType().getTypePtr())->getDecl();
const clang::Type *underlyingType = getUnderlyingType(decl);
auto typedefDecl = cast<clang::TypedefType>(underlyingType)->getDecl();
enumNameStr = typedefDecl->getName();
} else {
enumNameStr = decl->getName();
Expand Down
4 changes: 4 additions & 0 deletions lib/ClangImporter/ImportEnumInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ StringRef getCommonWordPrefix(StringRef a, StringRef b,
///
/// \see getCommonWordPrefix
StringRef getCommonPluralPrefix(StringRef singular, StringRef plural);

/// Returns the underlying integer type of an enum. If clang treats the type as
/// an elaborated type, an unwrapped type is returned.
const clang::Type *getUnderlyingType(const clang::EnumDecl *decl);
}
}

Expand Down
4 changes: 2 additions & 2 deletions lib/ClangImporter/ImportName.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,7 @@ findSwiftNameAttr(const clang::Decl *decl, ImportNameVersion version) {

if (auto enumDecl = dyn_cast<clang::EnumDecl>(decl)) {
// Intentionally don't get the canonical type here.
if (auto typedefType = dyn_cast<clang::TypedefType>(enumDecl->getIntegerType().getTypePtr())) {
if (auto typedefType = dyn_cast<clang::TypedefType>(getUnderlyingType(enumDecl))) {
// If the typedef is available in Swift, the user will get ambiguity.
// It also means they may not have intended this API to be imported like this.
if (importer::isUnavailableInSwift(typedefType->getDecl(), nullptr, true)) {
Expand Down Expand Up @@ -1796,7 +1796,7 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
// typedef (even if it's an anonymous enum).
if (auto enumDecl = dyn_cast<clang::EnumDecl>(D)) {
// Intentionally don't get the canonical type here.
if (auto typedefType = dyn_cast<clang::TypedefType>(enumDecl->getIntegerType().getTypePtr())) {
if (auto typedefType = dyn_cast<clang::TypedefType>(getUnderlyingType(enumDecl))) {
// If the typedef is available in Swift, the user will get ambiguity.
// It also means they may not have intended this API to be imported like this.
if (importer::isUnavailableInSwift(typedefType->getDecl(), nullptr, true)) {
Expand Down
39 changes: 25 additions & 14 deletions lib/ClangImporter/ImportType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2086,18 +2086,22 @@ ImportedType ClangImporter::Implementation::importFunctionReturnType(
OptionalityOfReturn = OTK_ImplicitlyUnwrappedOptional;
}

clang::QualType returnType = clangDecl->getReturnType();
if (auto elaborated =
dyn_cast<clang::ElaboratedType>(returnType))
returnType = elaborated->desugar();

// Specialized templates need to match the args/result exactly (i.e.,
// ptr -> ptr not ptr -> Optional<ptr>).
if (clangDecl->getReturnType()->isPointerType() &&
clangDecl->getPrimaryTemplate() &&
if (returnType->isPointerType() && clangDecl->getPrimaryTemplate() &&
clangDecl
->getPrimaryTemplate()
->getAsFunction()
->getReturnType()
->isTemplateTypeParmType())
OptionalityOfReturn = OTK_None;

if (auto typedefType = dyn_cast<clang::TypedefType>(clangDecl->getReturnType().getTypePtr())) {
if (auto typedefType = dyn_cast<clang::TypedefType>(returnType)) {
if (isUnavailableInSwift(typedefType->getDecl())) {
if (auto clangEnum = findAnonymousEnumForTypedef(SwiftContext, typedefType)) {
// If this fails, it means that we need a stronger predicate for
Expand All @@ -2112,7 +2116,7 @@ ImportedType ClangImporter::Implementation::importFunctionReturnType(
}

// Import the result type.
return importType(clangDecl->getReturnType(),
return importType(returnType,
(isAuditedResult ? ImportTypeKind::AuditedResult
: ImportTypeKind::Result),
ImportDiagnosticAdder(*this, clangDecl,
Expand Down Expand Up @@ -2159,7 +2163,11 @@ ImportedType ClangImporter::Implementation::importFunctionParamsAndReturnType(
ImportedType importedType;
ImportDiagnosticAdder addDiag(*this, clangDecl,
clangDecl->getSourceRange().getBegin());
if (auto typedefType = dyn_cast<clang::TypedefType>(clangDecl->getReturnType().getTypePtr())) {
clang::QualType returnType = clangDecl->getReturnType();
if (auto elaborated = dyn_cast<clang::ElaboratedType>(returnType))
returnType = elaborated->desugar();

if (auto typedefType = dyn_cast<clang::TypedefType>(returnType)) {
if (isUnavailableInSwift(typedefType->getDecl())) {
if (auto clangEnum = findAnonymousEnumForTypedef(SwiftContext, typedefType)) {
// If this fails, it means that we need a stronger predicate for
Expand All @@ -2174,15 +2182,15 @@ ImportedType ClangImporter::Implementation::importFunctionParamsAndReturnType(
}

if (auto templateType =
dyn_cast<clang::TemplateTypeParmType>(clangDecl->getReturnType())) {
dyn_cast<clang::TemplateTypeParmType>(returnType)) {
importedType = {findGenericTypeInGenericDecls(
*this, templateType, genericParams,
getImportTypeAttrs(clangDecl), addDiag),
false};
} else if ((isa<clang::PointerType>(clangDecl->getReturnType()) ||
isa<clang::ReferenceType>(clangDecl->getReturnType())) &&
isa<clang::TemplateTypeParmType>(clangDecl->getReturnType()->getPointeeType())) {
auto pointeeType = clangDecl->getReturnType()->getPointeeType();
} else if ((isa<clang::PointerType>(returnType) ||
isa<clang::ReferenceType>(returnType)) &&
isa<clang::TemplateTypeParmType>(returnType->getPointeeType())) {
auto pointeeType = returnType->getPointeeType();
auto templateParamType = cast<clang::TemplateTypeParmType>(pointeeType);
PointerTypeKind pointerKind = pointeeType.getQualifiers().hasConst()
? PTK_UnsafePointer
Expand All @@ -2191,13 +2199,13 @@ ImportedType ClangImporter::Implementation::importFunctionParamsAndReturnType(
findGenericTypeInGenericDecls(*this, templateParamType, genericParams,
getImportTypeAttrs(clangDecl), addDiag);
importedType = {genericType->wrapInPointer(pointerKind), false};
} else if (!(isa<clang::RecordType>(clangDecl->getReturnType()) ||
isa<clang::TemplateSpecializationType>(clangDecl->getReturnType())) ||
} else if (!(isa<clang::RecordType>(returnType) ||
isa<clang::TemplateSpecializationType>(returnType)) ||
// TODO: we currently don't lazily load operator return types, but
// this should be trivial to add.
clangDecl->isOverloadedOperator() ||
// Dependant types are trivially mapped as Any.
clangDecl->getReturnType()->isDependentType()) {
returnType->isDependentType()) {
// If importedType is already initialized, it means we found the enum that
// was supposed to be used (instead of the typedef type).
if (!importedType) {
Expand Down Expand Up @@ -2244,6 +2252,8 @@ ClangImporter::Implementation::importParameterType(
ArrayRef<GenericTypeParamDecl *> genericParams,
llvm::function_ref<void(Diagnostic &&)> addImportDiagnosticFn) {
auto paramTy = param->getType();
if (auto elaborated = dyn_cast<clang::ElaboratedType>(paramTy))
paramTy = elaborated->desugar();

ImportTypeKind importKind = getImportTypeKindForParam(param);

Expand Down Expand Up @@ -2845,7 +2855,8 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType(
ImportDiagnosticAdder addImportDiag(*this, clangDecl,
clangDecl->getLocation());
clang::QualType resultType = clangDecl->getReturnType();

if (auto elaborated = dyn_cast<clang::ElaboratedType>(resultType))
resultType = elaborated->desugar();

ImportedType importedType;
if (auto typedefType = dyn_cast<clang::TypedefType>(resultType.getTypePtr())) {
Expand Down