Skip to content

Commit aec6ea7

Browse files
committed
Merge pull request #2463 from milseman/newtype
[SILGen] Recognize swift_newtype-ed CF foreign class types
2 parents 910269d + 9dd6217 commit aec6ea7

File tree

6 files changed

+99
-19
lines changed

6 files changed

+99
-19
lines changed

include/swift/AST/Types.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,10 @@ class alignas(1 << TypeAlignInBits) TypeBase {
871871
return getAnyOptionalObjectType(ignored);
872872
}
873873

874+
// Return type underlying type of a swift_newtype annotated imported struct;
875+
// otherwise, return the null type.
876+
Type getSwiftNewtypeUnderlyingType();
877+
874878
/// Return the type T after looking through all of the optional or
875879
/// implicitly-unwrapped optional types.
876880
Type lookThroughAllAnyOptionalTypes();

lib/AST/Decl.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4655,3 +4655,25 @@ void InfixOperatorDecl::collectOperatorKeywordRanges(SmallVectorImpl
46554655
bool FuncDecl::isDeferBody() const {
46564656
return getName() == getASTContext().getIdentifier("$defer");
46574657
}
4658+
4659+
Type TypeBase::getSwiftNewtypeUnderlyingType() {
4660+
auto structDecl = getStructOrBoundGenericStruct();
4661+
if (!structDecl)
4662+
return {};
4663+
4664+
// Make sure the clang node has swift_newtype attribute
4665+
if (!structDecl->getClangNode())
4666+
return {};
4667+
auto clangNode = structDecl->getClangNode();
4668+
if (!clangNode.getAsDecl() ||
4669+
!clangNode.castAsDecl()->getAttr<clang::SwiftNewtypeAttr>())
4670+
return {};
4671+
4672+
// Underlying type is the type of rawValue
4673+
for (auto member : structDecl->getMembers())
4674+
if (auto varDecl = dyn_cast<VarDecl>(member))
4675+
if (varDecl->getName().str() == "rawValue")
4676+
return varDecl->getType();
4677+
4678+
return {};
4679+
}

lib/ClangImporter/ImportType.cpp

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,21 +1005,6 @@ static bool isNSString(Type type) {
10051005
return false;
10061006
}
10071007

1008-
static Type findNewtypeUnderlyingType(Type newtype) {
1009-
auto structDecl = newtype->getStructOrBoundGenericStruct();
1010-
assert(structDecl && structDecl->getClangNode() &&
1011-
structDecl->getClangNode().getAsDecl() &&
1012-
structDecl->getClangNode()
1013-
.castAsDecl()
1014-
->getAttr<clang::SwiftNewtypeAttr>() &&
1015-
"Called on a non-swift_newtype decl");
1016-
for (auto member : structDecl->getMembers())
1017-
if (auto varDecl = dyn_cast<VarDecl>(member))
1018-
if (varDecl->getName().str() == "rawValue")
1019-
return varDecl->getType();
1020-
assert(0 && "no rawValue variable member");
1021-
}
1022-
10231008
static Type adjustTypeForConcreteImport(ClangImporter::Implementation &impl,
10241009
clang::QualType clangType,
10251010
Type importedType,
@@ -1205,7 +1190,7 @@ static Type adjustTypeForConcreteImport(ClangImporter::Implementation &impl,
12051190
// then we have to for it to be unmanaged
12061191
if (hint == ImportHint::SwiftNewtypeFromCFPointer &&
12071192
!isCFAudited(importKind)) {
1208-
auto underlyingType = findNewtypeUnderlyingType(importedType);
1193+
auto underlyingType = importedType->getSwiftNewtypeUnderlyingType();
12091194
if (underlyingType)
12101195
importedType = getUnmanagedType(impl, underlyingType);
12111196
}

lib/SIL/SILFunctionType.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,8 +404,20 @@ enum class ConventionsKind : uint8_t {
404404
if (substTy->getClassOrBoundGenericClass()
405405
&& substTy->getClassOrBoundGenericClass()->isForeign())
406406
return false;
407+
// swift_newtype-ed CF type as foreign class
408+
if (auto typedefTy = clangTy->getAs<clang::TypedefType>()) {
409+
if (typedefTy->getDecl()->getAttr<clang::SwiftNewtypeAttr>()) {
410+
// Make sure that we actually made the struct during import
411+
if (auto underlyingType =
412+
substTy->getSwiftNewtypeUnderlyingType()) {
413+
if (underlyingType->getClassOrBoundGenericClass() &&
414+
underlyingType->getClassOrBoundGenericClass()->isForeign())
415+
return false;
416+
}
417+
}
418+
}
407419
}
408-
420+
409421
return true;
410422
}
411423
return false;

test/IDE/Inputs/custom-modules/Newtype.h

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,34 @@ typedef CFStringRef CFNewType __attribute((swift_newtype(struct)));
5757
// CF audited
5858
_Pragma("clang arc_cf_code_audited begin")
5959
extern const CFNewType MyCFNewTypeValue;
60-
CFNewType FooAudited(void);
60+
extern CFNewType FooAudited(void);
6161
_Pragma("clang arc_cf_code_audited end")
6262
extern const CFNewType MyCFNewTypeValueUnauditedButConst;
6363

6464
// un-audited CFStringRef
6565
extern CFNewType MyCFNewTypeValueUnaudited;
66-
CFNewType FooUnaudited(void);
66+
extern CFNewType FooUnaudited(void);
67+
68+
// Tests to show identical calling convention / binary representation for
69+
// new_type and non-new_type
70+
typedef CFStringRef MyABINewType __attribute((swift_newtype(struct)));
71+
typedef CFStringRef MyABIOldType;
72+
_Pragma("clang arc_cf_code_audited begin")
73+
extern const MyABINewType kMyABINewTypeGlobal;
74+
extern const MyABIOldType kMyABIOldTypeGlobal;
75+
extern MyABINewType getMyABINewType(void);
76+
extern MyABIOldType getMyABIOldType(void);
77+
extern void takeMyABINewType(MyABINewType);
78+
extern void takeMyABIOldType(MyABIOldType);
79+
80+
extern void takeMyABINewTypeNonNull(__nonnull MyABINewType);
81+
extern void takeMyABIOldTypeNonNull(__nonnull MyABIOldType);
82+
_Pragma("clang arc_cf_code_audited end")
83+
84+
typedef NSString *MyABINewTypeNS __attribute((swift_newtype(struct)));
85+
typedef NSString *MyABIOldTypeNS;
86+
extern MyABINewTypeNS getMyABINewTypeNS(void);
87+
extern MyABIOldTypeNS getMyABIOldTypeNS(void);
88+
extern void takeMyABINewTypeNonNullNS(__nonnull MyABINewTypeNS);
89+
extern void takeMyABIOldTypeNonNullNS(__nonnull MyABIOldTypeNS);
90+

test/IRGen/newtype.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,36 @@ public func getUnmanagedCFNewType(useVar: Bool) -> Unmanaged<CFString> {
6767
// witness table.
6868
public func hasArrayOfClosedEnums(closed: [ClosedEnum]) {
6969
}
70+
71+
// CHECK-LABEL: _TF7newtype11compareABIsFT_T_
72+
public func compareABIs() {
73+
let new = getMyABINewType()
74+
let old = getMyABIOldType()
75+
takeMyABINewType(new)
76+
takeMyABIOldType(old)
77+
78+
takeMyABINewTypeNonNull(new!)
79+
takeMyABIOldTypeNonNull(old!)
80+
81+
let newNS = getMyABINewTypeNS()
82+
let oldNS = getMyABIOldTypeNS()
83+
takeMyABINewTypeNonNullNS(newNS!)
84+
takeMyABIOldTypeNonNullNS(oldNS!)
85+
86+
// Make sure that the calling conventions align correctly, that is we don't
87+
// have double-indirection or anything else like that
88+
// CHECK: declare %struct.__CFString* @getMyABINewType() #0
89+
// CHECK: declare %struct.__CFString* @getMyABIOldType() #0
90+
//
91+
// CHECK: declare void @takeMyABINewType(%struct.__CFString*) #0
92+
// CHECK: declare void @takeMyABIOldType(%struct.__CFString*) #0
93+
//
94+
// CHECK: declare void @takeMyABINewTypeNonNull(%struct.__CFString*) #0
95+
// CHECK: declare void @takeMyABIOldTypeNonNull(%struct.__CFString*) #0
96+
//
97+
// CHECK: declare %0* @getMyABINewTypeNS() #0
98+
// CHECK: declare %0* @getMyABIOldTypeNS() #0
99+
//
100+
// CHECK: declare void @takeMyABINewTypeNonNullNS(%0*) #0
101+
// CHECK: declare void @takeMyABIOldTypeNonNullNS(%0*) #0
102+
}

0 commit comments

Comments
 (0)