Skip to content

Commit 08f9f11

Browse files
committed
IRGen: Map Int and UInt to Clang types via NS[U]Integer.
If NSInteger and NSUInteger typedefs are available in the current Clang context, use them when mapping Swift's Int and UInt to Clang types. This gives us consistent method and property type encodings for @objc methods with Clang, fixing rdar://problem/17506068.
1 parent 997b043 commit 08f9f11

File tree

3 files changed

+78
-0
lines changed

3 files changed

+78
-0
lines changed

lib/IRGen/GenClangType.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,30 @@ clang::CanQualType GenClangType::visitStructType(CanStructType type) {
225225
return Converter.reverseBuiltinTypeMapping(IGM, type);
226226
}
227227

228+
static clang::CanQualType getClangBuiltinTypeFromTypedef(
229+
const clang::ASTContext &context, StringRef typedefName) {
230+
auto identifier = &context.Idents.get(typedefName);
231+
auto lookup = context.getTranslationUnitDecl()->lookup(identifier);
232+
233+
clang::TypedefDecl *typedefDecl = nullptr;
234+
for (auto found : lookup) {
235+
auto foundTypedef = dyn_cast<clang::TypedefDecl>(found);
236+
if (!foundTypedef)
237+
continue;
238+
typedefDecl = foundTypedef;
239+
break;
240+
}
241+
if (!typedefDecl)
242+
return {};
243+
244+
auto underlyingTy =
245+
context.getCanonicalType(typedefDecl->getUnderlyingType());
246+
247+
if (underlyingTy->getAs<clang::BuiltinType>())
248+
return underlyingTy;
249+
return {};
250+
}
251+
228252
clang::CanQualType
229253
ClangTypeConverter::reverseBuiltinTypeMapping(IRGenModule &IGM,
230254
CanStructType type) {
@@ -260,6 +284,22 @@ ClangTypeConverter::reverseBuiltinTypeMapping(IRGenModule &IGM,
260284
clang::BuiltinType::Kind builtinKind) {
261285
CanType swiftType = getNamedSwiftType(stdlib, swiftName);
262286
if (!swiftType) return;
287+
288+
// Handle Int and UInt specially. On Apple platforms, these correspond to
289+
// the NSInteger and NSUInteger typedefs, so map them back to those typedefs
290+
// if they're available, to ensure we get consistent ObjC @encode strings.
291+
if (swiftType->getAnyNominal() == IGM.Context.getIntDecl()) {
292+
if (auto NSIntegerTy = getClangBuiltinTypeFromTypedef(ctx, "NSInteger")) {
293+
Cache.insert({swiftType, NSIntegerTy});
294+
return;
295+
}
296+
} else if (swiftType->getAnyNominal() == IGM.Context.getUIntDecl()) {
297+
if (auto NSUIntegerTy =
298+
getClangBuiltinTypeFromTypedef(ctx, "NSUInteger")) {
299+
Cache.insert({swiftType, NSUIntegerTy});
300+
return;
301+
}
302+
}
263303

264304
Cache.insert({swiftType, getClangBuiltinTypeFromKind(ctx, builtinKind)});
265305
};

test/IRGen/objc_int_encoding.sil

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) %s -emit-ir | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize
2+
// REQUIRES: objc_interop
3+
4+
// CHECK: [[SELECTOR:@.*]] = private global {{.*}} c"fooWithX:\00"
5+
6+
// CHECK-64: [[INT_UINT_METHOD_ENCODING:@.*]] = private unnamed_addr constant {{.*}} c"Q24@0:8q16\00"
7+
// CHECK-32: [[INT_UINT_METHOD_ENCODING:@.*]] = private unnamed_addr constant {{.*}} c"I12@0:4i8\00"
8+
9+
// CHECK: @_INSTANCE_METHODS__TtC17objc_int_encoding3Foo = private constant {{.*}} [[SELECTOR]], {{.*}} [[INT_UINT_METHOD_ENCODING]], {{.*}} @_TToFC17objc_int_encoding3Foo3foofT1xSi_Su
10+
11+
sil_stage canonical
12+
13+
import Builtin
14+
import Swift
15+
import Foundation
16+
17+
class Foo: NSObject {
18+
@objc override init() {}
19+
20+
@objc func foo(x: Int) -> UInt
21+
}
22+
23+
sil hidden @_TToFC17objc_int_encoding3Foo3foofT1xSi_Su : $@convention(objc_method) (Int, @guaranteed Foo) -> UInt {
24+
entry(%0 : $Int, %1 : $Foo):
25+
unreachable
26+
}
27+
sil @_TToFC17objc_int_encoding3FoocfT_S0_ : $@convention(objc_method) (@owned Foo) -> @owned Foo {
28+
entry(%1 : $Foo):
29+
unreachable
30+
}
31+
32+
sil_vtable Foo {}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,14 @@
44
#define OBJC_ARC_UNAVAILABLE __attribute__((unavailable("not available in automatic reference counting mode")))
55
#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE OBJC_ARC_UNAVAILABLE
66

7+
#ifdef __LP64__
78
typedef unsigned long NSUInteger;
89
typedef long NSInteger;
10+
#else
11+
typedef unsigned int NSUInteger;
12+
typedef int NSInteger;
13+
#endif
14+
915
typedef __typeof__(__objc_yes) BOOL;
1016

1117
typedef struct objc_selector *SEL;

0 commit comments

Comments
 (0)