Skip to content

Commit 277be31

Browse files
committed
[AST/Sema] SE-0487: Expand @nonexhaustive attribute to support warn argument
The spelling `@nonexhaustive(warn)` replaces `@preEnumExtensibility` attriubte. (cherry picked from commit 43eec8f)
1 parent f7f4cf6 commit 277be31

16 files changed

+132
-18
lines changed

include/swift/AST/Attr.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,10 @@ class DeclAttribute : public AttributeBase {
244244
SWIFT_INLINE_BITFIELD(LifetimeAttr, DeclAttribute, 1,
245245
isUnderscored : 1
246246
);
247+
248+
SWIFT_INLINE_BITFIELD(NonexhaustiveAttr, DeclAttribute, NumNonexhaustiveModeBits,
249+
mode : NumNonexhaustiveModeBits
250+
);
247251
} Bits;
248252
// clang-format on
249253

@@ -3334,6 +3338,35 @@ class ABIAttr : public DeclAttribute {
33343338
}
33353339
};
33363340

3341+
/// Defines a @nonexhaustive attribute.
3342+
class NonexhaustiveAttr : public DeclAttribute {
3343+
public:
3344+
NonexhaustiveAttr(SourceLoc atLoc, SourceRange range, NonexhaustiveMode mode,
3345+
bool implicit = false)
3346+
: DeclAttribute(DeclAttrKind::Nonexhaustive, atLoc, range, implicit) {
3347+
Bits.NonexhaustiveAttr.mode = unsigned(mode);
3348+
}
3349+
3350+
NonexhaustiveAttr(NonexhaustiveMode mode)
3351+
: NonexhaustiveAttr(SourceLoc(), SourceRange(), mode) {}
3352+
3353+
NonexhaustiveMode getMode() const {
3354+
return NonexhaustiveMode(Bits.NonexhaustiveAttr.mode);
3355+
}
3356+
3357+
static bool classof(const DeclAttribute *DA) {
3358+
return DA->getKind() == DeclAttrKind::Nonexhaustive;
3359+
}
3360+
3361+
NonexhaustiveAttr *clone(ASTContext &ctx) const {
3362+
return new (ctx) NonexhaustiveAttr(AtLoc, Range, getMode(), isImplicit());
3363+
}
3364+
3365+
bool isEquivalent(const NonexhaustiveAttr *other, Decl *attachedTo) const {
3366+
return getMode() == other->getMode();
3367+
}
3368+
};
3369+
33373370
/// Attributes that may be applied to declarations.
33383371
class DeclAttributes {
33393372
/// Linked list of declaration attributes.

include/swift/AST/AttrKind.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,17 @@ enum : unsigned {
158158
InheritActorContextModifier::Last_InheritActorContextKind))
159159
};
160160

161+
enum class NonexhaustiveMode : uint8_t {
162+
Error = 0,
163+
Warning,
164+
Last_NonexhaustiveMode = Warning
165+
};
166+
167+
enum : unsigned {
168+
NumNonexhaustiveModeBits = countBitsUsed(static_cast<unsigned>(
169+
NonexhaustiveMode::Last_NonexhaustiveMode))
170+
};
171+
161172
enum class DeclAttrKind : unsigned {
162173
#define DECL_ATTR(_, CLASS, ...) CLASS,
163174
#define LAST_DECL_ATTR(CLASS) Last_DeclAttr = CLASS,

include/swift/AST/DeclAttr.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -876,7 +876,7 @@ SIMPLE_DECL_ATTR(constInitialized, ConstInitialized,
876876
168)
877877
DECL_ATTR_FEATURE_REQUIREMENT(ConstInitialized, CompileTimeValues)
878878

879-
SIMPLE_DECL_ATTR(nonexhaustive, Nonexhaustive,
879+
DECL_ATTR(nonexhaustive, Nonexhaustive,
880880
OnEnum,
881881
ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove | ForbiddenInABIAttr,
882882
169)

include/swift/AST/KnownIdentifiers.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ IDENTIFIER(value)
169169
IDENTIFIER_WITH_NAME(value_, "_value")
170170
IDENTIFIER(Void)
171171
IDENTIFIER(WinSDK)
172+
IDENTIFIER(warn)
172173
IDENTIFIER(with)
173174
IDENTIFIER(withArguments)
174175
IDENTIFIER(withKeywordArguments)

include/swift/Parse/IDEInspectionCallbacks.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ enum class ParameterizedDeclAttributeKind {
4040
FreestandingMacro,
4141
AttachedMacro,
4242
StorageRestrictions,
43-
InheritActorContext
43+
InheritActorContext,
44+
Nonexhaustive,
4445
};
4546

4647
/// A bit of a hack. When completing inside the '@storageRestrictions'

lib/AST/Attr.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1725,6 +1725,19 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
17251725
break;
17261726
}
17271727

1728+
case DeclAttrKind::Nonexhaustive: {
1729+
auto *attr = cast<NonexhaustiveAttr>(this);
1730+
Printer << "@nonexhaustive";
1731+
switch (attr->getMode()) {
1732+
case NonexhaustiveMode::Error:
1733+
break;
1734+
case NonexhaustiveMode::Warning:
1735+
Printer << "(warn)";
1736+
break;
1737+
}
1738+
break;
1739+
}
1740+
17281741
#define SIMPLE_DECL_ATTR(X, CLASS, ...) case DeclAttrKind::CLASS:
17291742
#include "swift/AST/DeclAttr.def"
17301743
llvm_unreachable("handled above");
@@ -1956,6 +1969,8 @@ StringRef DeclAttribute::getAttrName() const {
19561969
}
19571970
case DeclAttrKind::Lifetime:
19581971
return cast<LifetimeAttr>(this)->isUnderscored() ? "_lifetime" : "lifetime";
1972+
case DeclAttrKind::Nonexhaustive:
1973+
return "nonexhaustive";
19591974
}
19601975
llvm_unreachable("bad DeclAttrKind");
19611976
}

lib/IDE/CompletionLookup.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3273,6 +3273,11 @@ void CompletionLookup::getAttributeDeclParamCompletions(
32733273
getStoredPropertyCompletions(NT);
32743274
}
32753275
}
3276+
break;
3277+
}
3278+
case ParameterizedDeclAttributeKind::Nonexhaustive: {
3279+
addDeclAttrParamKeyword("warn", /*Parameters=*/{}, "", false);
3280+
break;
32763281
}
32773282
}
32783283
}

lib/Parse/ParseDecl.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3970,6 +3970,21 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
39703970
Attributes.add(Attr.get());
39713971
break;
39723972
}
3973+
3974+
case DeclAttrKind::Nonexhaustive: {
3975+
auto mode = parseSingleAttrOption<NonexhaustiveMode>(
3976+
*this, Loc, AttrRange, AttrName, DK,
3977+
{{Context.Id_warn, NonexhaustiveMode::Warning}},
3978+
NonexhaustiveMode::Error,
3979+
ParameterizedDeclAttributeKind::Nonexhaustive);
3980+
if (!mode)
3981+
return makeParserSuccess();
3982+
3983+
if (!DiscardAttribute)
3984+
Attributes.add(new (Context) NonexhaustiveAttr(AtLoc, AttrRange, *mode));
3985+
3986+
break;
3987+
}
39733988
}
39743989

39753990
if (DuplicateAttribute) {

lib/Sema/TypeCheckSwitchStmt.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,14 +1167,20 @@ namespace {
11671167
DE.diagnose(startLoc, diag::non_exhaustive_switch_unknown_only,
11681168
subjectType, shouldIncludeFutureVersionComment);
11691169

1170-
// Presence of `@preEnumExtensibility` pushed the warning farther
1171-
// into the future.
1172-
if (theEnum &&
1173-
theEnum->getAttrs().hasAttribute<PreEnumExtensibilityAttr>()) {
1174-
diag.warnUntilFutureSwiftVersion();
1175-
} else {
1176-
diag.warnUntilSwiftVersion(6);
1177-
}
1170+
auto shouldWarnUntilVersion = [&theEnum]() -> unsigned {
1171+
if (theEnum) {
1172+
// Presence of `@nonexhaustive(warn)` pushes the warning farther,
1173+
// into the future.
1174+
if (auto *nonexhaustive =
1175+
theEnum->getAttrs().getAttribute<NonexhaustiveAttr>()) {
1176+
if (nonexhaustive->getMode() == NonexhaustiveMode::Warning)
1177+
return swift::version::Version::getFutureMajorLanguageVersion();
1178+
}
1179+
}
1180+
return 6;
1181+
};
1182+
1183+
diag.warnUntilSwiftVersion(shouldWarnUntilVersion());
11781184

11791185
mainDiagType = std::nullopt;
11801186
}

lib/Serialization/Deserialization.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6648,6 +6648,14 @@ llvm::Error DeclDeserializer::deserializeDeclCommon() {
66486648
break;
66496649
}
66506650

6651+
case decls_block::Nonexhaustive_DECL_ATTR: {
6652+
unsigned mode;
6653+
serialization::decls_block::NonexhaustiveDeclAttrLayout::readRecord(
6654+
scratch, mode);
6655+
Attr = new (ctx) NonexhaustiveAttr((NonexhaustiveMode)mode);
6656+
break;
6657+
}
6658+
66516659
#define SIMPLE_DECL_ATTR(NAME, CLASS, ...) \
66526660
case decls_block::CLASS##_DECL_ATTR: { \
66536661
bool isImplicit; \

0 commit comments

Comments
 (0)