Treat exhaustive enums as "non-resilient", and add a few more tests

"Formally non-resilient" in this new world means "the enum has a fixed
representation", which implies a fixed layout algorithm. We're not
there yet, but non-exhaustive enums should be able to be fixed-layout
as well by picking a general representation that won't need to grow.
Specifically, that's enums with raw types, and possibly also indirect
enums as well.

(It's likely the '_fixed_layout' /attribute/ on enums will go away,
but the concept of a fixed-layout enum is still useful.)
This commit is contained in:
Jordan Rose
2017-09-21 17:55:37 -07:00
parent 00361df52b
commit 7e3aaff78d
3 changed files with 34 additions and 8 deletions

View File

@@ -2286,9 +2286,11 @@ bool NominalTypeDecl::isFormallyResilient() const {
/*respectVersionedAttr=*/true).isPublic()) /*respectVersionedAttr=*/true).isPublic())
return false; return false;
// Check for an explicit @_fixed_layout attribute. // Check for an explicit @_fixed_layout or @_frozen attribute.
if (getAttrs().hasAttribute<FixedLayoutAttr>()) if (getAttrs().hasAttribute<FixedLayoutAttr>() ||
getAttrs().hasAttribute<FrozenAttr>()) {
return false; return false;
}
// Structs and enums imported from C *always* have a fixed layout. // Structs and enums imported from C *always* have a fixed layout.
// We know their size, and pass them as values in SIL and IRGen. // We know their size, and pass them as values in SIL and IRGen.

View File

@@ -38,7 +38,7 @@ public struct Reference {
public var n: Class public var n: Class
} }
@_fixed_layout public enum Either { @_frozen public enum Either {
case Left(Reference) case Left(Reference)
case Right(Reference) case Right(Reference)
} }
@@ -57,7 +57,7 @@ enum InternalEither {
public var n: Class public var n: Class
} }
@_fixed_layout public enum EitherFast { @_frozen public enum EitherFast {
case Left(ReferenceFast) case Left(ReferenceFast)
case Right(ReferenceFast) case Right(ReferenceFast)
} }
@@ -263,6 +263,25 @@ extension ResilientMultiPayloadGenericEnum {
} }
} }
// CHECK-LABEL: define{{( protected)?}} swiftcc void @"$S15enum_resilience39constructExhaustiveWithResilientMembers010resilient_A011SimpleShapeOyF"(%T14resilient_enum11SimpleShapeO* noalias nocapture sret)
// CHECK: [[BUFFER:%.*]] = bitcast %T14resilient_enum11SimpleShapeO* %0 to %swift.opaque*
// CHECK: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$S16resilient_struct4SizeVMa"([[INT]] 0)
// CHECK-NEXT: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
// CHECK: [[STORE_TAG:%.*]] = bitcast i8* {{%.+}} to void (%swift.opaque*, i32, i32, %swift.type*)*
// CHECK-NEXT: call void [[STORE_TAG]](%swift.opaque* noalias [[BUFFER]], i32 0, i32 1, %swift.type* [[METADATA]])
// CHECK-NEXT: ret void
// CHECK-NEXT: {{^}$}}
public func constructExhaustiveWithResilientMembers() -> SimpleShape {
return .KleinBottle
}
// CHECK-LABEL: define{{( protected)?}} swiftcc { i{{64|32}}, i8 } @"$S15enum_resilience19constructFullyFixed010resilient_A00dE6LayoutOyF"()
// CHECK: ret { [[INT]], i8 } { [[INT]] 0, i8 1 }
// CHECK-NEXT: {{^}$}}
public func constructFullyFixed() -> FullyFixedLayout {
return .noPayload
}
// CHECK-LABEL: define{{( protected)?}} private void @initialize_metadata_EnumWithResilientPayload(i8*) // CHECK-LABEL: define{{( protected)?}} private void @initialize_metadata_EnumWithResilientPayload(i8*)
// CHECK: call void @swift_initEnumMetadataMultiPayload(%swift.type* {{.*}}, [[INT]] 256, [[INT]] 2, i8*** {{.*}}) // CHECK: call void @swift_initEnumMetadataMultiPayload(%swift.type* {{.*}}, [[INT]] 256, [[INT]] 2, i8*** {{.*}})

View File

@@ -1,24 +1,29 @@
import resilient_struct import resilient_struct
// Fixed-layout enum with resilient members // Fixed-layout enum with resilient members
@_fixed_layout @_frozen public enum SimpleShape { @_frozen public enum SimpleShape {
case KleinBottle case KleinBottle
case Triangle(Size) case Triangle(Size)
} }
// Fixed-layout enum with resilient members // Fixed-layout enum with resilient members
@_fixed_layout @_frozen public enum Shape { @_frozen public enum Shape {
case Point case Point
case Rect(Size) case Rect(Size)
case RoundedRect(Size, Size) case RoundedRect(Size, Size)
} }
// Fixed-layout enum with indirect resilient members // Fixed-layout enum with indirect resilient members
@_fixed_layout @_frozen public enum FunnyShape { @_frozen public enum FunnyShape {
indirect case Parallelogram(Size) indirect case Parallelogram(Size)
indirect case Trapezoid(Size) indirect case Trapezoid(Size)
} }
@_frozen public enum FullyFixedLayout {
case noPayload
case hasPayload(Int)
}
// The enum payload has fixed layout inside this module, but // The enum payload has fixed layout inside this module, but
// resilient layout outside. Make sure we emit the payload // resilient layout outside. Make sure we emit the payload
// size in the metadata. // size in the metadata.
@@ -33,7 +38,7 @@ public struct Color {
} }
} }
@_fixed_layout @_frozen public enum CustomColor { @_frozen public enum CustomColor {
case Black case Black
case White case White
case Custom(Color) case Custom(Color)