Skip to content

Commit 85ccbb4

Browse files
committed
[ClangImporter] Bridging can happen even without full bridgeability
Partially reverts f4f8349 (from July!) which caused us to start importing global blocks with unbridged parameters, breaking source compatibility. I'm still investigating whether there's an actual hole in the logic; see next few commits. rdar://problem/34913634
1 parent a59af98 commit 85ccbb4

File tree

9 files changed

+99
-19
lines changed

9 files changed

+99
-19
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3476,6 +3476,8 @@ namespace {
34763476
Impl.CurrentVersion))
34773477
declType = Impl.getClangASTContext().getTypedefType(newtypeDecl);
34783478

3479+
// Note that we deliberately don't bridge most globals because we want to
3480+
// preserve pointer identity.
34793481
Type type = Impl.importType(declType,
34803482
(isAudited ? ImportTypeKind::AuditedVariable
34813483
: ImportTypeKind::Variable),

lib/ClangImporter/ImportType.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1313,7 +1313,7 @@ static Type adjustTypeForConcreteImport(ClangImporter::Implementation &impl,
13131313
}
13141314
}
13151315

1316-
if (bridging == Bridgeability::Full) {
1316+
if (canBridgeTypes(importKind) || importKind == ImportTypeKind::Typedef) {
13171317
auto fTy = importedType->castTo<FunctionType>();
13181318
FunctionType::ExtInfo einfo = fTy->getExtInfo();
13191319
if (einfo.getRepresentation() != FunctionTypeRepresentation::Swift) {
@@ -1356,7 +1356,6 @@ static Type adjustTypeForConcreteImport(ClangImporter::Implementation &impl,
13561356
// If we have a bridged Objective-C type and we are allowed to
13571357
// bridge, do so.
13581358
if (hint == ImportHint::ObjCBridged &&
1359-
bridging == Bridgeability::Full &&
13601359
canBridgeTypes(importKind) &&
13611360
importKind != ImportTypeKind::PropertyWithReferenceSemantics) {
13621361
// id and Any can be bridged without Foundation. There would be

lib/ClangImporter/ImporterImpl.h

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -907,22 +907,45 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
907907
///
908908
/// \param type The Clang type to import.
909909
///
910-
/// \param kind The kind of type import we're performing.
910+
/// \param kind A classification of the immediate context in which this type
911+
/// will be used. Different contexts result in the type being imported
912+
/// differently; for example, CF types are normally considered Unmanaged,
913+
/// but in parameter position they are known to always be passed at +0.
914+
/// See also the \p topLevelBridgeability parameter.
911915
///
912916
/// \param allowNSUIntegerAsInt If true, NSUInteger will be imported as Int
913-
/// in certain contexts. If false, it will always be imported as UInt.
914-
///
915-
/// \param bridgeability Whether we can bridge types in this context.
916-
/// This may restrict the ability to bridge types even in contexts
917-
/// that otherwise allow bridging, such as function results and
918-
/// parameters.
917+
/// in certain contexts. If false, it will always be imported as UInt.
918+
///
919+
/// \param topLevelBridgeability A classification of the top-level context in
920+
/// which this type will be used. This and \p kind are used together to
921+
/// determine whether a type can be imported in a more Swifty way than
922+
/// a naive translation of its C type. Full bridgeability requires that SIL
923+
/// can get back to the original Clang type if it needs to, which implies
924+
/// that this type is part of a top-level declaration where we do bridging.
925+
/// Without full bridgeability, we can still do some Swifty importing (e.g.
926+
/// mapping NSString to String) if we're in an immediate context \p kind
927+
/// that allows bridging, but only in cases where Swift's default mapping
928+
/// "back" to C is the correct one. If the original type has something
929+
/// funny going on, we either have to use a less lossy version of the type
930+
/// (ObjCBool rather than Bool) or refuse to import it at all (a block with
931+
/// the \c ns_returns_retained attribute).
932+
///
933+
/// \param optional If the imported type was a pointer-like type in C, this
934+
/// optionality is applied to the resulting Swift type.
935+
///
936+
/// \param resugarNSErrorPointer If true, Objective-C's `NSError **` is
937+
/// imported as Foundation.NSErrorPointer rather than
938+
/// AutoreleasingUnsafeMutablePointer<...>. This is usually desirable
939+
/// behavior, but isn't necessary when we use Swift's \c throws anyway.
940+
/// Strictly speaking, though, this is a hack used to break cyclic
941+
/// dependencies.
919942
///
920943
/// \returns The imported type, or null if this type could
921-
/// not be represented in Swift.
944+
/// not be represented in Swift.
922945
Type importType(clang::QualType type,
923946
ImportTypeKind kind,
924947
bool allowNSUIntegerAsInt,
925-
Bridgeability bridgeability,
948+
Bridgeability topLevelBridgeability,
926949
OptionalTypeKind optional = OTK_ImplicitlyUnwrappedOptional,
927950
bool resugarNSErrorPointer = true);
928951

test/ClangImporter/objc_id_as_any.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ idLover.takesArray(ofId: &y) // expected-error{{argument type 'Any' does not con
2525
idLover.takesId(x)
2626
idLover.takesId(y)
2727

28-
install_global_event_handler(idLover) // expected-error {{cannot convert value of type 'NSIdLover' to expected argument type 'event_handler?' (aka 'Optional<@convention(c) (AnyObject) -> ()>')}}
28+
install_global_event_handler(idLover) // expected-error {{cannot convert value of type 'NSIdLover' to expected argument type 'event_handler?' (aka 'Optional<@convention(c) (Any) -> ()>')}}
2929

3030
// FIXME: this should not type-check!
3131
// Function conversions are not legal when converting to a thin function type.

test/IDE/print_clang_bool_bridging.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@ func testCBoolFnToBlockTypedef(_: @escaping CBoolFn) -> CBoolBlock
4242
func testObjCBoolFnToBlockTypedef(_: @escaping ObjCBoolFn) -> ObjCBoolBlock
4343
func testDarwinBooleanFnToBlockTypedef(_: @escaping DarwinBooleanFn) -> DarwinBooleanBlock
4444

45-
typealias CBoolFnToBlockType = (CBoolFn) -> CBoolBlock
46-
typealias ObjCBoolFnToBlockType = (ObjCBoolFn) -> ObjCBoolBlock
47-
typealias DarwinBooleanFnToBlockType = (DarwinBooleanFn) -> DarwinBooleanBlock
45+
typealias CBoolFnToBlockType = (CBoolFn) -> (Bool) -> Bool
46+
typealias ObjCBoolFnToBlockType = (ObjCBoolFn) -> (ObjCBool) -> ObjCBool
47+
typealias DarwinBooleanFnToBlockType = (DarwinBooleanFn) -> (DarwinBoolean) -> DarwinBoolean
4848

49-
var globalObjCBoolFnToBlockFP: @convention(c) (ObjCBoolFn) -> @convention(block) (ObjCBool) -> ObjCBool
50-
var globalObjCBoolFnToBlockFPP: UnsafeMutablePointer<@convention(c) (ObjCBoolFn) -> @convention(block) (ObjCBool) -> ObjCBool>?
51-
var globalObjCBoolFnToBlockBP: @convention(block) (ObjCBoolFn) -> @convention(block) (ObjCBool) -> ObjCBool
49+
var globalObjCBoolFnToBlockFP: @convention(c) (ObjCBoolFn) -> (ObjCBool) -> ObjCBool
50+
var globalObjCBoolFnToBlockFPP: UnsafeMutablePointer<@convention(c) (ObjCBoolFn) -> (ObjCBool) -> ObjCBool>?
51+
var globalObjCBoolFnToBlockBP: @convention(block) (ObjCBoolFn) -> (ObjCBool) -> ObjCBool
5252

5353
var globalCBoolFn: CBoolFn
5454
var globalObjCBoolFn: ObjCBoolFn

test/IDE/print_omit_needless_words.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@
143143
// CHECK-FOUNDATION: func doSomethingElse(with: NSCopying & NSObjectProtocol)
144144

145145
// Note: Function type -> "Function".
146-
// CHECK-FOUNDATION: func sort(_: @escaping @convention(c) (AnyObject, AnyObject) -> Int)
146+
// CHECK-FOUNDATION: func sort(_: @escaping @convention(c) (Any, Any) -> Int)
147147

148148
// Note: Plural: NSArray without type arguments -> "Objects".
149149
// CHECK-FOUNDATION: func remove(_: [Any])
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#import <Foundation/Foundation.h>
2+
3+
extern NSString * _Nonnull (^ _Nonnull mutableBlockGlobal)(NSString * _Nonnull);
4+
extern NSString * _Nonnull (^ _Nonnull const constBlockGlobal)(NSString * _Nonnull);
5+
6+
extern NSString * _Nonnull (* _Nonnull mutableFPGlobal)(NSString * _Nonnull);
7+
extern NSString * _Nonnull (* _Nonnull const constFPGlobal)(NSString * _Nonnull);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#import "BlockGlobals.h"
2+
3+
NSString *(^mutableBlockGlobal)(NSString *) = ^ NSString *(NSString *arg) {
4+
return [@"default mutable block: " stringByAppendingString: arg];
5+
};
6+
NSString *(^ const constBlockGlobal)(NSString *) = ^ NSString *(NSString *arg) {
7+
return [@"default const block: " stringByAppendingString: arg];
8+
};
9+
10+
static NSString *appendToDefault(NSString *arg) {
11+
return [@"default mutable FP: " stringByAppendingString: arg];
12+
}
13+
14+
NSString *(*mutableFPGlobal)(NSString *) = &appendToDefault;
15+
16+
17+
static NSString *appendToDefaultConst(NSString *arg) {
18+
return [@"default const FP: " stringByAppendingString: arg];
19+
}
20+
NSString *(* const constFPGlobal)(NSString *) = &appendToDefaultConst;
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-clang -fobjc-arc %S/Inputs/BlockGlobals/BlockGlobals.m -c -o %t/BlockGlobals.o
4+
// RUN: %target-build-swift %s -import-objc-header %S/Inputs/BlockGlobals/BlockGlobals.h %t/BlockGlobals.o -o %t/main
5+
// RUN: %target-run %t/main
6+
7+
// REQUIRES: executable_test
8+
// REQUIRES: objc_interop
9+
10+
import Foundation
11+
import StdlibUnittest
12+
13+
var BlockGlobalsTestSuite = TestSuite("BlockGlobals")
14+
15+
BlockGlobalsTestSuite.test("const block") {
16+
expectEqual((@convention(block) (String) -> String).self as Any.Type, type(of: constBlockGlobal))
17+
expectEqual("default const block: abc", constBlockGlobal("abc"))
18+
}
19+
20+
BlockGlobalsTestSuite.test("const function pointer") {
21+
expectEqual((@convention(c) (String) -> String).self as Any.Type, type(of: constFPGlobal))
22+
expectEqual("default const FP: abc", constFPGlobal("abc"))
23+
}
24+
25+
// FIXME: Add tests for mutable globals, including mutating them, once the
26+
// compiler supports it, as well as loading from the const globals without
27+
// immediately calling them.
28+
29+
runAllTests()

0 commit comments

Comments
 (0)