Skip to content

Commit 53118e9

Browse files
committed
Split the "Foreign" flag into a ForeignKind enum.
This flag tracks whether we have a special kind of imported class that has limitations in what you can do with it. Currently it's used for two things: CF classes, and the magic "Protocol" class used to represent Objective-C protocol metadata. I'm planning to add a third to handle classes with the recently-added objc_runtime_visible attribute, which describes an Objective-C class whose runtime symbols are hidden (forcibly preventing categories and subclassing). This is used for some of the types in Dispatch, which has exposed some of the classes that were considered implementation details on past OSs. I'm splitting the flag into an enum rather than just marking the Dispatch classes with the existing flag because we still need to be able to /cast/ to the Dispatch types (which you can't do with CF types today) and because they deserve better than to be lumped in with CF for diagnostic purposes. Groundwork for rdar://problem/26850367, which is that Swift will happily let you extend the new Dispatch classes but then fails to find the symbols at link-time.
1 parent c6a5223 commit 53118e9

File tree

16 files changed

+85
-52
lines changed

16 files changed

+85
-52
lines changed

include/swift/AST/Decl.h

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -458,8 +458,8 @@ class alignas(1 << DeclAlignInBits) Decl {
458458
/// This is a value of \c StoredInheritsSuperclassInits.
459459
unsigned InheritsSuperclassInits : 2;
460460

461-
/// Whether this class is "foreign".
462-
unsigned Foreign : 1;
461+
/// \see ClassDecl::ForeignKind
462+
unsigned RawForeignKind : 2;
463463

464464
/// Whether this class contains a destructor decl.
465465
///
@@ -468,7 +468,7 @@ class alignas(1 << DeclAlignInBits) Decl {
468468
/// control inserting the implicit destructor.
469469
unsigned HasDestructorDecl : 1;
470470
};
471-
enum { NumClassDeclBits = NumNominalTypeDeclBits + 7 };
471+
enum { NumClassDeclBits = NumNominalTypeDeclBits + 8 };
472472
static_assert(NumClassDeclBits <= 32, "fits in an unsigned");
473473

474474
class StructDeclBitfields {
@@ -3238,6 +3238,19 @@ class ClassDecl : public NominalTypeDecl {
32383238
ClassDeclBits.RequiresStoredPropertyInits = requiresInits;
32393239
}
32403240

3241+
/// \see getForeignClassKind
3242+
enum class ForeignKind : uint8_t {
3243+
/// A normal Swift or Objective-C class.
3244+
Normal = 0,
3245+
/// An imported Core Foundation type. These are AnyObject-compatible but
3246+
/// do not have runtime metadata.
3247+
CFType,
3248+
/// An imported Objective-C type whose class and metaclass symbols are not
3249+
/// both available at link-time but can be accessed through the Objective-C
3250+
/// runtime.
3251+
RuntimeOnly
3252+
};
3253+
32413254
/// Whether this class is "foreign", meaning that it is implemented
32423255
/// by a runtime that Swift does not have first-class integration
32433256
/// with. This generally means that:
@@ -3248,11 +3261,18 @@ class ClassDecl : public NominalTypeDecl {
32483261
///
32493262
/// We may find ourselves wanting to break this bit into more
32503263
/// precise chunks later.
3251-
bool isForeign() const {
3252-
return ClassDeclBits.Foreign;
3264+
ForeignKind getForeignClassKind() const {
3265+
return static_cast<ForeignKind>(ClassDeclBits.RawForeignKind);
3266+
}
3267+
void setForeignClassKind(ForeignKind kind) {
3268+
ClassDeclBits.RawForeignKind = static_cast<unsigned>(kind);
32533269
}
3254-
void setForeign(bool isForeign = true) {
3255-
ClassDeclBits.Foreign = isForeign;
3270+
3271+
/// Returns true if this class is any kind of "foreign class".
3272+
///
3273+
/// \see getForeignClassKind
3274+
bool isForeign() const {
3275+
return getForeignClassKind() != ForeignKind::Normal;
32563276
}
32573277

32583278
/// Find a method of a class that overrides a given method.

include/swift/Serialization/ModuleFormat.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ const uint16_t VERSION_MAJOR = 0;
5353
/// in source control, you should also update the comment to briefly
5454
/// describe what change you made. The content of this comment isn't important;
5555
/// it just ensures a conflict if two people change the module format.
56-
const uint16_t VERSION_MINOR = 251; // Last change: SILFunctionType::isPseudogeneric
56+
const uint16_t VERSION_MINOR = 252; // Last change: remove class's "foreign" field
5757

5858
using DeclID = PointerEmbeddedInt<unsigned, 31>;
5959
using DeclIDField = BCFixed<31>;
@@ -816,7 +816,6 @@ namespace decls_block {
816816
BCFixed<1>, // implicit?
817817
BCFixed<1>, // explicitly objc?
818818
BCFixed<1>, // requires stored property initial values
819-
BCFixed<1>, // foreign
820819
TypeIDField, // superclass
821820
AccessibilityKindField, // accessibility
822821
BCVBR<4>, // number of conformances

lib/AST/Decl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2231,7 +2231,7 @@ ClassDecl::ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc,
22312231
ClassDeclBits.RequiresStoredPropertyInits = 0;
22322232
ClassDeclBits.InheritsSuperclassInits
22332233
= static_cast<unsigned>(StoredInheritsSuperclassInits::Unchecked);
2234-
ClassDeclBits.Foreign = false;
2234+
ClassDeclBits.RawForeignKind = 0;
22352235
ClassDeclBits.HasDestructorDecl = 0;
22362236
}
22372237

lib/ClangImporter/ImportDecl.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,7 +1243,7 @@ namespace {
12431243
theClass->setSuperclass(superclass);
12441244
theClass->setCheckedInheritanceClause();
12451245
theClass->setAddedImplicitInitializers(); // suppress all initializers
1246-
theClass->setForeign(true);
1246+
theClass->setForeignClassKind(ClassDecl::ForeignKind::CFType);
12471247
addObjCAttribute(theClass, None);
12481248
Impl.registerExternalDecl(theClass);
12491249

@@ -5660,7 +5660,8 @@ namespace {
56605660
nsObjectTy->getClassOrBoundGenericClass();
56615661

56625662
auto result = createRootClass(nsObjectDecl->getDeclContext());
5663-
result->setForeign(true);
5663+
// FIXME: Should use RuntimeOnly.
5664+
result->setForeignClassKind(ClassDecl::ForeignKind::CFType);
56645665
return result;
56655666
}
56665667

lib/IRGen/GenDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2845,7 +2845,7 @@ void IRGenModule::emitExtension(ExtensionDecl *ext) {
28452845

28462846
if (shouldEmitCategory(*this, ext)) {
28472847
assert(origClass && !origClass->isForeign() &&
2848-
"CF types cannot have categories emitted");
2848+
"foreign types cannot have categories emitted");
28492849
llvm::Constant *category = emitCategoryData(*this, ext);
28502850
category = llvm::ConstantExpr::getBitCast(category, Int8PtrTy);
28512851
ObjCCategories.push_back(category);

lib/IRGen/GenMeta.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5438,6 +5438,7 @@ IRGenModule::getAddrOfForeignTypeMetadataCandidate(CanType type) {
54385438
if (auto classType = dyn_cast<ClassType>(type)) {
54395439
assert(!classType.getParent());
54405440
auto classDecl = classType->getDecl();
5441+
// FIXME: Differentiate between the different kinds of foreign classes.
54415442
assert(classDecl->isForeign());
54425443

54435444
ForeignClassMetadataBuilder builder(*this, classDecl);

lib/PrintAsObjC/PrintAsObjC.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,8 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
611611
if (auto weakTy = ty->getAs<WeakStorageType>()) {
612612
auto innerTy = weakTy->getReferentType()->getAnyOptionalObjectType();
613613
auto innerClass = innerTy->getClassOrBoundGenericClass();
614-
if ((innerClass && !innerClass->isForeign()) ||
614+
if ((innerClass &&
615+
innerClass->getForeignClassKind()!=ClassDecl::ForeignKind::CFType) ||
615616
(innerTy->isObjCExistentialType() && !isCFTypeRef(innerTy))) {
616617
os << ", weak";
617618
}
@@ -653,7 +654,8 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
653654
break;
654655
}
655656
} else if ((dyn_cast_or_null<ClassDecl>(nominal) &&
656-
!cast<ClassDecl>(nominal)->isForeign()) ||
657+
cast<ClassDecl>(nominal)->getForeignClassKind() !=
658+
ClassDecl::ForeignKind::CFType) ||
657659
(copyTy->isObjCExistentialType() && !isCFTypeRef(copyTy))) {
658660
os << ", strong";
659661
}
@@ -1617,8 +1619,10 @@ class ModuleWriter {
16171619
}
16181620

16191621
bool forwardDeclare(const ClassDecl *CD) {
1620-
if (!CD->isObjC() || CD->isForeign())
1622+
if (!CD->isObjC() ||
1623+
CD->getForeignClassKind() == ClassDecl::ForeignKind::CFType) {
16211624
return false;
1625+
}
16221626
forwardDeclare(CD, [&]{ os << "@class " << getNameForObjC(CD) << ";\n"; });
16231627
return true;
16241628
}

lib/SIL/SILFunctionType.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -401,18 +401,24 @@ enum class ConventionsKind : uint8_t {
401401

402402
if (clangTy->getPointeeType()->getAs<clang::RecordType>()) {
403403
// CF type as foreign class
404-
if (substTy->getClassOrBoundGenericClass()
405-
&& substTy->getClassOrBoundGenericClass()->isForeign())
404+
if (substTy->getClassOrBoundGenericClass() &&
405+
substTy->getClassOrBoundGenericClass()->getForeignClassKind() ==
406+
ClassDecl::ForeignKind::CFType) {
406407
return false;
408+
}
407409
// swift_newtype-ed CF type as foreign class
408410
if (auto typedefTy = clangTy->getAs<clang::TypedefType>()) {
409411
if (typedefTy->getDecl()->getAttr<clang::SwiftNewtypeAttr>()) {
410412
// Make sure that we actually made the struct during import
411413
if (auto underlyingType =
412414
substTy->getSwiftNewtypeUnderlyingType()) {
413-
if (underlyingType->getClassOrBoundGenericClass() &&
414-
underlyingType->getClassOrBoundGenericClass()->isForeign())
415-
return false;
415+
if (auto underlyingClass =
416+
underlyingType->getClassOrBoundGenericClass()) {
417+
if (underlyingClass->getForeignClassKind() ==
418+
ClassDecl::ForeignKind::CFType) {
419+
return false;
420+
}
421+
}
416422
}
417423
}
418424
}

lib/SILGen/SILGenPoly.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,8 @@ ManagedValue Transform::transform(ManagedValue v,
459459
auto class2 = outputSubstType->getClassOrBoundGenericClass();
460460

461461
// CF <-> Objective-C via toll-free bridging.
462-
if (class1->isForeign() != class2->isForeign()) {
462+
if ((class1->getForeignClassKind() == ClassDecl::ForeignKind::CFType) ^
463+
(class2->getForeignClassKind() == ClassDecl::ForeignKind::CFType)) {
463464
return ManagedValue(SGF.B.createUncheckedRefCast(Loc,
464465
v.getValue(),
465466
loweredResultTy),

lib/Sema/CSApply.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2886,7 +2886,8 @@ namespace {
28862886
case CheckedCastKind::ValueCast:
28872887
// Check the cast target is a non-foreign type
28882888
if (auto cls = toType->getAs<ClassType>()) {
2889-
if (cls->getDecl()->isForeign()) {
2889+
if (cls->getDecl()->getForeignClassKind() ==
2890+
ClassDecl::ForeignKind::CFType) {
28902891
tc.diagnose(expr->getLoc(), diag::isa_is_foreign_check, toType);
28912892
}
28922893
}
@@ -2975,7 +2976,8 @@ namespace {
29752976
if (auto metaTy = destObjectType->getAs<MetatypeType>())
29762977
destObjectType = metaTy->getInstanceType();
29772978
if (auto destClass = destObjectType->getClassOrBoundGenericClass()) {
2978-
if (destClass->isForeign()) {
2979+
if (destClass->getForeignClassKind() ==
2980+
ClassDecl::ForeignKind::CFType) {
29792981
if (SuppressDiagnostics)
29802982
return nullptr;
29812983

0 commit comments

Comments
 (0)