Merge pull request #82922 from xedin/nonexhaustive-enums-6.2

[6.2][AST/Sema] SE-0487: Implement `@nonexhaustive` attribute and new enum exhaustivity checking rule
This commit is contained in:
Pavel Yaskevich
2025-08-20 20:31:07 -07:00
committed by GitHub
35 changed files with 316 additions and 208 deletions

View File

@@ -244,6 +244,10 @@ protected:
SWIFT_INLINE_BITFIELD(LifetimeAttr, DeclAttribute, 1,
isUnderscored : 1
);
SWIFT_INLINE_BITFIELD(NonexhaustiveAttr, DeclAttribute, NumNonexhaustiveModeBits,
mode : NumNonexhaustiveModeBits
);
} Bits;
// clang-format on
@@ -3334,6 +3338,35 @@ public:
}
};
/// Defines a @nonexhaustive attribute.
class NonexhaustiveAttr : public DeclAttribute {
public:
NonexhaustiveAttr(SourceLoc atLoc, SourceRange range, NonexhaustiveMode mode,
bool implicit = false)
: DeclAttribute(DeclAttrKind::Nonexhaustive, atLoc, range, implicit) {
Bits.NonexhaustiveAttr.mode = unsigned(mode);
}
NonexhaustiveAttr(NonexhaustiveMode mode)
: NonexhaustiveAttr(SourceLoc(), SourceRange(), mode) {}
NonexhaustiveMode getMode() const {
return NonexhaustiveMode(Bits.NonexhaustiveAttr.mode);
}
static bool classof(const DeclAttribute *DA) {
return DA->getKind() == DeclAttrKind::Nonexhaustive;
}
NonexhaustiveAttr *clone(ASTContext &ctx) const {
return new (ctx) NonexhaustiveAttr(AtLoc, Range, getMode(), isImplicit());
}
bool isEquivalent(const NonexhaustiveAttr *other, Decl *attachedTo) const {
return getMode() == other->getMode();
}
};
/// Attributes that may be applied to declarations.
class DeclAttributes {
/// Linked list of declaration attributes.

View File

@@ -158,6 +158,17 @@ enum : unsigned {
InheritActorContextModifier::Last_InheritActorContextKind))
};
enum class NonexhaustiveMode : uint8_t {
Error = 0,
Warning,
Last_NonexhaustiveMode = Warning
};
enum : unsigned {
NumNonexhaustiveModeBits = countBitsUsed(static_cast<unsigned>(
NonexhaustiveMode::Last_NonexhaustiveMode))
};
enum class DeclAttrKind : unsigned {
#define DECL_ATTR(_, CLASS, ...) CLASS,
#define LAST_DECL_ATTR(CLASS) Last_DeclAttr = CLASS,

View File

@@ -751,7 +751,7 @@ protected:
HasAnyUnavailableDuringLoweringValues : 1
);
SWIFT_INLINE_BITFIELD(ModuleDecl, TypeDecl, 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+8,
SWIFT_INLINE_BITFIELD(ModuleDecl, TypeDecl, 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+8,
/// If the module is compiled as static library.
StaticLibrary : 1,
@@ -820,10 +820,7 @@ protected:
SerializePackageEnabled : 1,
/// Whether this module has enabled strict memory safety checking.
StrictMemorySafety : 1,
/// Whether this module has enabled `ExtensibleEnums` feature.
ExtensibleEnums : 1
StrictMemorySafety : 1
);
SWIFT_INLINE_BITFIELD(PrecedenceGroupDecl, Decl, 1+2,

View File

@@ -876,11 +876,19 @@ SIMPLE_DECL_ATTR(constInitialized, ConstInitialized,
168)
DECL_ATTR_FEATURE_REQUIREMENT(ConstInitialized, CompileTimeValues)
DECL_ATTR(nonexhaustive, Nonexhaustive,
OnEnum,
ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove | ForbiddenInABIAttr,
169)
DECL_ATTR_FEATURE_REQUIREMENT(Nonexhaustive, NonexhaustiveAttribute)
SIMPLE_DECL_ATTR(concurrent, Concurrent,
OnFunc | OnConstructor | OnSubscript | OnVar,
ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove | UnconstrainedInABIAttr,
170)
// Unused '171': Used to be `@preEnumExtensibility`
LAST_DECL_ATTR(Concurrent)
#undef DECL_ATTR_ALIAS

View File

@@ -8714,6 +8714,19 @@ GROUPED_WARNING(
"behavior",
(StringRef))
//===----------------------------------------------------------------------===//
// MARK: @nonexhaustive and @preEnumExtensibility Attributes
//===----------------------------------------------------------------------===//
ERROR(nonexhaustive_attr_on_frozen_type,none,
"cannot use '@nonexhaustive' together with '@frozen'", ())
ERROR(nonexhaustive_attr_on_internal_type,none,
"'@nonexhaustive' attribute can only be applied to public or package "
"declarations, but %0 is "
"%select{private|fileprivate|internal|%error|%error|%error}1",
(DeclName, AccessLevel))
//===----------------------------------------------------------------------===//
// MARK: `using` declaration
//===----------------------------------------------------------------------===//

View File

@@ -169,6 +169,7 @@ IDENTIFIER(value)
IDENTIFIER_WITH_NAME(value_, "_value")
IDENTIFIER(Void)
IDENTIFIER(WinSDK)
IDENTIFIER(warn)
IDENTIFIER(with)
IDENTIFIER(withArguments)
IDENTIFIER(withKeywordArguments)

View File

@@ -835,14 +835,6 @@ public:
Bits.ModuleDecl.ObjCNameLookupCachePopulated = value;
}
bool supportsExtensibleEnums() const {
return Bits.ModuleDecl.ExtensibleEnums;
}
void setSupportsExtensibleEnums(bool value = true) {
Bits.ModuleDecl.ExtensibleEnums = value;
}
/// For the main module, retrieves the list of primary source files being
/// compiled, that is, the files we're generating code for.
ArrayRef<SourceFile *> getPrimarySourceFiles() const;

View File

@@ -268,6 +268,7 @@ LANGUAGE_FEATURE(BuiltinSelect, 0, "Builtin.select")
LANGUAGE_FEATURE(AlwaysInheritActorContext, 472, "@_inheritActorContext(always)")
LANGUAGE_FEATURE(NonescapableAccessorOnTrivial, 0, "Support UnsafeMutablePointer.mutableSpan")
LANGUAGE_FEATURE(InlineArrayTypeSugar, 483, "Type sugar for InlineArray")
SUPPRESSIBLE_LANGUAGE_FEATURE(NonexhaustiveAttribute, 487, "Nonexhaustive Enums")
// Swift 6
UPCOMING_FEATURE(ConciseMagicFile, 274, 6)
@@ -505,11 +506,6 @@ SUPPRESSIBLE_EXPERIMENTAL_FEATURE(AddressableTypes, true)
/// Allow custom availability domains to be defined and referenced.
EXPERIMENTAL_FEATURE(CustomAvailability, true)
/// Allow public enumerations to be extensible by default
/// regardless of whether the module they are declared in
/// is resilient or not.
EXPERIMENTAL_FEATURE(ExtensibleEnums, true)
/// Syntax sugar features for concurrency.
EXPERIMENTAL_FEATURE(ConcurrencySyntaxSugar, true)

View File

@@ -40,7 +40,8 @@ enum class ParameterizedDeclAttributeKind {
FreestandingMacro,
AttachedMacro,
StorageRestrictions,
InheritActorContext
InheritActorContext,
Nonexhaustive,
};
/// A bit of a hack. When completing inside the '@storageRestrictions'

View File

@@ -150,7 +150,6 @@ class ExtendedValidationInfo {
unsigned AllowNonResilientAccess: 1;
unsigned SerializePackageEnabled: 1;
unsigned StrictMemorySafety: 1;
unsigned SupportsExtensibleEnums : 1;
} Bits;
public:
@@ -272,11 +271,6 @@ public:
version, SourceLoc(), /*Diags=*/nullptr))
SwiftInterfaceCompilerVersion = genericVersion.value();
}
bool supportsExtensibleEnums() const { return Bits.SupportsExtensibleEnums; }
void setSupportsExtensibleEnums(bool val) {
Bits.SupportsExtensibleEnums = val;
}
};
struct SearchPath {