Skip to content

Commit 92652c6

Browse files
authored
[ClangImporter] Supporting changes towards structs with ARC pointers (swiftlang#59594)
In order to allow supporting `__strong` (and `__weak`) struct fields, some parts of the ClangImporter needs to understand them. The changes in this commit allows the type importer to allow the already supported `__unsafe_unretained` struct fields, but still reject the `__strong` and `__weak` fields. Later changes will add support for bridging `__strong` and `__weak` fields. All the code should be equivalent to the previous code, and since all the structs with non-trivial copy/destroy are completely discarded, the code should not even be hit in any case. The included modifications in the tests check that the error and the diagnostics note are produced correctly.
1 parent 9611253 commit 92652c6

File tree

3 files changed

+45
-13
lines changed

3 files changed

+45
-13
lines changed

lib/ClangImporter/ImportType.cpp

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,8 +1267,8 @@ static bool canBridgeTypes(ImportTypeKind importKind) {
12671267
case ImportTypeKind::Variable:
12681268
case ImportTypeKind::AuditedVariable:
12691269
case ImportTypeKind::Enum:
1270-
case ImportTypeKind::RecordField:
12711270
return false;
1271+
case ImportTypeKind::RecordField:
12721272
case ImportTypeKind::Result:
12731273
case ImportTypeKind::AuditedResult:
12741274
case ImportTypeKind::Parameter:
@@ -1419,7 +1419,8 @@ static ImportedType adjustTypeForConcreteImport(
14191419
bool allowNSUIntegerAsInt, Bridgeability bridging,
14201420
llvm::function_ref<void(Diagnostic &&)> addImportDiagnostic,
14211421
ImportTypeAttrs attrs, OptionalTypeKind optKind,
1422-
bool resugarNSErrorPointer) {
1422+
bool resugarNSErrorPointer,
1423+
clang::Qualifiers::ObjCLifetime objCLifetime) {
14231424
Type importedType = importResult.AbstractType;
14241425
ImportHint hint = importResult.Hint;
14251426

@@ -1464,6 +1465,8 @@ static ImportedType adjustTypeForConcreteImport(
14641465
// bridge, do so.
14651466
if (canBridgeTypes(importKind) &&
14661467
importKind != ImportTypeKind::PropertyWithReferenceSemantics &&
1468+
!(importKind == ImportTypeKind::RecordField &&
1469+
objCLifetime <= clang::Qualifiers::OCL_ExplicitNone) &&
14671470
!(importKind == ImportTypeKind::Typedef &&
14681471
bridging == Bridgeability::None)) {
14691472
// id and Any can be bridged without Foundation. There would be
@@ -1484,7 +1487,10 @@ static ImportedType adjustTypeForConcreteImport(
14841487
// In some contexts, we bridge them to use the Swift function type
14851488
// representation. This includes typedefs of block types, which use the
14861489
// Swift function type representation.
1487-
if (!canBridgeTypes(importKind))
1490+
// FIXME: Do not bridge on RecordFields to keep previous behaviour for
1491+
// the time being.
1492+
if (!canBridgeTypes(importKind) ||
1493+
importKind == ImportTypeKind::RecordField)
14881494
break;
14891495

14901496
// Determine the function type representation we need.
@@ -1579,15 +1585,26 @@ static ImportedType adjustTypeForConcreteImport(
15791585
assert(importedType);
15801586

15811587
if (importKind == ImportTypeKind::RecordField &&
1582-
importedType->isAnyClassReferenceType() &&
15831588
!importedType->isForeignReferenceType()) {
1584-
// Wrap retainable struct fields in Unmanaged.
1585-
// FIXME: Eventually we might get C++-like support for strong pointers in
1586-
// structs, at which point we should really be checking the lifetime
1587-
// qualifiers.
1588-
// FIXME: This should apply to blocks as well, but Unmanaged is constrained
1589-
// to AnyObject.
1590-
importedType = getUnmanagedType(impl, importedType);
1589+
switch (objCLifetime) {
1590+
// Wrap retainable struct fields in Unmanaged.
1591+
case clang::Qualifiers::OCL_None:
1592+
case clang::Qualifiers::OCL_ExplicitNone:
1593+
// FIXME: This should apply to blocks as well, but Unmanaged is constrained
1594+
// to AnyObject.
1595+
if (importedType->isAnyClassReferenceType()) {
1596+
importedType = getUnmanagedType(impl, importedType);
1597+
}
1598+
break;
1599+
// FIXME: Eventually we might get C++-like support for strong pointers in
1600+
// structs, at which point we should really be checking the lifetime
1601+
// qualifiers.
1602+
case clang::Qualifiers::OCL_Strong:
1603+
case clang::Qualifiers::OCL_Weak:
1604+
return {Type(), false};
1605+
case clang::Qualifiers::OCL_Autoreleasing:
1606+
llvm_unreachable("invalid Objective-C lifetime");
1607+
}
15911608
}
15921609

15931610
// Apply attrs.
@@ -1665,6 +1682,8 @@ ImportedType ClangImporter::Implementation::importType(
16651682
}
16661683
}
16671684

1685+
clang::Qualifiers::ObjCLifetime objCLifetime = type.getObjCLifetime();
1686+
16681687
// Perform abstract conversion, ignoring how the type is actually used.
16691688
SwiftTypeConverter converter(
16701689
*this, addImportDiagnosticFn, allowNSUIntegerAsInt, bridging,
@@ -1674,7 +1693,8 @@ ImportedType ClangImporter::Implementation::importType(
16741693
// Now fix up the type based on how we're concretely using it.
16751694
auto adjustedType = adjustTypeForConcreteImport(
16761695
*this, importResult, importKind, allowNSUIntegerAsInt, bridging,
1677-
addImportDiagnosticFn, attrs, optionality, resugarNSErrorPointer);
1696+
addImportDiagnosticFn, attrs, optionality, resugarNSErrorPointer,
1697+
objCLifetime);
16781698

16791699
return adjustedType;
16801700
}

test/ClangImporter/objc_bridging.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -parse-as-library -verify %s
1+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -parse-as-library -verify-additional-file %clang-importer-sdk-path/usr/include/objc_structs.h -verify %s
22

33
// REQUIRES: objc_interop
44

@@ -62,6 +62,10 @@ func objcStructs(_ s: StructOfNSStrings, sb: StructOfBlocks) {
6262
// FIXME: Blocks should also be Unmanaged.
6363
_ = sb.block as Bool // expected-error {{cannot convert value of type '@convention(block) () -> Void' to type 'Bool' in coercion}}
6464
sb.block() // okay
65+
66+
// Structs with non-trivial copy/destroy should not be imported
67+
_ = WeaksInAStruct() // expected-error {{cannot find 'WeaksInAStruct' in scope}}
68+
_ = StrongsInAStruct() // expected-error {{cannot find 'StrongsInAStruct' in scope}}
6569
}
6670

6771
func test_repair_does_not_interfere_with_conversions() {

test/Inputs/clang-importer-sdk/usr/include/objc_structs.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,11 @@ struct StructOfNSStrings {
77
struct StructOfBlocks {
88
void (^__unsafe_unretained _Nonnull block)(void);
99
};
10+
11+
struct StrongsInAStruct { // expected-note {{record 'StrongsInAStruct' is not trivial to copy/destroy}}
12+
__strong NSString *nsstr;
13+
};
14+
15+
struct WeaksInAStruct { // expected-note {{record 'WeaksInAStruct' is not trivial to copy/destroy}}
16+
__weak NSString *nsstr;
17+
};

0 commit comments

Comments
 (0)