Skip to content

Commit c84bec7

Browse files
committed
[Clang importer] Suppress method imports found via selector lookup.
When we found Objective-C methods via selector lookup, we would skip the “should we even try to import this?” check. If the Swift-name-as-derived- from-Objective-C is different from the actual Swift name, we might try to (redundantly) import something from the generated Objective-C header, which can lead to crashes. The specific method causing problems was defined like this in Swift: @objc public class func using(index: AnyObject) -> AnyObject? { return nil } which produced an Objective-C method like this: + (id _Nullable)usingIndex:(id _Nonnull)index; The Swift name derived from the Objective-C method is `usingIndex(_:)`, which of course does not match `using(index:)`, meaning that we think these two methods are different (they aren’t). The safe fix is to check whether we should import a given Objective-C method declaration along the found-via-Objective-C-selector path, like we do with normal name lookup. A longer term fix is to emit swift_name attributes for such methods. Fixes the fiendish Clang importer crash in rdar://problem/60046206.
1 parent c0cf407 commit c84bec7

File tree

5 files changed

+53
-0
lines changed

5 files changed

+53
-0
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3134,6 +3134,9 @@ void ClangModuleUnit::lookupObjCMethods(
31343134
auto owningClangModule = getClangTopLevelOwningModule(objcMethod, clangCtx);
31353135
if (owningClangModule != clangModule) continue;
31363136

3137+
if (shouldSuppressDeclImport(objcMethod))
3138+
continue;
3139+
31373140
// If we found a property accessor, import the property.
31383141
if (objcMethod->isPropertyAccessor())
31393142
(void)owner.importDecl(objcMethod->findPropertyDecl(true),
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#import <objc/NSObject.h>
2+
3+
# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
4+
# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X)))
5+
6+
# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME)
7+
8+
# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="ObjCExportingFramework",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol))
9+
10+
SWIFT_CLASS_NAMED("SwiftClass")
11+
@interface SwiftClass : NSObject
12+
+ (id _Nullable)usingIndex:(id _Nonnull)index;
13+
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
14+
@end
15+
16+
# pragma clang attribute pop
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import Foundation
2+
@_exported import MismatchedNames
3+
4+
@objc public class SwiftClass : NSObject {
5+
@objc public class func using(index: AnyObject) -> AnyObject? { return nil }
6+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
framework module MismatchedNames {
2+
}
3+
4+
module MismatchedNames.Swift {
5+
header "MismatchedNames-Swift.h"
6+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: mkdir -p %t/modules
3+
4+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-module -module-name MismatchedNames -F %S/Inputs/frameworks -o %t/modules/MismatchedNames.swiftmodule %S/Inputs/frameworks/MismatchedNames.framework/MismatchedNamesSwift.swift
5+
6+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -F %S/Inputs/frameworks -I %t/modules %s -verify -verify-ignore-unknown
7+
8+
// REQUIRES: objc_interop
9+
10+
11+
import Foundation
12+
import ObjectiveC
13+
import MismatchedNames
14+
15+
// Ensure that we don't crash when looking up via Objective-C selector and
16+
// finding a method in the generated header that (due to a missing swift_name
17+
// attribute) isn't "obviously" matching its corresponding Swift method.
18+
//
19+
// rdar://problem/60046206 covers this crash.
20+
func test() {
21+
_ = Selector(("usingIndex:")) // expected-warning{{use '#selector' instead of explicitly constructing a 'Selector'}}
22+
}

0 commit comments

Comments
 (0)