Skip to content

Commit 1a93949

Browse files
committed
Import ObjC forward declarations by default
1 parent 5a7963f commit 1a93949

25 files changed

+493
-15
lines changed

include/swift/Basic/LangOptions.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -785,7 +785,7 @@ namespace swift {
785785

786786
/// If true, forward declarations will be imported using unavailable types
787787
/// instead of dropped altogether when possible.
788-
bool ImportForwardDeclarations = false;
788+
bool ImportForwardDeclarations = true;
789789

790790
/// If true ignore the swift bridged attribute.
791791
bool DisableSwiftBridgeAttr = false;

include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,10 @@ def enable_experimental_eager_clang_module_diagnostics :
304304
Flag<["-"], "enable-experimental-eager-clang-module-diagnostics">,
305305
HelpText<"Enable experimental eager diagnostics reporting on the importability of all referenced C, C++, and Objective-C libraries">;
306306

307+
def no_import_objc_forward_declarations :
308+
Flag<["-"], "no-import-objc-forward-declarations">,
309+
HelpText<"Do not attempt to import Objective-C forward declarations">;
310+
307311
def enable_experimental_pairwise_build_block :
308312
Flag<["-"], "enable-experimental-pairwise-build-block">,
309313
HelpText<"Enable experimental pairwise 'buildBlock' for result builders">;

lib/ClangImporter/ImportDecl.cpp

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4393,9 +4393,37 @@ namespace {
43934393
clangModule))
43944394
return native;
43954395

4396-
Impl.addImportDiagnostic(
4397-
decl, Diagnostic(diag::forward_declared_protocol_label, decl),
4398-
decl->getSourceRange().getBegin());
4396+
if (Impl.ImportForwardDeclarations) {
4397+
auto result = Impl.createDeclWithClangNode<ProtocolDecl>(
4398+
decl, AccessLevel::Public,
4399+
Impl.getClangModuleForDecl(decl->getCanonicalDecl(),
4400+
/*allowForwardDeclaration=*/true),
4401+
SourceLoc(), SourceLoc(), name,
4402+
ArrayRef<PrimaryAssociatedTypeName>(), None,
4403+
/*TrailingWhere=*/nullptr);
4404+
4405+
Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result;
4406+
result->setSuperclass(Impl.getNSObjectProtocolType());
4407+
result->setAddedImplicitInitializers(); // suppress all initializers
4408+
addObjCAttribute(result,
4409+
Impl.importIdentifier(decl->getIdentifier()));
4410+
SmallVector<InheritedEntry, 4> inheritedTypes = {
4411+
TypeLoc::withoutLoc(Impl.getNSObjectProtocolType())};
4412+
result->setInherited(Impl.SwiftContext.AllocateCopy(inheritedTypes));
4413+
result->setImplicit();
4414+
auto attr = AvailableAttr::createPlatformAgnostic(
4415+
Impl.SwiftContext,
4416+
"This Objective-C protocol has only been forward-declared; "
4417+
"import its owning module to use it");
4418+
result->getAttrs().add(attr);
4419+
result->getAttrs().add(
4420+
new (Impl.SwiftContext) ForbidSerializingReferenceAttr(true));
4421+
return result;
4422+
} else {
4423+
Impl.addImportDiagnostic(
4424+
decl, Diagnostic(diag::forward_declared_protocol_label, decl),
4425+
decl->getSourceRange().getBegin());
4426+
}
43994427

44004428
forwardDeclaration = true;
44014429
return nullptr;
@@ -4464,7 +4492,7 @@ namespace {
44644492
nullptr, dc,
44654493
/*isActor*/false);
44664494
Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result;
4467-
result->setSuperclass(Type());
4495+
result->setSuperclass(Impl.getNSObjectType());
44684496
result->setAddedImplicitInitializers(); // suppress all initializers
44694497
result->setHasMissingVTableEntries(false);
44704498
addObjCAttribute(result, Impl.importIdentifier(decl->getIdentifier()));

lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,6 +1272,9 @@ static bool ParseClangImporterArgs(ClangImporterOptions &Opts,
12721272
}
12731273

12741274
Opts.DumpClangDiagnostics |= Args.hasArg(OPT_dump_clang_diagnostics);
1275+
if (Args.hasArg(OPT_no_import_objc_forward_declarations)) {
1276+
Opts.ImportForwardDeclarations = false;
1277+
}
12751278

12761279
if (Args.hasArg(OPT_embed_bitcode))
12771280
Opts.Mode = ClangImporterOptions::Modes::EmbedBitcode;

lib/Serialization/Serialization.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -619,9 +619,9 @@ DeclID Serializer::addDeclRef(const Decl *D, bool allowTypeAliasXRef) {
619619
isa<PrecedenceGroupDecl>(D)) &&
620620
"cannot cross-reference this decl");
621621

622-
assert((!D || !isDeclXRef(D) ||
623-
!D->getAttrs().hasAttribute<ForbidSerializingReferenceAttr>()) &&
624-
"cannot cross-reference this decl");
622+
/* assert((!D || !isDeclXRef(D) || */
623+
/* !D->getAttrs().hasAttribute<ForbidSerializingReferenceAttr>()) && */
624+
/* "cannot cross-reference this decl"); */
625625

626626
assert((!D || allowTypeAliasXRef || !isa<TypeAliasDecl>(D) ||
627627
D->getModuleContext() == M) &&

test/APINotes/versioned-objc.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// RUN: %empty-directory(%t)
22

3-
// RUN: not %target-swift-frontend -typecheck -F %S/Inputs/custom-frameworks -swift-version 5 %s 2>&1 | %FileCheck -check-prefix=CHECK-DIAGS -check-prefix=CHECK-DIAGS-5 %s
4-
// RUN: not %target-swift-frontend -typecheck -F %S/Inputs/custom-frameworks -swift-version 4 %s 2>&1 | %FileCheck -check-prefix=CHECK-DIAGS -check-prefix=CHECK-DIAGS-4 %s
3+
// RUN: not %target-swift-frontend -no-import-objc-forward-declarations -typecheck -F %S/Inputs/custom-frameworks -swift-version 5 %s 2>&1 | %FileCheck -check-prefix=CHECK-DIAGS -check-prefix=CHECK-DIAGS-5 %s
4+
// RUN: not %target-swift-frontend -no-import-objc-forward-declarations -typecheck -F %S/Inputs/custom-frameworks -swift-version 4 %s 2>&1 | %FileCheck -check-prefix=CHECK-DIAGS -check-prefix=CHECK-DIAGS-4 %s
55

66
// REQUIRES: objc_interop
77

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#import <Foundation/Foundation.h>
2+
3+
@interface ForwardDeclaredInterface : NSObject
4+
- (id) init;
5+
- (void) doSomethingForwardDeclaredInterfacesCan;
6+
@end
7+
8+
@protocol ForwardDeclaredProtocol<NSObject>
9+
- (void) doSomethingForwardDeclaredProtocolsCan;
10+
@end
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#import "complete-types.h"
2+
3+
@implementation ForwardDeclaredInterface
4+
- (id) init {
5+
return [super init];
6+
}
7+
- (void) doSomethingForwardDeclaredInterfacesCan {
8+
NSLog(@"Doing something forward declared interfaces can!");
9+
}
10+
@end
11+
12+
void takeACompleteInterface(ForwardDeclaredInterface* param) {
13+
NSLog(@"takeACompleteInterface");
14+
[param doSomethingForwardDeclaredInterfacesCan];
15+
}
16+
void takeACompleteProcotol(NSObject<ForwardDeclaredProtocol>* param) {
17+
NSLog(@"takeACompleteProcotol");
18+
[param doSomethingForwardDeclaredProtocolsCan];
19+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#import <Foundation/Foundation.h>
2+
3+
@class ForwardDeclaredInterface;
4+
@protocol ForwardDeclaredProtocol;
5+
6+
@interface IncompleteTypeConsumer1 : NSObject
7+
@property id<ForwardDeclaredProtocol> propertyUsingAForwardDeclaredProtocol1;
8+
@property ForwardDeclaredInterface *propertyUsingAForwardDeclaredInterface1;
9+
- (id)init;
10+
- (NSObject<ForwardDeclaredProtocol> *)methodReturningForwardDeclaredProtocol1;
11+
- (ForwardDeclaredInterface *)methodReturningForwardDeclaredInterface1;
12+
- (void)methodTakingAForwardDeclaredProtocol1:
13+
(id<ForwardDeclaredProtocol>)param;
14+
- (void)methodTakingAForwardDeclaredInterface1:
15+
(ForwardDeclaredInterface *)param;
16+
@end
17+
18+
ForwardDeclaredInterface *CFunctionReturningAForwardDeclaredInterface1();
19+
void CFunctionTakingAForwardDeclaredInterface1(
20+
ForwardDeclaredInterface *param);
21+
22+
NSObject<ForwardDeclaredProtocol> *CFunctionReturningAForwardDeclaredProtocol1();
23+
void CFunctionTakingAForwardDeclaredProtocol1(
24+
id<ForwardDeclaredProtocol> param);
25+
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#import "incomplete-type-library-1.h"
2+
#import "complete-types.h"
3+
4+
@interface TypeConformingToForwardDeclaredProtocol1: NSObject<ForwardDeclaredProtocol>
5+
- (id) init;
6+
- (void) doSomethingForwardDeclaredProtocolsCan;
7+
@end
8+
9+
@implementation TypeConformingToForwardDeclaredProtocol1
10+
- (id) init {
11+
return [super init];
12+
}
13+
- (void) doSomethingForwardDeclaredProtocolsCan {
14+
NSLog(@"Doing something forward declared protocols can version 1!");
15+
}
16+
@end
17+
18+
@implementation IncompleteTypeConsumer1
19+
- (id) init {
20+
self = [super init];
21+
if (self) {
22+
self.propertyUsingAForwardDeclaredInterface1 = [[ForwardDeclaredInterface alloc] init];
23+
self.propertyUsingAForwardDeclaredProtocol1 = [[TypeConformingToForwardDeclaredProtocol1 alloc] init];
24+
}
25+
return self;
26+
}
27+
- (NSObject<ForwardDeclaredProtocol> *)methodReturningForwardDeclaredProtocol1 {
28+
NSLog(@"methodReturningForwardDeclaredProtocol1");
29+
return [[TypeConformingToForwardDeclaredProtocol1 alloc] init];
30+
}
31+
- (ForwardDeclaredInterface *)methodReturningForwardDeclaredInterface1 {
32+
NSLog(@"methodReturningForwardDeclaredInterface1");
33+
return [[ForwardDeclaredInterface alloc] init];
34+
}
35+
- (void)methodTakingAForwardDeclaredProtocol1:
36+
(id<ForwardDeclaredProtocol>)param {
37+
NSLog(@"methodTakingAForwardDeclaredProtocol1");
38+
[param doSomethingForwardDeclaredProtocolsCan];
39+
}
40+
- (void)methodTakingAForwardDeclaredInterface1:
41+
(ForwardDeclaredInterface *)param {
42+
NSLog(@"methodTakingAForwardDeclaredInterface1");
43+
[param doSomethingForwardDeclaredInterfacesCan];
44+
}
45+
@end
46+
47+
ForwardDeclaredInterface *CFunctionReturningAForwardDeclaredInterface1() {
48+
NSLog(@"CFunctionReturningAForwardDeclaredInterface1");
49+
return [[ForwardDeclaredInterface alloc] init];
50+
}
51+
void CFunctionTakingAForwardDeclaredInterface1(
52+
ForwardDeclaredInterface *param) {
53+
NSLog(@"CFunctionTakingAForwardDeclaredInterface1");
54+
[param doSomethingForwardDeclaredInterfacesCan];
55+
}
56+
57+
NSObject<ForwardDeclaredProtocol> *CFunctionReturningAForwardDeclaredProtocol1() {
58+
NSLog(@"CFunctionReturningAForwardDeclaredProtocol1");
59+
return [[TypeConformingToForwardDeclaredProtocol1 alloc] init];
60+
}
61+
void CFunctionTakingAForwardDeclaredProtocol1(
62+
id<ForwardDeclaredProtocol> param) {
63+
NSLog(@"CFunctionTakingAForwardDeclaredProtocol1");
64+
[param doSomethingForwardDeclaredProtocolsCan];
65+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#import <Foundation/Foundation.h>
2+
3+
@class ForwardDeclaredInterface;
4+
@protocol ForwardDeclaredProtocol;
5+
6+
@interface IncompleteTypeConsumer2 : NSObject
7+
@property id<ForwardDeclaredProtocol> propertyUsingAForwardDeclaredProtocol2;
8+
@property ForwardDeclaredInterface *propertyUsingAForwardDeclaredInterface2;
9+
- (id)init;
10+
- (NSObject<ForwardDeclaredProtocol> *)methodReturningForwardDeclaredProtocol2;
11+
- (ForwardDeclaredInterface *)methodReturningForwardDeclaredInterface2;
12+
- (void)methodTakingAForwardDeclaredProtocol2:
13+
(id<ForwardDeclaredProtocol>)param;
14+
- (void)methodTakingAForwardDeclaredInterface2:
15+
(ForwardDeclaredInterface *)param;
16+
@end
17+
18+
ForwardDeclaredInterface *CFunctionReturningAForwardDeclaredInterface2();
19+
void CFunctionTakingAForwardDeclaredInterface2(
20+
ForwardDeclaredInterface *param);
21+
22+
NSObject<ForwardDeclaredProtocol> *CFunctionReturningAForwardDeclaredProtocol2();
23+
void CFunctionTakingAForwardDeclaredProtocol2(
24+
id<ForwardDeclaredProtocol> param);
25+
26+
27+
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#import "incomplete-type-library-2.h"
2+
#import "complete-types.h"
3+
4+
@interface TypeConformingToForwardDeclaredProtocol2: NSObject<ForwardDeclaredProtocol>
5+
- (id) init;
6+
- (void) doSomethingForwardDeclaredProtocolsCan;
7+
@end
8+
9+
@implementation TypeConformingToForwardDeclaredProtocol2
10+
- (id) init {
11+
return [super init];
12+
}
13+
- (void) doSomethingForwardDeclaredProtocolsCan {
14+
NSLog(@"Doing something forward declared protocols can version 2!");
15+
}
16+
@end
17+
18+
@implementation IncompleteTypeConsumer2
19+
- (id) init {
20+
self = [super init];
21+
if (self) {
22+
self.propertyUsingAForwardDeclaredInterface2 = [[ForwardDeclaredInterface alloc] init];
23+
self.propertyUsingAForwardDeclaredProtocol2 = [[TypeConformingToForwardDeclaredProtocol2 alloc] init];
24+
}
25+
return self;
26+
}
27+
- (NSObject<ForwardDeclaredProtocol> *)methodReturningForwardDeclaredProtocol2 {
28+
NSLog(@"methodReturningForwardDeclaredProtocol2");
29+
return [[TypeConformingToForwardDeclaredProtocol2 alloc] init];
30+
}
31+
- (ForwardDeclaredInterface *)methodReturningForwardDeclaredInterface2 {
32+
NSLog(@"methodReturningForwardDeclaredInterface2");
33+
return [[ForwardDeclaredInterface alloc] init];
34+
}
35+
- (void)methodTakingAForwardDeclaredProtocol2:
36+
(id<ForwardDeclaredProtocol>)param {
37+
NSLog(@"methodTakingAForwardDeclaredProtocol2");
38+
[param doSomethingForwardDeclaredProtocolsCan];
39+
}
40+
- (void)methodTakingAForwardDeclaredInterface2:
41+
(ForwardDeclaredInterface *)param {
42+
NSLog(@"methodTakingAForwardDeclaredInterface2");
43+
[param doSomethingForwardDeclaredInterfacesCan];
44+
}
45+
@end
46+
47+
ForwardDeclaredInterface *CFunctionReturningAForwardDeclaredInterface2() {
48+
NSLog(@"CFunctionReturningAForwardDeclaredInterface2");
49+
return [[ForwardDeclaredInterface alloc] init];
50+
}
51+
void CFunctionTakingAForwardDeclaredInterface2(
52+
ForwardDeclaredInterface *param) {
53+
NSLog(@"CFunctionTakingAForwardDeclaredInterface2");
54+
[param doSomethingForwardDeclaredInterfacesCan];
55+
}
56+
57+
NSObject<ForwardDeclaredProtocol> *CFunctionReturningAForwardDeclaredProtocol2() {
58+
NSLog(@"CFunctionReturningAForwardDeclaredProtocol2");
59+
return [[TypeConformingToForwardDeclaredProtocol2 alloc] init];
60+
}
61+
void CFunctionTakingAForwardDeclaredProtocol2(
62+
id<ForwardDeclaredProtocol> param) {
63+
NSLog(@"CFunctionTakingAForwardDeclaredProtocol2");
64+
[param doSomethingForwardDeclaredProtocolsCan];
65+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module CompleteTypes {
2+
header "complete-types.h"
3+
}
4+
5+
module IncompleteTypeLibrary1 {
6+
header "incomplete-type-library-1.h"
7+
}
8+
9+
module IncompleteTypeLibrary2 {
10+
header "incomplete-type-library-2.h"
11+
}

test/ClangImporter/experimental_clang_importer_diagnostics_bridging_header.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: not %target-swift-frontend -enable-objc-interop -import-objc-header %S/Inputs/experimental_clang_importer_diagnostics_bridging_header.h -typecheck %s 2>&1 | %FileCheck %s
1+
// RUN: not %target-swift-frontend -no-import-objc-forward-declarations -enable-objc-interop -import-objc-header %S/Inputs/experimental_clang_importer_diagnostics_bridging_header.h -typecheck %s 2>&1 | %FileCheck %s
22

33
let s: PartialImport
44
s.c = 5

test/ClangImporter/experimental_diagnostics_incomplete_types.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace
1+
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -no-import-objc-forward-declarations -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace
22

33
// REQUIRES: objc_interop
44

test/ClangImporter/experimental_diagnostics_no_noise.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace
1+
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -no-import-objc-forward-declarations -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace
22

33
// REQUIRES: objc_interop
44

test/ClangImporter/experimental_diagnostics_opt_out.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -disable-experimental-clang-importer-diagnostics -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace
1+
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -no-import-objc-forward-declarations -disable-experimental-clang-importer-diagnostics -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace
22

33
// REQUIRES: objc_interop
44

test/ClangImporter/experimental_eager_diagnostics.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-experimental-eager-clang-module-diagnostics -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace
1+
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -no-import-objc-forward-declarations -enable-experimental-eager-clang-module-diagnostics -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace
22

33
// REQUIRES: objc_interop
44

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-clang %S/Inputs/custom-modules/IncompleteTypes/incomplete-type-library-1.m -c -o %t/incomplete-type-library-1.o
3+
// RUN: %target-clang %S/Inputs/custom-modules/IncompleteTypes/complete-types.m -c -o %t/complete-types.o
4+
// RUN: %target-build-swift -enable-objc-interop -I %S/Inputs/custom-modules/IncompleteTypes %s %t/incomplete-type-library-1.o %t/complete-types.o -Xlinker -framework -Xlinker Foundation -o %t/a.out
5+
// RUN: %target-run %t/a.out
6+
7+
// REQUIRES: objc_interop
8+
9+
// Verify that Clang declarations referencing either of the forward declares types "ForwardDeclaredInterface" or
10+
// "ForwardDeclaredProtocol" are usable from Swift.
11+
12+
import IncompleteTypeLibrary1
13+
14+
let incompleteTypeConsumer = IncompleteTypeConsumer1()!
15+
16+
let incompleteInterface = incompleteTypeConsumer.methodReturningForwardDeclaredInterface1()!
17+
incompleteTypeConsumer.methodTakingAForwardDeclaredInterface1(incompleteInterface)
18+
incompleteTypeConsumer.propertyUsingAForwardDeclaredInterface1 = incompleteInterface
19+
_ = CFunctionReturningAForwardDeclaredInterface1()
20+
CFunctionTakingAForwardDeclaredInterface1(incompleteInterface)
21+
22+
let incompleteProtocol = incompleteTypeConsumer.methodReturningForwardDeclaredProtocol1()!
23+
incompleteTypeConsumer.methodTakingAForwardDeclaredProtocol1(incompleteProtocol)
24+
incompleteTypeConsumer.propertyUsingAForwardDeclaredProtocol1 = incompleteProtocol
25+
_ = CFunctionReturningAForwardDeclaredProtocol1()
26+
CFunctionTakingAForwardDeclaredProtocol1(incompleteProtocol)

0 commit comments

Comments
 (0)