Skip to content

[4.2] [Clang importer] Honor swift_bridged_typedef attribute. #16239

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
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
2 changes: 1 addition & 1 deletion lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2529,7 +2529,7 @@ namespace {
clang::QualType ClangType = Decl->getUnderlyingType();
SwiftType = Impl.importTypeIgnoreIUO(
ClangType, ImportTypeKind::Typedef, isInSystemModule(DC),
getTypedefBridgeability(ClangType), OTK_Optional);
getTypedefBridgeability(Decl, ClangType), OTK_Optional);
}

if (!SwiftType)
Expand Down
25 changes: 15 additions & 10 deletions lib/ClangImporter/ImportType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -663,12 +663,11 @@ namespace {
auto underlyingType = type->desugar();

// Figure out the bridgeability we would normally use for this typedef.
auto typedefBridgeability = getTypedefBridgeability(underlyingType);
auto typedefBridgeability =
getTypedefBridgeability(type->getDecl(), underlyingType);

// Figure out the typedef we should actually use.
auto underlyingBridgeability =
(Bridging == Bridgeability::Full
? typedefBridgeability : Bridgeability::None);
auto underlyingBridgeability = Bridging;
SwiftTypeConverter innerConverter(Impl, AllowNSUIntegerAsInt,
underlyingBridgeability);
auto underlyingResult = innerConverter.Visit(underlyingType);
Expand All @@ -685,7 +684,8 @@ namespace {
#ifndef NDEBUG
switch (underlyingResult.Hint) {
case ImportHint::Block:
// Blocks change in all sorts of ways, due to bridging.
case ImportHint::ObjCBridged:
// Bridging is fine for Objective-C and blocks.
break;
case ImportHint::NSUInteger:
// NSUInteger might be imported as Int rather than UInt depending
Expand Down Expand Up @@ -1088,7 +1088,6 @@ namespace {
static bool canBridgeTypes(ImportTypeKind importKind) {
switch (importKind) {
case ImportTypeKind::Abstract:
case ImportTypeKind::Typedef:
case ImportTypeKind::Value:
case ImportTypeKind::Variable:
case ImportTypeKind::AuditedVariable:
Expand All @@ -1104,6 +1103,7 @@ static bool canBridgeTypes(ImportTypeKind importKind) {
case ImportTypeKind::Property:
case ImportTypeKind::PropertyWithReferenceSemantics:
case ImportTypeKind::BridgedValue:
case ImportTypeKind::Typedef:
return true;
}

Expand Down Expand Up @@ -1286,7 +1286,7 @@ static ImportedType adjustTypeForConcreteImport(
// In a bridgeable context, or in the direct structure of a typedef,
// we would prefer to instead use the default Swift convention.
if (hint == ImportHint::Block) {
if (canBridgeTypes(importKind) || importKind == ImportTypeKind::Typedef) {
if (canBridgeTypes(importKind)) {
auto fTy = importedType->castTo<FunctionType>();
FunctionType::ExtInfo einfo = fTy->getExtInfo();
if (einfo.getRepresentation() != FunctionTypeRepresentation::Swift) {
Expand Down Expand Up @@ -1330,13 +1330,18 @@ static ImportedType adjustTypeForConcreteImport(
// bridge, do so.
if (hint == ImportHint::ObjCBridged &&
canBridgeTypes(importKind) &&
importKind != ImportTypeKind::PropertyWithReferenceSemantics) {
importKind != ImportTypeKind::PropertyWithReferenceSemantics &&
!(importKind == ImportTypeKind::Typedef &&
bridging == Bridgeability::None)) {
// id and Any can be bridged without Foundation. There would be
// bootstrapping issues with the ObjectiveC module otherwise.
if (hint.BridgedType->isAny()
|| impl.tryLoadFoundationModule()
|| impl.ImportForwardDeclarations) {
importedType = hint.BridgedType;

// Set the bridged type if it wasn't done already.
if (!importedType->isEqual(hint.BridgedType))
importedType = hint.BridgedType;
}
}

Expand Down Expand Up @@ -2484,7 +2489,7 @@ Type ClangImporter::Implementation::getSugaredTypeReference(TypeDecl *type) {
}

return NameAliasType::get(typealias, parentType, SubstitutionMap(),
typealias->getUnderlyingTypeLoc().getType());
typealias->getUnderlyingTypeLoc().getType());
}

return type->getDeclaredInterfaceType();
Expand Down
10 changes: 8 additions & 2 deletions lib/ClangImporter/ImporterImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,14 @@ enum class Bridgeability {
///
/// In either case we end up losing sugar at some uses sites, so this is more
/// about what the right default is.
static inline Bridgeability getTypedefBridgeability(clang::QualType type) {
return type->isBlockPointerType() ? Bridgeability::Full : Bridgeability::None;
static inline Bridgeability getTypedefBridgeability(
const clang::TypedefNameDecl *decl,
clang::QualType type) {
return decl->hasAttr<clang::SwiftBridgedTypedefAttr>()
? Bridgeability::Full
: type->isBlockPointerType()
? Bridgeability::Full
: Bridgeability::None;
}

/// \brief Describes the kind of the C type that can be mapped to a stdlib
Expand Down
8 changes: 8 additions & 0 deletions test/IDE/print_clang_decls.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
// RUN: %target-swift-ide-test(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -print-module -source-filename %s -module-to-print=nullability -function-definitions=false -prefer-type-repr=true > %t.printed.txt
// RUN: %FileCheck %s -check-prefix=CHECK-NULLABILITY -strict-whitespace < %t.printed.txt

// RUN: %target-swift-ide-test(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -print-module -source-filename %s -module-to-print=bridged_typedef -function-definitions=false -prefer-type-repr=true > %t.printed.txt
// RUN: %FileCheck %s -check-prefix=CHECK-BRIDGED-TYPEDEF -strict-whitespace < %t.printed.txt

// TAG_DECLS_AND_TYPEDEFS: {{^}}struct FooStruct1 {{{$}}
// TAG_DECLS_AND_TYPEDEFS: {{^}} var x: Int32{{$}}
// TAG_DECLS_AND_TYPEDEFS: {{^}} var y: Double{{$}}
Expand Down Expand Up @@ -153,3 +156,8 @@
// CHECK-NULLABILITY: func optArrayMethod() -> [Any]?
// CHECK-NULLABILITY: }
// CHECK-NULLABILITY: func compare_classes(_ sc1: SomeClass, _ sc2: SomeClass, _ sc3: SomeClass!)

// CHECK-BRIDGED-TYPEDEF: typealias NSMyAmazingStringAlias = String
// CHECK-BRIDGED-TYPEDEF: func acceptNSMyAmazingStringAlias(_ param: NSMyAmazingStringAlias?)
// CHECK-BRIDGED-TYPEDEF: func acceptNSMyAmazingStringAliasArray(_ param: [NSMyAmazingStringAlias])
// CHECK-BRIDGED-TYPEDEF: func acceptIndirectedAmazingAlias(_ param: AutoreleasingUnsafeMutablePointer<NSString>?)
13 changes: 13 additions & 0 deletions test/Inputs/clang-importer-sdk/usr/include/bridged_typedef.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef BRIDGED_TYPEDEF_H
#define BRIDGED_TYPEDEF_H

@import Foundation;


typedef NSString *NSMyAmazingStringAlias __attribute__((swift_bridged_typedef));

void acceptNSMyAmazingStringAlias(NSMyAmazingStringAlias _Nullable param);
void acceptNSMyAmazingStringAliasArray(NSArray<NSMyAmazingStringAlias> * _Nonnull param);
void acceptIndirectedAmazingAlias(NSMyAmazingStringAlias _Nonnull * _Nullable param);

#endif
5 changes: 5 additions & 0 deletions test/Inputs/clang-importer-sdk/usr/include/module.map
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,8 @@ module OtherSubscripts {
header "OtherSubscripts.h"
export *
}

module bridged_typedef {
header "bridged_typedef.h"
export *
}