diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 3765b344febcc..90af8c8b3f198 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1367,6 +1367,15 @@ ERROR(pattern_binds_no_variables,none, "variables", (unsigned)) +ERROR(pattern_no_uninhabited_type,none, + "%select{%select{variable|constant}0|stored property}1 %2 cannot have " + "enum type %3 with no cases", + (bool, bool, Identifier, Type)) +ERROR(pattern_no_uninhabited_tuple_type,none, + "%select{%select{variable|constant}0|stored property}1 %2 cannot have " + "tuple type %3 containing enum with no cases", + (bool, bool, Identifier, Type)) + ERROR(nscoding_unstable_mangled_name,none, "%select{private|fileprivate|nested|local}0 class %1 has an " "unstable name when archiving via 'NSCoding'", diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index f993087abe611..d3c5939a79bed 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2461,6 +2461,25 @@ class DeclChecker : public DeclVisitor { } } + // Reject variable if it is a stored property with an uninhabited type + if (VD->hasStorage() && + VD->getInterfaceType()->isStructurallyUninhabited()) { + auto uninhabitedTypeDiag = diag::pattern_no_uninhabited_type; + + if (VD->getInterfaceType()->is()) { + uninhabitedTypeDiag = diag::pattern_no_uninhabited_tuple_type; + } else { + assert((VD->getInterfaceType()->is() || + VD->getInterfaceType()->is()) && + "unknown structurally uninhabited type"); + } + + TC.diagnose(VD->getLoc(), uninhabitedTypeDiag, VD->isLet(), + VD->isInstanceMember(), VD->getName(), + VD->getInterfaceType()); + VD->markInvalid(); + } + if (!checkOverrides(VD)) { // If a property has an override attribute but does not override // anything, complain. diff --git a/test/IRGen/generic_enums.swift b/test/IRGen/generic_enums.swift index 4d28aae8c7ca6..31286b399c338 100644 --- a/test/IRGen/generic_enums.swift +++ b/test/IRGen/generic_enums.swift @@ -6,4 +6,5 @@ struct Bar { } enum Foo{ + case bar } diff --git a/test/Reflection/Inputs/TypeLowering.swift b/test/Reflection/Inputs/TypeLowering.swift index c11b2575bf8db..7c8683925e289 100644 --- a/test/Reflection/Inputs/TypeLowering.swift +++ b/test/Reflection/Inputs/TypeLowering.swift @@ -144,8 +144,14 @@ public struct MetatypeStruct { public let abstractMetatype: MetadataHolder } +// We don't allow stored properties to have uninhabited types now, but make a +// wrapper over one to continue testing this public enum EmptyEnum {} +public struct EmptyEnumWrapper { + public var value: T +} + public enum NoPayloadEnum { case A case B @@ -194,7 +200,7 @@ public enum MultiPayloadGenericDynamic { } public struct EnumStruct { - public let empty: EmptyEnum + public let empty: EmptyEnumWrapper public let noPayload: NoPayloadEnum public let sillyNoPayload: SillyNoPayloadEnum public let singleton: SingletonEnum diff --git a/test/Reflection/typeref_lowering.swift b/test/Reflection/typeref_lowering.swift index b72c45be0701c..b15074409b1fc 100644 --- a/test/Reflection/typeref_lowering.swift +++ b/test/Reflection/typeref_lowering.swift @@ -926,7 +926,9 @@ // CHECK-64: (struct TypeLowering.EnumStruct) // CHECK-64-NEXT: (struct size=81 alignment=8 stride=88 num_extra_inhabitants=[[PTR_XI]] // CHECK-64-NEXT: (field name=empty offset=0 -// CHECK-64-NEXT: (no_payload_enum size=0 alignment=1 stride=1 num_extra_inhabitants=0)) +// CHECK-64-NEXT: (struct size=0 alignment=1 stride=1 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=value offset=0 +// CHECK-64-NEXT: (no_payload_enum size=0 alignment=1 stride=1 num_extra_inhabitants=0)))) // CHECK-64-NEXT: (field name=noPayload offset=0 // CHECK-64-NEXT: (no_payload_enum size=1 alignment=1 stride=1 num_extra_inhabitants=0)) // CHECK-64-NEXT: (field name=sillyNoPayload offset=1 diff --git a/test/attr/attr_noreturn.swift b/test/attr/attr_noreturn.swift index 8dea7613d6954..d68b44238024e 100644 --- a/test/attr/attr_noreturn.swift +++ b/test/attr/attr_noreturn.swift @@ -34,7 +34,8 @@ func noReturn3(_: Int) // expected-error@-2 {{'@noreturn' has been removed; functions that never return should have a return type of 'Never' instead}}{{1-11=}}{{53-56=Never}} // Test that error recovery gives us the 'Never' return type -let x: Never = noReturn1(0) // No error +let x: Never = noReturn1(0) +// expected-error@-1 {{constant 'x' cannot have enum type 'Never' with no cases}} // @noreturn in function type declarations let valueNoReturn: @noreturn () -> () diff --git a/test/attr/attr_objc.swift b/test/attr/attr_objc.swift index 49f74cdafa107..ac6a76a2583ff 100644 --- a/test/attr/attr_objc.swift +++ b/test/attr/attr_objc.swift @@ -941,11 +941,12 @@ class infer_instanceVar1 { // expected-note@-2 {{Swift structs cannot be represented in Objective-C}} var var_PlainEnum: PlainEnum -// CHECK-LABEL: {{^}} var var_PlainEnum: PlainEnum + // expected-error@-1 {{stored property 'var_PlainEnum' cannot have enum type 'PlainEnum' with no cases}} @objc var var_PlainEnum_: PlainEnum // expected-error@-1 {{property cannot be marked @objc because its type cannot be represented in Objective-C}} // expected-note@-2 {{non-'@objc' enums cannot be represented in Objective-C}} + // expected-error@-3 {{stored property 'var_PlainEnum_' cannot have enum type 'PlainEnum' with no cases}} var var_PlainProtocol: PlainProtocol // CHECK-LABEL: {{^}} var var_PlainProtocol: PlainProtocol @@ -1271,6 +1272,7 @@ class infer_instanceVar1 { // expected-error@-1 {{'unowned' may only be applied to class and class-bound protocol types, not 'PlainStruct'}} unowned var var_Unowned_bad3: PlainEnum // expected-error@-1 {{'unowned' may only be applied to class and class-bound protocol types, not 'PlainEnum'}} + // expected-error@-2 {{stored property 'var_Unowned_bad3' cannot have enum type 'PlainEnum' with no cases}} unowned var var_Unowned_bad4: String // expected-error@-1 {{'unowned' may only be applied to class and class-bound protocol types, not 'String'}} // CHECK-NOT: @objc{{.*}}Unowned_fail diff --git a/test/decl/var/properties.swift b/test/decl/var/properties.swift index 12ef699fc53e4..6e1f6f7e38008 100644 --- a/test/decl/var/properties.swift +++ b/test/decl/var/properties.swift @@ -1267,3 +1267,25 @@ class WeakFixItTest { // expected-error @+1 {{'weak' variable should have optional type '(WFI_P1 & WFI_P2)?'}} {{18-18=(}} {{33-33=)?}} weak var bar : WFI_P1 & WFI_P2 } + +// SR-8811 +// Stored properties cannot have uninhabited types + +struct SR8811 { + var x: Never // expected-error {{stored property 'x' cannot have enum type 'Never' with no cases}} + + var y: (Int, Never, Bool) // expected-error {{stored property 'y' cannot have tuple type '(Int, Never, Bool)' containing enum with no cases}} +} + +let sr8811x: Never // expected-error {{constant 'sr8811x' cannot have enum type 'Never' with no cases}} + +var sr8811y: (Int, Never) // expected-error {{variable 'sr8811y' cannot have tuple type '(Int, Never)' containing enum with no cases}} + +// Ok +var sr8811z: Never { + return fatalError() +} + +enum SR8811EmptyGenericEnum {} + +let sr8811z: SR8811EmptyGenericEnum // expected-error {{constant 'sr8811z' cannot have enum type 'SR8811EmptyGenericEnum' with no cases}} diff --git a/test/expr/expressions.swift b/test/expr/expressions.swift index f28c7b05b476f..0473b67d103cc 100644 --- a/test/expr/expressions.swift +++ b/test/expr/expressions.swift @@ -584,9 +584,9 @@ func conversionTest(_ a: inout Double, b: inout Int) { var pi_f3 = float.init(getPi()) // expected-error {{ambiguous use of 'init(_:)'}} var pi_f4 = float.init(pi_f) - var e = Empty(f) + var e = Empty(f) // expected-error {{variable 'e' cannot have enum type 'Empty' with no cases}} var e2 = Empty(d) // expected-error{{cannot convert value of type 'Double' to expected argument type 'Float'}} - var e3 = Empty(Float(d)) + var e3 = Empty(Float(d)) // expected-error {{variable 'e3' cannot have enum type 'Empty' with no cases}} } struct Rule { // expected-note {{'init(target:dependencies:)' declared here}}