Skip to content

Commit b318763

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 6132819 commit b318763

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
@@ -473,6 +473,9 @@ BUILTIN_MISC_OPERATION(UnsafeGuaranteed, "unsafeGuaranteed", "", Special)
473473
// unsafeGuaranteedEnd has type (Builtin.Int8) -> ()
474474
BUILTIN_MISC_OPERATION(UnsafeGuaranteedEnd, "unsafeGuaranteedEnd", "", Special)
475475

476+
// getObjCTypeEncoding has type <T> T.Type -> RawPointer
477+
BUILTIN_MISC_OPERATION(GetObjCTypeEncoding, "getObjCTypeEncoding", "n", Special)
478+
476479
#undef BUILTIN_MISC_OPERATION
477480

478481
// 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
@@ -913,6 +913,15 @@ static ValueDecl *getZeroInitializerOperation(ASTContext &Context,
913913
return builder.build(Id);
914914
}
915915

916+
static ValueDecl *getGetObjCTypeEncodingOperation(ASTContext &Context,
917+
Identifier Id) {
918+
// <T> T.Type -> RawPointer
919+
GenericSignatureBuilder builder(Context);
920+
builder.addParameter(makeMetatype(makeGenericParam()));
921+
builder.setResult(makeConcrete(Context.TheRawPointerType));
922+
return builder.build(Id);
923+
}
924+
916925
static ValueDecl *getAddressOfOperation(ASTContext &Context, Identifier Id) {
917926
// <T> (@inout T) -> RawPointer
918927
GenericSignatureBuilder builder(Context);
@@ -1740,6 +1749,9 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
17401749
case BuiltinValueKind::IntToFPWithOverflow:
17411750
if (Types.size() != 2) return nullptr;
17421751
return getIntToFPWithOverflowOperation(Context, Id, Types[0], Types[1]);
1752+
1753+
case BuiltinValueKind::GetObjCTypeEncoding:
1754+
return getGetObjCTypeEncodingOperation(Context, Id);
17431755
}
17441756

17451757
llvm_unreachable("bad builtin value!");

lib/IRGen/GenBuiltin.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "swift/AST/Builtins.h"
2424
#include "swift/AST/Types.h"
2525
#include "swift/SIL/SILModule.h"
26+
#include "clang/AST/ASTContext.h"
2627

2728
#include "Explosion.h"
2829
#include "GenCall.h"
@@ -830,5 +831,18 @@ if (Builtin.ID == BuiltinValueKind::id) { \
830831
return;
831832
}
832833

834+
if (Builtin.ID == BuiltinValueKind::GetObjCTypeEncoding) {
835+
args.claimAll();
836+
Type valueTy = substitutions[0].getReplacement();
837+
// Get the type encoding for the associated clang type.
838+
auto clangTy = IGF.IGM.getClangType(valueTy->getCanonicalType());
839+
std::string encoding;
840+
IGF.IGM.getClangASTContext().getObjCEncodingForType(clangTy, encoding);
841+
842+
auto globalString = IGF.IGM.getAddrOfGlobalString(encoding);
843+
out.add(globalString);
844+
return;
845+
}
846+
833847
llvm_unreachable("IRGen unimplemented for this builtin!");
834848
}

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)