diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 7d9678253f9..d1c4f99a89e 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -4310,12 +4310,19 @@ public: AccessStrategy getAccessStrategy(AccessSemantics semantics, AccessKind accessKind) const; - /// \brief Do we need to use resilient access patterns outside of this type's - /// resilience domain? + /// \brief Should this declaration behave as if it must be accessed + /// resiliently, even when we're building a non-resilient module? + /// + /// This is used for diagnostics, because we do not want a behavior + /// change between builds with resilience enabled and disabled. + bool isFormallyResilient() const; + + /// \brief Do we need to use resilient access patterns outside of this + /// property's resilience domain? bool isResilient() const; /// \brief Do we need to use resilient access patterns when accessing this - /// type from the given module? + /// property from the given module? bool isResilient(ModuleDecl *M, ResilienceExpansion expansion) const; /// Does the storage use a behavior? diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index dd6cca755f2..27598b803b6 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1472,16 +1472,10 @@ bool ValueDecl::isOutermostPrivateOrFilePrivateScope() const { !isInPrivateOrLocalContext(this); } -bool AbstractStorageDecl::isResilient() const { - // If we're in a nominal type, just query the type. - auto *dc = getDeclContext(); - - if (dc->isTypeContext()) { - auto *nominalDecl = dc->getAsNominalTypeOrNominalTypeExtensionContext(); - if (nominalDecl == nullptr) - return false; - return nominalDecl->isResilient(); - } +bool AbstractStorageDecl::isFormallyResilient() const { + // Check for an explicit @_fixed_layout attribute. + if (getAttrs().hasAttribute()) + return false; // Private and (unversioned) internal variables always have a // fixed layout. @@ -1489,12 +1483,19 @@ bool AbstractStorageDecl::isResilient() const { /*respectVersionedAttr=*/true).isPublic()) return false; - // Check for an explicit @_fixed_layout attribute. - if (getAttrs().hasAttribute()) + // If we're an instance property of a nominal type, query the type. + auto *dc = getDeclContext(); + if (!isStatic()) + if (auto *nominalDecl = dc->getAsNominalTypeOrNominalTypeExtensionContext()) + return nominalDecl->isResilient(); + + return true; +} + +bool AbstractStorageDecl::isResilient() const { + if (!isFormallyResilient()) return false; - // Must use resilient access patterns. - assert(getDeclContext()->isModuleScopeContext()); switch (getDeclContext()->getParentModule()->getResilienceStrategy()) { case ResilienceStrategy::Resilient: return true; diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index f4d1839576a..a8d1595bab5 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -276,9 +276,8 @@ static void maybeMarkTransparent(FuncDecl *accessor, if (!nominalDecl) return; - // Accessors for stored properties of resilient types are not - // @_transparent. - if (nominalDecl->isResilient()) + // Accessors for resilient properties are not @_transparent. + if (storage->isResilient()) return; // Accessors for protocol storage requirements are never @_transparent diff --git a/test/SILGen/fixed_layout_attribute.swift b/test/SILGen/fixed_layout_attribute.swift index cb46889b5a3..75a14c4dc1f 100644 --- a/test/SILGen/fixed_layout_attribute.swift +++ b/test/SILGen/fixed_layout_attribute.swift @@ -48,3 +48,24 @@ private let privateGlobal = 0 struct AnotherInternalStruct { var storedProperty = privateGlobal } + +// Static properties in fixed-layout type is still resilient + +@_fixed_layout +public struct HasStaticProperty { + public static var staticProperty: Int = 0 +} + +// CHECK-LABEL: sil @$S22fixed_layout_attribute18usesStaticPropertyyyF : $@convention(thin) () -> () +// CHECK: function_ref @$S22fixed_layout_attribute17HasStaticPropertyV06staticF0Sivau : $@convention(thin) () -> Builtin.RawPointer +// CHECK: return +public func usesStaticProperty() { + _ = HasStaticProperty.staticProperty +} + +// CHECK-LABEL: sil [serialized] @$S22fixed_layout_attribute28usesStaticPropertyInlineableyyF : $@convention(thin) () -> () + +@_inlineable +public func usesStaticPropertyInlineable() { + _ = HasStaticProperty.staticProperty +} diff --git a/validation-test/Evolution/Inputs/struct_change_stored_to_computed.swift b/validation-test/Evolution/Inputs/struct_change_stored_to_computed.swift index ac8eb1724bb..2f9bc590519 100644 --- a/validation-test/Evolution/Inputs/struct_change_stored_to_computed.swift +++ b/validation-test/Evolution/Inputs/struct_change_stored_to_computed.swift @@ -34,7 +34,7 @@ public struct ChangeStoredToComputed { } } - public var fahrenheit: Int = 32 + public var fahrenheit: Int } #endif diff --git a/validation-test/Evolution/Inputs/struct_change_stored_to_computed_static.swift b/validation-test/Evolution/Inputs/struct_change_stored_to_computed_static.swift new file mode 100644 index 00000000000..fdbdb07b2a5 --- /dev/null +++ b/validation-test/Evolution/Inputs/struct_change_stored_to_computed_static.swift @@ -0,0 +1,34 @@ + +#if BEFORE + +@_fixed_layout +public struct ChangeStoredToComputed { + public static var celsius: Int = 0 + + public static var fahrenheit: Int { + get { + return (celsius * 9) / 5 + 32 + } + set { + celsius = ((newValue - 32) * 5) / 9 + } + } +} + +#else + +@_fixed_layout +public struct ChangeStoredToComputed { + public static var celsius: Int { + get { + return ((fahrenheit - 32) * 5) / 9 + } + set { + fahrenheit = (newValue * 9) / 5 + 32 + } + } + + public static var fahrenheit: Int = 32 +} + +#endif diff --git a/validation-test/Evolution/test_struct_change_stored_to_computed_static.swift b/validation-test/Evolution/test_struct_change_stored_to_computed_static.swift new file mode 100644 index 00000000000..14a4a97ab97 --- /dev/null +++ b/validation-test/Evolution/test_struct_change_stored_to_computed_static.swift @@ -0,0 +1,34 @@ +// RUN: %target-resilience-test +// REQUIRES: executable_test + +import StdlibUnittest +import struct_change_stored_to_computed_static + + +var ChangeStoredToComputedTest = TestSuite("ChangeStoredToComputed") + +ChangeStoredToComputedTest.test("ChangeStoredToComputed") { + do { + expectEqual(ChangeStoredToComputed.celsius, 0) + expectEqual(ChangeStoredToComputed.fahrenheit, 32) + } + + do { + ChangeStoredToComputed.celsius = 10 + expectEqual(ChangeStoredToComputed.celsius, 10) + expectEqual(ChangeStoredToComputed.fahrenheit, 50) + } + + do { + func increaseTemperature(_ t: inout Int) { + t += 10 + } + + increaseTemperature(&ChangeStoredToComputed.celsius) + + expectEqual(ChangeStoredToComputed.celsius, 20) + expectEqual(ChangeStoredToComputed.fahrenheit, 68) + } +} + +runAllTests()