Skip to content

Commit 272163f

Browse files
committed
Add a builtin to generate the ObjC @encode string for a type.
We need the encode string to be able to construct NSValues using the core valueWithBytes:objCType: API. This builtin only works with concrete, @objc-representable types for now, which should be sufficient for a stdlib-internal API.
1 parent fa92152 commit 272163f

File tree

5 files changed

+76
-0
lines changed

5 files changed

+76
-0
lines changed

include/swift/AST/Builtins.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,9 @@ BUILTIN_MISC_OPERATION(UnsafeGuaranteed, "unsafeGuaranteed", "", Special)
452452
// unsafeGuaranteedEnd has type (Builtin.Int8) -> ()
453453
BUILTIN_MISC_OPERATION(UnsafeGuaranteedEnd, "unsafeGuaranteedEnd", "", Special)
454454

455+
// getObjCTypeEncoding has type <T> T.Type -> RawPointer
456+
BUILTIN_MISC_OPERATION(GetObjCTypeEncoding, "getObjCTypeEncoding", "n", Special)
457+
455458
#undef BUILTIN_MISC_OPERATION
456459

457460
// BUILTIN_TYPE_TRAIT_OPERATION - Compile-time type trait operations.

lib/AST/Builtins.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,15 @@ static ValueDecl *getZeroInitializerOperation(ASTContext &Context,
847847
return builder.build(Id);
848848
}
849849

850+
static ValueDecl *getGetObjCTypeEncodingOperation(ASTContext &Context,
851+
Identifier Id) {
852+
// <T> T.Type -> RawPointer
853+
GenericSignatureBuilder builder(Context);
854+
builder.addParameter(makeMetatype(makeGenericParam()));
855+
builder.setResult(makeConcrete(Context.TheRawPointerType));
856+
return builder.build(Id);
857+
}
858+
850859
static ValueDecl *getAddressOfOperation(ASTContext &Context, Identifier Id) {
851860
// <T> (@inout T) -> RawPointer
852861
GenericSignatureBuilder builder(Context);
@@ -1626,6 +1635,9 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
16261635
case BuiltinValueKind::IntToFPWithOverflow:
16271636
if (Types.size() != 2) return nullptr;
16281637
return getIntToFPWithOverflowOperation(Context, Id, Types[0], Types[1]);
1638+
1639+
case BuiltinValueKind::GetObjCTypeEncoding:
1640+
return getGetObjCTypeEncodingOperation(Context, Id);
16291641
}
16301642

16311643
llvm_unreachable("bad builtin value!");

lib/IRGen/GenBuiltin.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "llvm/ADT/StringSwitch.h"
2323
#include "swift/AST/Types.h"
2424
#include "swift/SIL/SILModule.h"
25+
#include "clang/AST/ASTContext.h"
2526

2627
#include "Explosion.h"
2728
#include "GenCall.h"
@@ -852,5 +853,18 @@ if (Builtin.ID == BuiltinValueKind::id) { \
852853
return;
853854
}
854855

856+
if (Builtin.ID == BuiltinValueKind::GetObjCTypeEncoding) {
857+
args.claimAll();
858+
Type valueTy = substitutions[0].getReplacement();
859+
// Get the type encoding for the associated clang type.
860+
auto clangTy = IGF.IGM.getClangType(valueTy->getCanonicalType());
861+
std::string encoding;
862+
IGF.IGM.getClangASTContext().getObjCEncodingForType(clangTy, encoding);
863+
864+
auto globalString = IGF.IGM.getAddrOfGlobalString(encoding);
865+
out.add(globalString);
866+
return;
867+
}
868+
855869
llvm_unreachable("IRGen unimplemented for this builtin!");
856870
}

stdlib/public/core/BridgeObjectiveC.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,4 +580,16 @@ extension AutoreleasingUnsafeMutablePointer {
580580
}
581581
}
582582

583+
/// Get the ObjC type encoding for a type as a pointer to a C string.
584+
///
585+
/// This is used by the Foundation overlays. The compiler will error if the
586+
/// passed-in type is generic or not representable in Objective-C
587+
@_transparent
588+
public func _getObjCTypeEncoding<T>(_ type: T.Type) -> UnsafePointer<Int8> {
589+
// This must be `@_transparent` because `Builtin.getObjCTypeEncoding` is
590+
// only supported by the compiler for concrete types that are representable
591+
// in ObjC.
592+
return UnsafePointer(Builtin.getObjCTypeEncoding(type))
593+
}
594+
583595
#endif

test/IRGen/builtins_objc.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// RUN: %target-swift-frontend -parse-stdlib -primary-file %s -emit-ir | %FileCheck %s
2+
3+
// REQUIRES: executable_test
4+
// REQUIRES: objc_interop
5+
6+
import Swift
7+
import Foundation
8+
9+
@objc enum ObjCEnum: Int32 { case X }
10+
@objc class ObjCClass: NSObject {}
11+
class NonObjCClass {}
12+
13+
@_silgen_name("use")
14+
func use(_: Builtin.RawPointer)
15+
16+
17+
func getObjCTypeEncoding<T>(_: T) {
18+
// CHECK: call void @use({{.* i8]\*}} [[INT32:@[0-9]+]],
19+
use(Builtin.getObjCTypeEncoding(Int32.self))
20+
// CHECK: call void @use({{.* i8]\*}} [[INT32]]
21+
use(Builtin.getObjCTypeEncoding(ObjCEnum.self))
22+
// CHECK: call void @use({{.* i8]\*}} [[CGRECT:@[0-9]+]],
23+
use(Builtin.getObjCTypeEncoding(CGRect.self))
24+
// CHECK: call void @use({{.* i8]\*}} [[NSRANGE:@[0-9]+]],
25+
use(Builtin.getObjCTypeEncoding(NSRange.self))
26+
// CHECK: call void @use({{.* i8]\*}} [[OBJECT:@[0-9]+]],
27+
use(Builtin.getObjCTypeEncoding(AnyObject.self))
28+
// CHECK: call void @use({{.* i8]\*}} [[OBJECT]]
29+
use(Builtin.getObjCTypeEncoding(NSObject.self))
30+
// CHECK: call void @use({{.* i8]\*}} [[OBJECT]]
31+
use(Builtin.getObjCTypeEncoding(ObjCClass.self))
32+
// CHECK: call void @use({{.* i8]\*}} [[OBJECT]]
33+
use(Builtin.getObjCTypeEncoding(NonObjCClass.self))
34+
}
35+

0 commit comments

Comments
 (0)