Skip to content

Commit f562aeb

Browse files
committed
[ClangImporter] Resolve forward declarations before importing names.
This allows a previously-working case of Objective-C forward-declaring a type in a /different/ Swift module to continue working, as long as the Swift context being compiled manages to import the other module properly (including its generated header). This isn't really our recommended pattern---that would be to @import the module in the bridging header and forego the forward declaration---but it doesn't cost much to keep it working. It's also a place where textual and precompiled bridging headers behaved differently, because precompiled ones are processed much earlier. https://bugs.swift.org/browse/SR-3798
1 parent 63d2ac9 commit f562aeb

File tree

5 files changed

+54
-18
lines changed

5 files changed

+54
-18
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4030,18 +4030,8 @@ namespace {
40304030
}
40314031

40324032
Decl *VisitObjCInterfaceDecl(const clang::ObjCInterfaceDecl *decl) {
4033-
Optional<ImportedName> correctSwiftName;
4034-
auto importedName = importFullName(decl, correctSwiftName);
4035-
if (!importedName) return nullptr;
4036-
4037-
// If we've been asked to produce a Swift 2 stub, handle it via a
4038-
// typealias.
4039-
if (correctSwiftName)
4040-
return importSwift2TypeAlias(decl, importedName, *correctSwiftName);
4041-
4042-
auto name = importedName.getDeclName().getBaseName();
4043-
4044-
auto createRootClass = [=](DeclContext *dc = nullptr) -> ClassDecl * {
4033+
auto createRootClass = [=](Identifier name,
4034+
DeclContext *dc = nullptr) -> ClassDecl * {
40454035
if (!dc) {
40464036
dc = Impl.getClangModuleForDecl(decl->getCanonicalDecl(),
40474037
/*allowForwardDeclaration=*/true);
@@ -4076,11 +4066,26 @@ namespace {
40764066
const ClassDecl *nsObjectDecl =
40774067
nsObjectTy->getClassOrBoundGenericClass();
40784068

4079-
auto result = createRootClass(nsObjectDecl->getDeclContext());
4069+
auto result = createRootClass(Impl.SwiftContext.Id_Protocol,
4070+
nsObjectDecl->getDeclContext());
40804071
result->setForeignClassKind(ClassDecl::ForeignKind::RuntimeOnly);
40814072
return result;
40824073
}
40834074

4075+
if (auto *definition = decl->getDefinition())
4076+
decl = definition;
4077+
4078+
Optional<ImportedName> correctSwiftName;
4079+
auto importedName = importFullName(decl, correctSwiftName);
4080+
if (!importedName) return nullptr;
4081+
4082+
// If we've been asked to produce a Swift 2 stub, handle it via a
4083+
// typealias.
4084+
if (correctSwiftName)
4085+
return importSwift2TypeAlias(decl, importedName, *correctSwiftName);
4086+
4087+
auto name = importedName.getDeclName().getBaseName();
4088+
40844089
if (!decl->hasDefinition()) {
40854090
// Check if this class is implemented in its adapter.
40864091
if (auto clangModule = Impl.getClangModuleForDecl(decl, true)) {
@@ -4092,7 +4097,7 @@ namespace {
40924097

40934098
if (Impl.ImportForwardDeclarations) {
40944099
// Fake it by making an unavailable opaque @objc root class.
4095-
auto result = createRootClass();
4100+
auto result = createRootClass(name);
40964101
result->setImplicit();
40974102
auto attr = AvailableAttr::createPlatformAgnostic(Impl.SwiftContext,
40984103
"This Objective-C class has only been forward-declared; "
@@ -4105,9 +4110,6 @@ namespace {
41054110
return nullptr;
41064111
}
41074112

4108-
decl = decl->getDefinition();
4109-
assert(decl);
4110-
41114113
auto dc =
41124114
Impl.importDeclContextOf(decl, importedName.getEffectiveContext());
41134115
if (!dc)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@class SwiftClass, SwiftClassWithCustomName;
2+
3+
@interface BridgingHeader
4+
+ (void)takeForward:(SwiftClass *)class;
5+
+ (void)takeRenamedForward:(SwiftClassWithCustomName *)class;
6+
@end

test/ClangImporter/MixedSource/Inputs/mixed-framework/Mixed.framework/Headers/Mixed.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// Manual PrintAsObjC for testing purposes.
2+
13
struct PureClangType {
24
int x;
35
int y;
@@ -16,7 +18,7 @@ struct PureClangType {
1618
# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
1719
#endif
1820

19-
#ifndef SWIFT_EXTENSION(X)
21+
#ifndef SWIFT_EXTENSION
2022
# define SWIFT_EXTENSION(X) X##__LINE__
2123
#endif
2224

test/ClangImporter/MixedSource/Inputs/resolve-cross-language/Base.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,9 @@ extension BaseClass {
3232
@objc public func getSwiftEnum() -> SwiftEnum { return .Quux }
3333
public init() {}
3434
}
35+
36+
@objc(RenamedClass) public class SwiftClass {}
37+
38+
public func getSwiftClass() -> SwiftClass {
39+
return SwiftClass()
40+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: rm -rf %t && mkdir -p %t
2+
// RUN: cp -r %S/Inputs/mixed-framework/Mixed.framework %t
3+
4+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-module -o %t/Mixed.framework/Modules/Mixed.swiftmodule/%target-swiftmodule-name %S/Inputs/mixed-framework/Mixed.swift -import-underlying-module -F %t -module-name Mixed -disable-objc-attr-requires-foundation-module
5+
6+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -F %t -import-objc-header %S/Inputs/import-mixed-framework-with-forward.h %s -verify
7+
8+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-pch -F %t %S/Inputs/import-mixed-framework-with-forward.h -o %t/bridge.pch
9+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -F %t -import-objc-header %t/bridge.pch %s -verify
10+
11+
12+
// REQUIRES: objc_interop
13+
14+
import Mixed
15+
16+
BridgingHeader.takeForward(SwiftClass(x: 42))
17+
BridgingHeader.takeRenamedForward(CustomNameClass())
18+
19+
// Check that we're compiling at all.
20+
BridgingHeader.takeRenamedForward(SwiftClass(x: 42)) // expected-error {{cannot convert value of type 'SwiftClass' to expected argument type 'CustomNameClass!'}}

0 commit comments

Comments
 (0)