Skip to content

Commit 3b6e40c

Browse files
committed
Use ClassDecl::ForeignKind to model Clang's objc_runtime_visible.
We're now correctly checking for inheritance, adding @objc methods, and adding @objc protocols for both CF types and objc_runtime_visible classes (those without visible symbols). The latter is used for some of the types in Dispatch, which has exposed some of the classes that were considered implementation details on past OSs. We still don't properly implement using 'as?' to check conformance to a Swift protocol for a CF or objc_runtime_visible type, but we can do that later. rdar://problem/26850367
1 parent 53118e9 commit 3b6e40c

File tree

16 files changed

+235
-65
lines changed

16 files changed

+235
-65
lines changed

include/swift/AST/Decl.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3315,10 +3315,6 @@ class ClassDecl : public NominalTypeDecl {
33153315
/// the Objective-C runtime.
33163316
StringRef getObjCRuntimeName(llvm::SmallVectorImpl<char> &buffer) const;
33173317

3318-
/// Determine whether the class is only visible to the Objective-C runtime
3319-
/// and not to the linker.
3320-
bool isOnlyObjCRuntimeVisible() const;
3321-
33223318
/// Returns the appropriate kind of entry point to generate for this class,
33233319
/// based on its attributes.
33243320
///

include/swift/AST/DiagnosticsSema.def

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1166,10 +1166,14 @@ NOTE(types_not_equal_requirement,none,
11661166
ERROR(non_class_cannot_conform_to_class_protocol,none,
11671167
"non-class type %0 cannot conform to class protocol %1",
11681168
(Type, Type))
1169-
ERROR(foreign_class_cannot_conform_to_objc_protocol,none,
1169+
ERROR(cf_class_cannot_conform_to_objc_protocol,none,
11701170
"Core Foundation class %0 cannot conform to @objc protocol %1 because "
11711171
"Core Foundation types are not classes in Objective-C",
11721172
(Type, Type))
1173+
ERROR(objc_runtime_visible_cannot_conform_to_objc_protocol,none,
1174+
"class %0 cannot conform to @objc protocol %1 because "
1175+
"the class is only visible via the Objective-C runtime",
1176+
(Type, Type))
11731177
ERROR(protocol_has_missing_requirements,none,
11741178
"type %0 cannot conform to protocol %1 because it has requirements that "
11751179
"cannot be satisfied", (Type, Type))
@@ -1577,8 +1581,11 @@ ERROR(inheritance_from_final_class,none,
15771581
ERROR(inheritance_from_unspecialized_objc_generic_class,none,
15781582
"inheritance from a generic Objective-C class %0 must bind "
15791583
"type parameters of %0 to specific concrete types", (Identifier))
1584+
ERROR(inheritance_from_cf_class,none,
1585+
"cannot inherit from Core Foundation type %0", (Identifier))
15801586
ERROR(inheritance_from_objc_runtime_visible_class,none,
1581-
"inheritance from an Objective-C class %0 only visible via the runtime", (Identifier))
1587+
"cannot inherit from class %0 because it is only visible via the "
1588+
"Objective-C runtime", (Identifier))
15821589

15831590

15841591
// Enums
@@ -2606,8 +2613,6 @@ ERROR(objc_in_extension_context,none,
26062613
"members of constrained extensions cannot be declared @objc", ())
26072614
ERROR(objc_in_generic_extension,none,
26082615
"@objc is not supported within extensions of generic classes", ())
2609-
ERROR(objc_in_objc_runtime_visible,none,
2610-
"@objc is not supported within extensions of classes only visible via the Objective-C runtime", ())
26112616

26122617
ERROR(objc_for_generic_class,none,
26132618
"generic subclasses of '@objc' classes cannot have an explicit '@objc' "
@@ -2728,6 +2733,11 @@ ERROR(objc_invalid_on_failing_init,none,
27282733
"%" OBJC_ATTR_SELECT "0 because 'nil' indicates failure to Objective-C",
27292734
(unsigned))
27302735

2736+
ERROR(objc_in_objc_runtime_visible,none,
2737+
"%0 cannot be %" OBJC_ATTR_SELECT "1 because class %2 is only visible "
2738+
"via the Objective-C runtime",
2739+
(DescriptiveDeclKind, unsigned, Identifier))
2740+
27312741
ERROR(objc_override_method_selector_mismatch,none,
27322742
"Objective-C method has a different selector from the "
27332743
"method it overrides (%0 vs. %1)", (ObjCSelector, ObjCSelector))

lib/AST/Decl.cpp

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2398,19 +2398,6 @@ StringRef ClassDecl::getObjCRuntimeName(
23982398
return mangleObjCRuntimeName(this, buffer);
23992399
}
24002400

2401-
bool ClassDecl::isOnlyObjCRuntimeVisible() const {
2402-
auto clangDecl = getClangDecl();
2403-
if (!clangDecl) return false;
2404-
2405-
auto objcClass = dyn_cast<clang::ObjCInterfaceDecl>(clangDecl);
2406-
if (!objcClass) return false;
2407-
2408-
if (auto def = objcClass->getDefinition())
2409-
objcClass = def;
2410-
2411-
return objcClass->hasAttr<clang::ObjCRuntimeVisibleAttr>();
2412-
}
2413-
24142401
ArtificialMainKind ClassDecl::getArtificialMainKind() const {
24152402
if (getAttrs().hasAttribute<UIApplicationMainAttr>())
24162403
return ArtificialMainKind::UIApplicationMain;

lib/ClangImporter/ImportDecl.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5660,8 +5660,7 @@ namespace {
56605660
nsObjectTy->getClassOrBoundGenericClass();
56615661

56625662
auto result = createRootClass(nsObjectDecl->getDeclContext());
5663-
// FIXME: Should use RuntimeOnly.
5664-
result->setForeignClassKind(ClassDecl::ForeignKind::CFType);
5663+
result->setForeignClassKind(ClassDecl::ForeignKind::RuntimeOnly);
56655664
return result;
56665665
}
56675666

@@ -5732,6 +5731,8 @@ namespace {
57325731

57335732
if (declaredNative)
57345733
markMissingSwiftDecl(result);
5734+
if (decl->getAttr<clang::ObjCRuntimeVisibleAttr>())
5735+
result->setForeignClassKind(ClassDecl::ForeignKind::RuntimeOnly);
57355736

57365737
// If this Objective-C class has a supertype, import it.
57375738
SmallVector<TypeLoc, 4> inheritedTypes;

lib/IRGen/GenCast.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,10 @@ llvm::Value *irgen::emitClassDowncast(IRGenFunction &IGF, llvm::Value *from,
163163
break;
164164
}
165165

166-
// If the destination type is a foreign class or a non-specific
166+
// If the destination type is a CF type or a non-specific
167167
// class-bounded archetype, use the most general cast entrypoint.
168-
} else if (toType.is<ArchetypeType>() || destClass->isForeign()) {
168+
} else if (toType.is<ArchetypeType>() ||
169+
destClass->getForeignClassKind()==ClassDecl::ForeignKind::CFType) {
169170
metadataRef = IGF.emitTypeMetadataRef(toType.getSwiftRValueType());
170171

171172
switch (mode) {

lib/IRGen/GenDecl.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2272,6 +2272,7 @@ Address IRGenModule::getAddrOfObjCClassRef(ClassDecl *theClass) {
22722272
llvm::Constant *IRGenModule::getAddrOfObjCClass(ClassDecl *theClass,
22732273
ForDefinition_t forDefinition) {
22742274
assert(ObjCInterop && "getting address of ObjC class in no-interop mode");
2275+
assert(!theClass->isForeign());
22752276
LinkEntity entity = LinkEntity::forObjCClass(theClass);
22762277
DebugTypeInfo DbgTy(theClass, ObjCClassPtrTy,
22772278
getPointerSize(), getPointerAlignment());
@@ -2285,6 +2286,7 @@ llvm::Constant *IRGenModule::getAddrOfObjCClass(ClassDecl *theClass,
22852286
llvm::Constant *IRGenModule::getAddrOfObjCMetaclass(ClassDecl *theClass,
22862287
ForDefinition_t forDefinition) {
22872288
assert(ObjCInterop && "getting address of ObjC metaclass in no-interop mode");
2289+
assert(!theClass->isForeign());
22882290
LinkEntity entity = LinkEntity::forObjCMetaclass(theClass);
22892291
DebugTypeInfo DbgTy(theClass, ObjCClassPtrTy,
22902292
getPointerSize(), getPointerAlignment());

lib/IRGen/GenMeta.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -292,10 +292,8 @@ llvm::Constant *irgen::tryEmitConstantHeapMetadataRef(IRGenModule &IGM,
292292
if (doesClassMetadataRequireDynamicInitialization(IGM, theDecl))
293293
return nullptr;
294294

295-
// Otherwise, just respect genericity and Objective-C runtime visibility.
296-
} else if ((theDecl->isGenericContext()
297-
&& !isTypeErasedGenericClass(theDecl))
298-
|| theDecl->isOnlyObjCRuntimeVisible()) {
295+
// Otherwise, just respect genericity.
296+
} else if (theDecl->isGenericContext() && !isTypeErasedGenericClass(theDecl)){
299297
return nullptr;
300298
}
301299

@@ -331,13 +329,15 @@ llvm::Value *irgen::emitObjCHeapMetadataRef(IRGenFunction &IGF,
331329
bool allowUninitialized) {
332330
// If the class is visible only through the Objective-C runtime, form the
333331
// appropriate runtime call.
334-
if (theClass->isOnlyObjCRuntimeVisible()) {
332+
if (theClass->getForeignClassKind() == ClassDecl::ForeignKind::RuntimeOnly) {
335333
SmallString<64> scratch;
336334
auto className =
337335
IGF.IGM.getAddrOfGlobalString(theClass->getObjCRuntimeName(scratch));
338336
return IGF.Builder.CreateCall(IGF.IGM.getLookUpClassFn(), className);
339337
}
340338

339+
assert(!theClass->isForeign());
340+
341341
Address classRef = IGF.IGM.getAddrOfObjCClassRef(theClass);
342342
auto classObject = IGF.Builder.CreateLoad(classRef);
343343
if (allowUninitialized) return classObject;
@@ -5438,7 +5438,6 @@ 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.
54425441
assert(classDecl->isForeign());
54435442

54445443
ForeignClassMetadataBuilder builder(*this, classDecl);

lib/Sema/TypeCheckDecl.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1934,8 +1934,8 @@ static Optional<ObjCReason> shouldMarkAsObjC(TypeChecker &TC,
19341934
// as @objc, don't diagnose.
19351935
Type contextTy = VD->getDeclContext()->getDeclaredTypeInContext();
19361936
if (auto classDecl = contextTy->getClassOrBoundGenericClass()) {
1937-
// One cannot define @objc members of Objective-C runtime visible classes.
1938-
if (classDecl->isOnlyObjCRuntimeVisible())
1937+
// One cannot define @objc members of any foreign classes.
1938+
if (classDecl->isForeign())
19391939
return None;
19401940

19411941
if (classDecl->checkObjCAncestry() != ObjCClassKind::NonObjC)
@@ -3722,9 +3722,17 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
37223722
Super->getName());
37233723
}
37243724

3725-
if (Super->isOnlyObjCRuntimeVisible()) {
3725+
switch (Super->getForeignClassKind()) {
3726+
case ClassDecl::ForeignKind::Normal:
3727+
break;
3728+
case ClassDecl::ForeignKind::CFType:
3729+
TC.diagnose(CD, diag::inheritance_from_cf_class,
3730+
Super->getName());
3731+
break;
3732+
case ClassDecl::ForeignKind::RuntimeOnly:
37263733
TC.diagnose(CD, diag::inheritance_from_objc_runtime_visible_class,
37273734
Super->getName());
3735+
break;
37283736
}
37293737
}
37303738

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3950,15 +3950,26 @@ checkConformsToProtocol(TypeChecker &TC,
39503950
// Foreign classes cannot conform to objc protocols.
39513951
if (Proto->isObjC() &&
39523952
!Proto->isSpecificProtocol(KnownProtocolKind::AnyObject)) {
3953-
if (auto clas = canT->getClassOrBoundGenericClass())
3954-
if (clas->getForeignClassKind() != ClassDecl::ForeignKind::Normal) {
3955-
// FIXME: Customize the error message for different foreign class kinds.
3956-
TC.diagnose(ComplainLoc,
3957-
diag::foreign_class_cannot_conform_to_objc_protocol,
3953+
if (auto clas = canT->getClassOrBoundGenericClass()) {
3954+
Optional<decltype(diag::cf_class_cannot_conform_to_objc_protocol)>
3955+
diagKind;
3956+
switch (clas->getForeignClassKind()) {
3957+
case ClassDecl::ForeignKind::Normal:
3958+
break;
3959+
case ClassDecl::ForeignKind::CFType:
3960+
diagKind = diag::cf_class_cannot_conform_to_objc_protocol;
3961+
break;
3962+
case ClassDecl::ForeignKind::RuntimeOnly:
3963+
diagKind = diag::objc_runtime_visible_cannot_conform_to_objc_protocol;
3964+
break;
3965+
}
3966+
if (diagKind) {
3967+
TC.diagnose(ComplainLoc, diagKind.getValue(),
39583968
T, Proto->getDeclaredType());
39593969
conformance->setInvalid();
39603970
return conformance;
39613971
}
3972+
}
39623973
}
39633974

39643975
// If the protocol contains missing requirements, it can't be conformed to

lib/Sema/TypeCheckType.cpp

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2648,14 +2648,6 @@ static bool checkObjCInExtensionContext(TypeChecker &tc,
26482648
return true;
26492649
}
26502650

2651-
// Cannot define @objc members of an Objective-C runtime visible class,
2652-
// because doing so would create a category.
2653-
if (CD->isOnlyObjCRuntimeVisible()) {
2654-
if (diagnose)
2655-
tc.diagnose(value, diag::objc_in_objc_runtime_visible);
2656-
return true;
2657-
}
2658-
26592651
extendedTy = CD->getSuperclass();
26602652
}
26612653
}
@@ -2699,15 +2691,28 @@ static bool checkObjCInForeignClassContext(TypeChecker &TC,
26992691
if (!clas)
27002692
return false;
27012693

2702-
if (clas->getForeignClassKind() == ClassDecl::ForeignKind::Normal)
2694+
switch (clas->getForeignClassKind()) {
2695+
case ClassDecl::ForeignKind::Normal:
27032696
return false;
27042697

2705-
if (Diagnose) {
2706-
// FIXME: Customize diagnostic here for various foreign class kinds.
2707-
TC.diagnose(VD->getLoc(), diag::objc_invalid_on_foreign_class,
2708-
getObjCDiagnosticAttrKind(Reason));
2709-
describeObjCReason(TC, VD, Reason);
2698+
case ClassDecl::ForeignKind::CFType:
2699+
if (Diagnose) {
2700+
TC.diagnose(VD, diag::objc_invalid_on_foreign_class,
2701+
getObjCDiagnosticAttrKind(Reason));
2702+
describeObjCReason(TC, VD, Reason);
2703+
}
2704+
break;
2705+
2706+
case ClassDecl::ForeignKind::RuntimeOnly:
2707+
if (Diagnose) {
2708+
TC.diagnose(VD, diag::objc_in_objc_runtime_visible,
2709+
VD->getDescriptiveKind(), getObjCDiagnosticAttrKind(Reason),
2710+
clas->getName());
2711+
describeObjCReason(TC, VD, Reason);
2712+
}
2713+
break;
27102714
}
2715+
27112716
return true;
27122717
}
27132718

0 commit comments

Comments
 (0)