AST: Static properties of fixed-layout types are resilient

We don't want @_fixed_layout to apply to static properties, or you
get fun consequences like not being able to change static stored
properties defined in extensions of imported types to computed.
This commit is contained in:
Slava Pestov
2018-01-20 21:22:58 -08:00
parent 834a121b10
commit 8f9f7afc55
7 changed files with 117 additions and 21 deletions

View File

@@ -4310,12 +4310,19 @@ public:
AccessStrategy getAccessStrategy(AccessSemantics semantics, AccessStrategy getAccessStrategy(AccessSemantics semantics,
AccessKind accessKind) const; AccessKind accessKind) const;
/// \brief Do we need to use resilient access patterns outside of this type's /// \brief Should this declaration behave as if it must be accessed
/// resilience domain? /// 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; bool isResilient() const;
/// \brief Do we need to use resilient access patterns when accessing this /// \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; bool isResilient(ModuleDecl *M, ResilienceExpansion expansion) const;
/// Does the storage use a behavior? /// Does the storage use a behavior?

View File

@@ -1472,16 +1472,10 @@ bool ValueDecl::isOutermostPrivateOrFilePrivateScope() const {
!isInPrivateOrLocalContext(this); !isInPrivateOrLocalContext(this);
} }
bool AbstractStorageDecl::isResilient() const { bool AbstractStorageDecl::isFormallyResilient() const {
// If we're in a nominal type, just query the type. // Check for an explicit @_fixed_layout attribute.
auto *dc = getDeclContext(); if (getAttrs().hasAttribute<FixedLayoutAttr>())
return false;
if (dc->isTypeContext()) {
auto *nominalDecl = dc->getAsNominalTypeOrNominalTypeExtensionContext();
if (nominalDecl == nullptr)
return false;
return nominalDecl->isResilient();
}
// Private and (unversioned) internal variables always have a // Private and (unversioned) internal variables always have a
// fixed layout. // fixed layout.
@@ -1489,12 +1483,19 @@ bool AbstractStorageDecl::isResilient() const {
/*respectVersionedAttr=*/true).isPublic()) /*respectVersionedAttr=*/true).isPublic())
return false; return false;
// Check for an explicit @_fixed_layout attribute. // If we're an instance property of a nominal type, query the type.
if (getAttrs().hasAttribute<FixedLayoutAttr>()) auto *dc = getDeclContext();
if (!isStatic())
if (auto *nominalDecl = dc->getAsNominalTypeOrNominalTypeExtensionContext())
return nominalDecl->isResilient();
return true;
}
bool AbstractStorageDecl::isResilient() const {
if (!isFormallyResilient())
return false; return false;
// Must use resilient access patterns.
assert(getDeclContext()->isModuleScopeContext());
switch (getDeclContext()->getParentModule()->getResilienceStrategy()) { switch (getDeclContext()->getParentModule()->getResilienceStrategy()) {
case ResilienceStrategy::Resilient: case ResilienceStrategy::Resilient:
return true; return true;

View File

@@ -276,9 +276,8 @@ static void maybeMarkTransparent(FuncDecl *accessor,
if (!nominalDecl) if (!nominalDecl)
return; return;
// Accessors for stored properties of resilient types are not // Accessors for resilient properties are not @_transparent.
// @_transparent. if (storage->isResilient())
if (nominalDecl->isResilient())
return; return;
// Accessors for protocol storage requirements are never @_transparent // Accessors for protocol storage requirements are never @_transparent

View File

@@ -48,3 +48,24 @@ private let privateGlobal = 0
struct AnotherInternalStruct { struct AnotherInternalStruct {
var storedProperty = privateGlobal 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
}

View File

@@ -34,7 +34,7 @@ public struct ChangeStoredToComputed {
} }
} }
public var fahrenheit: Int = 32 public var fahrenheit: Int
} }
#endif #endif

View File

@@ -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

View File

@@ -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()