Skip to content

Commit 4525d88

Browse files
committed
Diagnose resilient properties in objcImpl
…when the deployment target is not high enough to support them.
1 parent 69171ea commit 4525d88

File tree

5 files changed

+103
-3
lines changed

5 files changed

+103
-3
lines changed

include/swift/AST/DiagnosticsIRGen.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,5 +69,11 @@ NOTE(layout_strings_blocked,none,
6969
"Layout string value witnesses have been disabled for module '%0' "
7070
"through block list entry", (StringRef))
7171

72+
ERROR(attr_objc_implementation_resilient_property_unsupported, none,
73+
"'@implementation' on %0 %1 does not support stored properties whose "
74+
"size can change due to library evolution; raise the minimum deployment "
75+
"target to %0 %2 or store this value in an object or 'any' type",
76+
(StringRef, const llvm::VersionTuple, const llvm::VersionTuple))
77+
7278
#define UNDEFINE_DIAGNOSTIC_MACROS
7379
#include "DefineDiagnosticMacros.h"

include/swift/AST/FeatureAvailability.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ FEATURE(TaskExecutor, FUTURE)
7575
FEATURE(Differentiation, FUTURE)
7676
FEATURE(InitRawStructMetadata, FUTURE)
7777
FEATURE(ClearSensitive, FUTURE)
78+
FEATURE(UpdatePureObjCClassMetadata, FUTURE)
7879

7980
#undef FEATURE
8081
#undef FUTURE

lib/IRGen/GenMeta.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5057,13 +5057,81 @@ static void emitObjCClassSymbol(IRGenModule &IGM, ClassDecl *classDecl,
50575057
.to(alias, link.isForDefinition());
50585058
}
50595059

5060+
/// Check whether the metadata update strategy requires runtime support that is
5061+
/// not guaranteed available by the minimum deployment target, and diagnose if
5062+
/// so.
5063+
static void
5064+
diagnoseUnsupportedObjCImplLayout(IRGenModule &IGM, ClassDecl *classDecl,
5065+
const ClassLayout &fragileLayout) {
5066+
if (!fragileLayout.hasObjCImplementation())
5067+
return;
5068+
5069+
auto strategy = IGM.getClassMetadataStrategy(classDecl);
5070+
5071+
switch (strategy) {
5072+
case ClassMetadataStrategy::Fixed:
5073+
// Fixed is just fine; no special support needed.
5074+
break;
5075+
5076+
case ClassMetadataStrategy::FixedOrUpdate:
5077+
case ClassMetadataStrategy::Update: {
5078+
auto &ctx = IGM.Context;
5079+
5080+
// Update and FixedOrUpdate require support in both the Swift and ObjC
5081+
// runtimes.
5082+
auto requiredAvailability=ctx.getUpdatePureObjCClassMetadataAvailability();
5083+
// FIXME: Take the class's availability into account
5084+
auto currentAvailability = AvailabilityContext::forDeploymentTarget(ctx);
5085+
if (currentAvailability.isContainedIn(requiredAvailability))
5086+
break;
5087+
5088+
// We don't have the support we need. Find and diagnose the variable-size
5089+
// stored properties.
5090+
auto &diags = ctx.Diags;
5091+
5092+
bool diagnosed = false;
5093+
forEachField(IGM, classDecl, [&](Field field) {
5094+
auto elemLayout = fragileLayout.getFieldAccessAndElement(field).second;
5095+
if (field.getKind() != Field::Kind::Var ||
5096+
elemLayout.getType().isFixedSize())
5097+
return;
5098+
5099+
diags.diagnose(
5100+
field.getVarDecl(),
5101+
diag::attr_objc_implementation_resilient_property_unsupported,
5102+
prettyPlatformString(targetPlatform(ctx.LangOpts)),
5103+
currentAvailability.getOSVersion().getLowerEndpoint(),
5104+
requiredAvailability.getOSVersion().getLowerEndpoint());
5105+
diagnosed = true;
5106+
});
5107+
5108+
// We should have found at least one property to complain about.
5109+
if (diagnosed)
5110+
break;
5111+
5112+
LLVM_FALLTHROUGH;
5113+
}
5114+
5115+
case ClassMetadataStrategy::Singleton:
5116+
case ClassMetadataStrategy::Resilient:
5117+
// This isn't supposed to happen, but just in case, let's give some sort of
5118+
// vaguely legible output instead of using llvm_unreachable().
5119+
IGM.error(classDecl->getLoc(),
5120+
llvm::Twine("class '") + classDecl->getBaseIdentifier().str() +
5121+
"' needs a metadata strategy not supported by @implementation");
5122+
break;
5123+
}
5124+
}
5125+
50605126
/// Emit the type metadata or metadata template for a class.
50615127
void irgen::emitClassMetadata(IRGenModule &IGM, ClassDecl *classDecl,
50625128
const ClassLayout &fragileLayout,
50635129
const ClassLayout &resilientLayout) {
50645130
assert(!classDecl->isForeign());
50655131
PrettyStackTraceDecl stackTraceRAII("emitting metadata for", classDecl);
50665132

5133+
diagnoseUnsupportedObjCImplLayout(IGM, classDecl, fragileLayout);
5134+
50675135
emitFieldOffsetGlobals(IGM, classDecl, fragileLayout, resilientLayout);
50685136

50695137
// Set up a dummy global to stand in for the metadata object while we produce

test/IRGen/objc_implementation.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Test doesn't pass on all platforms (rdar://101420862)
22
// REQUIRES: OS=macosx
33

4-
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-experimental-feature CImplementation -I %S/Inputs/abi -F %clang-importer-sdk-path/frameworks %s -import-objc-header %S/Inputs/objc_implementation.h -emit-ir > %t.ir
4+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-experimental-feature CImplementation -I %S/Inputs/abi -F %clang-importer-sdk-path/frameworks %s -import-objc-header %S/Inputs/objc_implementation.h -emit-ir -target %target-future-triple > %t.ir
55
// RUN: %FileCheck --input-file %t.ir %s
66
// RUN: %FileCheck --input-file %t.ir --check-prefix NEGATIVE %s
77
// REQUIRES: objc_interop
@@ -17,7 +17,7 @@
1717

1818
// Metaclass
1919
// CHECK: @"OBJC_METACLASS_$_ImplClass" = global %objc_class { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, {{.*}}ptr [[_METACLASS_DATA_ImplClass:@[^, ]+]]{{.*}}, align 8
20-
// CHECK: @_PROTOCOLS_ImplClass = internal constant { i64, [2 x ptr] } { i64 2, [2 x ptr] [ptr @_PROTOCOL_NSCopying, ptr @_PROTOCOL_NSMutableCopying] }, section "__DATA, __objc_const", align 8
20+
// CHECK: @_PROTOCOLS_ImplClass = internal constant { i64, [2 x ptr] } { i64 2, [2 x ptr] [ptr @"_OBJC_PROTOCOL_$_NSCopying", ptr @"_OBJC_PROTOCOL_$_NSMutableCopying"] }, section "__DATA, __objc_const", align 8
2121
// CHECK: [[_METACLASS_DATA_ImplClass]] = internal constant { i32, i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr } { i32 129, i32 40, i32 40, i32 0, ptr null, ptr @.str.9.ImplClass, ptr null, ptr @_PROTOCOLS_ImplClass, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
2222
// TODO: Why the extra i32 field above?
2323

@@ -121,7 +121,7 @@
121121
// CHECK: @"$s19objc_implementationMXM" = linkonce_odr hidden constant <{ i32, i32, i32 }> <{ i32 0, i32 0, i32 trunc (i64 sub (i64 ptrtoint (ptr @.str.19.objc_implementation to i64), i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32, i32 }>, ptr @"$s19objc_implementationMXM", i32 0, i32 2) to i64)) to i32) }>, section "__TEXT,__constg_swiftt", align 4
122122
// CHECK: @"symbolic So9ImplClassC" = linkonce_odr hidden constant <{ [13 x i8], i8 }> <{ [13 x i8] c"So9ImplClassC", i8 0 }>, section "__TEXT,__swift5_typeref, regular"{{.*}}, align 2
123123
// CHECK: @"$s19objc_implementation13SwiftSubclassCMn" = constant <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }> <{ i32 80, i32 trunc (i64 sub (i64 ptrtoint (ptr @"$s19objc_implementationMXM" to i64), i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>, ptr @"$s19objc_implementation13SwiftSubclassCMn", i32 0, i32 1) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @.str.13.SwiftSubclass to i64), i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>, ptr @"$s19objc_implementation13SwiftSubclassCMn", i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @"$s19objc_implementation13SwiftSubclassCMa" to i64), i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>, ptr @"$s19objc_implementation13SwiftSubclassCMn", i32 0, i32 3) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @"$s19objc_implementation13SwiftSubclassCMF" to i64), i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>, ptr @"$s19objc_implementation13SwiftSubclassCMn", i32 0, i32 4) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @"symbolic So9ImplClassC" to i64), i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>, ptr @"$s19objc_implementation13SwiftSubclassCMn", i32 0, i32 5) to i64)) to i32), i32 3, i32 10, i32 0, i32 0, i32 10 }>, section "__TEXT,__constg_swiftt", align 4
124-
// CHECK: @"$s19objc_implementation13SwiftSubclassCMf" = internal global <{ ptr, ptr, ptr, i64, ptr, ptr, ptr, i64, i32, i32, i32, i16, i16, i32, i32, ptr, ptr }> <{ ptr null, ptr @"$s19objc_implementation13SwiftSubclassCfD", ptr @"$sBOWV", i64 ptrtoint (ptr @"OBJC_METACLASS_$__TtC19objc_implementation13SwiftSubclass" to i64), ptr @"OBJC_CLASS_$_ImplClass", ptr @_objc_empty_cache, ptr null, i64 add (i64 ptrtoint (ptr @_DATA__TtC19objc_implementation13SwiftSubclass to i64), i64 1), i32 0, i32 0, i32 24, i16 7, i16 0, i32 104, i32 24, ptr @"$s19objc_implementation13SwiftSubclassCMn", ptr null }>, section "__DATA,__objc_data, regular", align 8
124+
// CHECK: @"$s19objc_implementation13SwiftSubclassCMf" = internal global <{ ptr, ptr, ptr, i64, ptr, ptr, ptr, i64, i32, i32, i32, i16, i16, i32, i32, ptr, ptr }> <{ ptr null, ptr @"$s19objc_implementation13SwiftSubclassCfD", ptr @"$sBOWV", i64 ptrtoint (ptr @"OBJC_METACLASS_$__TtC19objc_implementation13SwiftSubclass" to i64), ptr @"OBJC_CLASS_$_ImplClass", ptr @_objc_empty_cache, ptr null, i64 add (i64 ptrtoint (ptr @_DATA__TtC19objc_implementation13SwiftSubclass to i64), i64 2), i32 0, i32 0, i32 24, i16 7, i16 0, i32 104, i32 24, ptr @"$s19objc_implementation13SwiftSubclassCMn", ptr null }>, section "__DATA,__objc_data, regular", align 8
125125
// CHECK: @"symbolic _____ 19objc_implementation13SwiftSubclassC" = linkonce_odr hidden constant <{ i8, i32, i8 }> <{ i8 1, i32 trunc (i64 sub (i64 ptrtoint (ptr @"$s19objc_implementation13SwiftSubclassCMn" to i64), i64 ptrtoint (ptr getelementptr inbounds (<{ i8, i32, i8 }>, ptr @"symbolic _____ 19objc_implementation13SwiftSubclassC", i32 0, i32 1) to i64)) to i32), i8 0 }>, section "__TEXT,__swift5_typeref, regular"{{.*}}, align 2
126126
// CHECK: @"$s19objc_implementation13SwiftSubclassCMF" = internal constant { i32, i32, i16, i16, i32 } { i32 trunc (i64 sub (i64 ptrtoint (ptr @"symbolic _____ 19objc_implementation13SwiftSubclassC" to i64), i64 ptrtoint (ptr @"$s19objc_implementation13SwiftSubclassCMF" to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @"symbolic So9ImplClassC" to i64), i64 ptrtoint (ptr getelementptr inbounds ({ i32, i32, i16, i16, i32 }, ptr @"$s19objc_implementation13SwiftSubclassCMF", i32 0, i32 1) to i64)) to i32), i16 7, i16 12, i32 0 }, section "__TEXT,__swift5_fieldmd, regular"{{.*}}, align 4
127127
open class SwiftSubclass: ImplClass {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -target %target-stable-abi-triple -I %S/Inputs/abi -F %clang-importer-sdk-path/frameworks %s -import-objc-header %S/Inputs/objc_implementation.h -emit-ir -o %t.ir -enable-library-evolution -verify
2+
// REQUIRES: objc_interop
3+
4+
@_objcImplementation extension ImplClassWithResilientStoredProperty {
5+
@objc var beforeInt: Int32 = 0 // no-error
6+
final var a: Mirror? // expected-error {{does not support stored properties whose size can change due to library evolution; raise the minimum deployment target to}}
7+
final var b: AnyKeyPath? // no-error
8+
final var c: Int = 0 // no-error
9+
final var d: S1? // no-error
10+
final var e: S2? // expected-error {{does not support stored properties whose size can change due to library evolution; raise the minimum deployment target to}}
11+
final var f: C1? // no-error
12+
@objc var afterInt: Int32 = 0 // no-error
13+
}
14+
15+
public struct S1 {
16+
var int = 1
17+
}
18+
19+
public struct S2 {
20+
var mirror: Mirror?
21+
}
22+
23+
public class C1 {
24+
var mirror: Mirror?
25+
}

0 commit comments

Comments
 (0)