Skip to content

Commit 77a86a5

Browse files
authored
Merge pull request #79891 from gottesmm/pr-9df6772bb44656cbd85cad72ee5c3637caab8956
Make Feature a struct enum so we can put methods on it.
2 parents 2d9217b + 3ff9463 commit 77a86a5

17 files changed

+121
-101
lines changed

include/swift/Basic/Feature.h

+56-35
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#ifndef SWIFT_BASIC_FEATURES_H
14-
#define SWIFT_BASIC_FEATURES_H
13+
#ifndef SWIFT_BASIC_FEATURE_H
14+
#define SWIFT_BASIC_FEATURE_H
15+
16+
#include "swift/Basic/LLVM.h"
1517

1618
#include "llvm/ADT/StringRef.h"
1719
#include <optional>
@@ -21,53 +23,72 @@ namespace swift {
2123
class LangOptions;
2224

2325
/// Enumeration describing all of the named features.
24-
enum class Feature : uint16_t {
26+
struct Feature {
27+
enum class InnerKind : uint16_t {
2528
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) FeatureName,
2629
#include "swift/Basic/Features.def"
27-
};
30+
};
31+
32+
InnerKind kind;
2833

29-
constexpr unsigned numFeatures() {
30-
enum Features {
34+
constexpr Feature(InnerKind kind) : kind(kind) {}
35+
constexpr Feature(unsigned inputKind) : kind(InnerKind(inputKind)) {}
36+
37+
constexpr operator InnerKind() const { return kind; }
38+
constexpr explicit operator unsigned() const { return unsigned(kind); }
39+
constexpr explicit operator size_t() const { return size_t(kind); }
40+
41+
static constexpr unsigned getNumFeatures() {
42+
enum Features {
3143
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) FeatureName,
3244
#include "swift/Basic/Features.def"
33-
NumFeatures
34-
};
35-
return NumFeatures;
36-
}
45+
NumFeatures
46+
};
47+
return NumFeatures;
48+
}
3749

38-
/// Check whether the given feature is available in production compilers.
39-
bool isFeatureAvailableInProduction(Feature feature);
50+
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
51+
static const Feature FeatureName;
52+
#include "swift/Basic/Features.def"
4053

41-
/// Determine the in-source name of the given feature.
42-
llvm::StringRef getFeatureName(Feature feature);
54+
/// Check whether the given feature is available in production compilers.
55+
bool isAvailableInProduction() const;
4356

44-
/// Determine whether the first feature is more recent (and thus implies
45-
/// the existence of) the second feature. Only meaningful for suppressible
46-
/// features.
47-
inline bool featureImpliesFeature(Feature feature, Feature implied) {
48-
// Suppressible features are expected to be listed in order of
49-
// addition in Features.def.
50-
return (unsigned) feature < (unsigned) implied;
51-
}
57+
/// Determine the in-source name of the given feature.
58+
llvm::StringRef getName() const;
5259

53-
/// Get the feature corresponding to this "future" feature, if there is one.
54-
std::optional<Feature> getUpcomingFeature(llvm::StringRef name);
60+
/// Determine whether the given feature supports adoption mode.
61+
bool isAdoptable() const;
5562

56-
/// Get the feature corresponding to this "experimental" feature, if there is
57-
/// one.
58-
std::optional<Feature> getExperimentalFeature(llvm::StringRef name);
63+
/// Determine whether this feature should be included in the
64+
/// module interface
65+
bool includeInModuleInterface() const;
5966

60-
/// Get the major language version in which this feature was introduced, or
61-
/// \c None if it does not have such a version.
62-
std::optional<unsigned> getFeatureLanguageVersion(Feature feature);
67+
/// Determine whether the first feature is more recent (and thus implies
68+
/// the existence of) the second feature. Only meaningful for suppressible
69+
/// features.
70+
constexpr bool featureImpliesFeature(Feature implied) const {
71+
// Suppressible features are expected to be listed in order of
72+
// addition in Features.def.
73+
return (unsigned)kind < (unsigned)implied.kind;
74+
}
6375

64-
/// Determine whether the given feature supports adoption mode.
65-
bool isFeatureAdoptable(Feature feature);
76+
/// Get the feature corresponding to this "future" feature, if there is one.
77+
static std::optional<Feature> getUpcomingFeature(StringRef name);
6678

67-
/// Determine whether this feature should be included in the
68-
/// module interface
69-
bool includeInModuleInterface(Feature feature);
79+
/// Get the feature corresponding to this "experimental" feature, if there is
80+
/// one.
81+
static std::optional<Feature> getExperimentalFeature(StringRef name);
7082

83+
/// Get the major language version in which this feature was introduced, or
84+
/// \c None if it does not have such a version.
85+
std::optional<unsigned> getLanguageVersion() const;
86+
};
87+
88+
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
89+
constexpr inline Feature Feature::FeatureName = \
90+
Feature::InnerKind::FeatureName;
91+
#include "swift/Basic/Features.def"
7192
}
7293

7394
#endif // SWIFT_BASIC_FEATURES_H

include/swift/SILOptimizer/OptimizerBridgingImpl.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,7 @@ bool BridgedPassContext::enableMergeableTraps() const {
555555

556556
bool BridgedPassContext::hasFeature(BridgedFeature feature) const {
557557
swift::SILModule *mod = invocation->getPassManager()->getModule();
558-
return mod->getASTContext().LangOpts.hasFeature((swift::Feature)feature);
558+
return mod->getASTContext().LangOpts.hasFeature(swift::Feature(feature));
559559
}
560560

561561
bool BridgedPassContext::enableMoveInoutStackProtection() const {

lib/AST/ASTPrinter.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -3352,7 +3352,7 @@ static void printCompatibilityCheckIf(ASTPrinter &printer, bool isElseIf,
33523352
} else {
33533353
first = false;
33543354
}
3355-
printer << "$" << getFeatureName(feature);
3355+
printer << "$" << Feature(feature).getName();
33563356
}
33573357

33583358
#ifndef NDEBUG

lib/AST/FeatureSet.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ void FeatureSet::collectRequiredFeature(Feature feature,
552552

553553
void FeatureSet::collectSuppressibleFeature(Feature feature,
554554
InsertOrRemove operation) {
555-
suppressible.insertOrRemove(numFeatures() - size_t(feature),
555+
suppressible.insertOrRemove(Feature::getNumFeatures() - size_t(feature),
556556
operation == Insert);
557557
}
558558

lib/AST/FeatureSet.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919

2020
namespace swift {
2121

22-
using BasicFeatureSet = FixedBitSet<numFeatures(), Feature>;
22+
using BasicFeatureSet =
23+
FixedBitSet<Feature::getNumFeatures(), Feature::InnerKind>;
2324

2425
class FeatureSet {
2526
BasicFeatureSet required;
@@ -30,7 +31,7 @@ class FeatureSet {
3031
// This is the easiest way of letting us iterate from largest to
3132
// smallest, i.e. from the newest to the oldest feature, which is
3233
// the order in which we need to emit #if clauses.
33-
using SuppressibleFeatureSet = FixedBitSet<numFeatures(), size_t>;
34+
using SuppressibleFeatureSet = FixedBitSet<Feature::getNumFeatures(), size_t>;
3435
SuppressibleFeatureSet suppressible;
3536

3637
public:
@@ -42,7 +43,7 @@ class FeatureSet {
4243

4344
public:
4445
bool empty() const { return i == e; }
45-
Feature next() { return Feature(numFeatures() - *i++); }
46+
Feature next() { return Feature(Feature::getNumFeatures() - *i++); }
4647
};
4748

4849
bool empty() const { return required.empty() && suppressible.empty(); }

lib/Basic/Feature.cpp

+12-12
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616

1717
using namespace swift;
1818

19-
bool swift::isFeatureAvailableInProduction(Feature feature) {
20-
switch (feature) {
19+
bool Feature::isAvailableInProduction() const {
20+
switch (kind) {
2121
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
2222
case Feature::FeatureName: \
2323
return true;
@@ -29,8 +29,8 @@ bool swift::isFeatureAvailableInProduction(Feature feature) {
2929
llvm_unreachable("covered switch");
3030
}
3131

32-
llvm::StringRef swift::getFeatureName(Feature feature) {
33-
switch (feature) {
32+
llvm::StringRef Feature::getName() const {
33+
switch (kind) {
3434
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
3535
case Feature::FeatureName: \
3636
return #FeatureName;
@@ -39,7 +39,7 @@ llvm::StringRef swift::getFeatureName(Feature feature) {
3939
llvm_unreachable("covered switch");
4040
}
4141

42-
std::optional<Feature> swift::getUpcomingFeature(llvm::StringRef name) {
42+
std::optional<Feature> Feature::getUpcomingFeature(llvm::StringRef name) {
4343
return llvm::StringSwitch<std::optional<Feature>>(name)
4444
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description)
4545
#define UPCOMING_FEATURE(FeatureName, SENumber, Version) \
@@ -48,7 +48,7 @@ std::optional<Feature> swift::getUpcomingFeature(llvm::StringRef name) {
4848
.Default(std::nullopt);
4949
}
5050

51-
std::optional<Feature> swift::getExperimentalFeature(llvm::StringRef name) {
51+
std::optional<Feature> Feature::getExperimentalFeature(llvm::StringRef name) {
5252
return llvm::StringSwitch<std::optional<Feature>>(name)
5353
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description)
5454
#define EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
@@ -57,8 +57,8 @@ std::optional<Feature> swift::getExperimentalFeature(llvm::StringRef name) {
5757
.Default(std::nullopt);
5858
}
5959

60-
std::optional<unsigned> swift::getFeatureLanguageVersion(Feature feature) {
61-
switch (feature) {
60+
std::optional<unsigned> Feature::getLanguageVersion() const {
61+
switch (kind) {
6262
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description)
6363
#define UPCOMING_FEATURE(FeatureName, SENumber, Version) \
6464
case Feature::FeatureName: \
@@ -69,8 +69,8 @@ std::optional<unsigned> swift::getFeatureLanguageVersion(Feature feature) {
6969
}
7070
}
7171

72-
bool swift::isFeatureAdoptable(Feature feature) {
73-
switch (feature) {
72+
bool Feature::isAdoptable() const {
73+
switch (kind) {
7474
#define ADOPTABLE_UPCOMING_FEATURE(FeatureName, SENumber, Version)
7575
#define ADOPTABLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd)
7676
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
@@ -87,8 +87,8 @@ bool swift::isFeatureAdoptable(Feature feature) {
8787
}
8888
}
8989

90-
bool swift::includeInModuleInterface(Feature feature) {
91-
switch (feature) {
90+
bool Feature::includeInModuleInterface() const {
91+
switch (kind) {
9292
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
9393
case Feature::FeatureName: \
9494
return true;

lib/Basic/LangOptions.cpp

+8-8
Original file line numberDiff line numberDiff line change
@@ -299,14 +299,13 @@ bool LangOptions::FeatureState::isEnabled() const {
299299
}
300300

301301
bool LangOptions::FeatureState::isEnabledForAdoption() const {
302-
ASSERT(isFeatureAdoptable(feature) &&
303-
"You forgot to make the feature adoptable!");
302+
ASSERT(feature.isAdoptable() && "You forgot to make the feature adoptable!");
304303

305304
return state == FeatureState::Kind::EnabledForAdoption;
306305
}
307306

308307
LangOptions::FeatureStateStorage::FeatureStateStorage()
309-
: states(numFeatures(), FeatureState::Kind::Off) {}
308+
: states(Feature::getNumFeatures(), FeatureState::Kind::Off) {}
310309

311310
void LangOptions::FeatureStateStorage::setState(Feature feature,
312311
FeatureState::Kind state) {
@@ -327,7 +326,7 @@ LangOptions::FeatureState LangOptions::getFeatureState(Feature feature) const {
327326
if (state.isEnabled())
328327
return state;
329328

330-
if (auto version = getFeatureLanguageVersion(feature)) {
329+
if (auto version = feature.getLanguageVersion()) {
331330
if (isSwiftVersionAtLeast(*version)) {
332331
return FeatureState(feature, FeatureState::Kind::Enabled);
333332
}
@@ -340,7 +339,7 @@ bool LangOptions::hasFeature(Feature feature) const {
340339
if (featureStates.getState(feature).isEnabled())
341340
return true;
342341

343-
if (auto version = getFeatureLanguageVersion(feature))
342+
if (auto version = feature.getLanguageVersion())
344343
return isSwiftVersionAtLeast(*version);
345344

346345
return false;
@@ -360,11 +359,12 @@ bool LangOptions::hasFeature(llvm::StringRef featureName) const {
360359

361360
void LangOptions::enableFeature(Feature feature, bool forAdoption) {
362361
if (forAdoption) {
363-
ASSERT(isFeatureAdoptable(feature));
362+
ASSERT(feature.isAdoptable());
364363
featureStates.setState(feature, FeatureState::Kind::EnabledForAdoption);
365-
} else {
366-
featureStates.setState(feature, FeatureState::Kind::Enabled);
364+
return;
367365
}
366+
367+
featureStates.setState(feature, FeatureState::Kind::Enabled);
368368
}
369369

370370
void LangOptions::disableFeature(Feature feature) {

lib/DriverTool/sil_opt_main.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -753,14 +753,14 @@ int sil_opt_main(ArrayRef<const char *> argv, void *MainAddr) {
753753
}
754754

755755
for (auto &featureName : options.UpcomingFeatures) {
756-
auto feature = getUpcomingFeature(featureName);
756+
auto feature = Feature::getUpcomingFeature(featureName);
757757
if (!feature) {
758758
llvm::errs() << "error: unknown upcoming feature "
759759
<< QuotedString(featureName) << "\n";
760760
exit(-1);
761761
}
762762

763-
if (auto firstVersion = getFeatureLanguageVersion(*feature)) {
763+
if (auto firstVersion = feature->getLanguageVersion()) {
764764
if (Invocation.getLangOptions().isSwiftVersionAtLeast(*firstVersion)) {
765765
llvm::errs() << "error: upcoming feature " << QuotedString(featureName)
766766
<< " is already enabled as of Swift version "
@@ -772,7 +772,7 @@ int sil_opt_main(ArrayRef<const char *> argv, void *MainAddr) {
772772
}
773773

774774
for (auto &featureName : options.ExperimentalFeatures) {
775-
if (auto feature = getExperimentalFeature(featureName)) {
775+
if (auto feature = Feature::getExperimentalFeature(featureName)) {
776776
Invocation.getLangOptions().enableFeature(*feature);
777777
} else {
778778
llvm::errs() << "error: unknown experimental feature "

lib/Frontend/CompilerInvocation.cpp

+9-9
Original file line numberDiff line numberDiff line change
@@ -537,8 +537,8 @@ static bool ShouldIncludeModuleInterfaceArg(const Arg *A) {
537537
if (!A->getOption().matches(options::OPT_enable_experimental_feature))
538538
return true;
539539

540-
if (auto feature = getExperimentalFeature(A->getValue())) {
541-
return swift::includeInModuleInterface(*feature);
540+
if (auto feature = Feature::getExperimentalFeature(A->getValue())) {
541+
return feature->includeInModuleInterface();
542542
}
543543

544544
return true;
@@ -824,7 +824,7 @@ static bool ParseEnabledFeatureArgs(LangOptions &Opts, ArgList &Args,
824824
featureMode = std::nullopt;
825825
}
826826

827-
auto feature = getUpcomingFeature(featureName);
827+
auto feature = Feature::getUpcomingFeature(featureName);
828828
if (feature) {
829829
// Diagnose upcoming features enabled with -enable-experimental-feature.
830830
if (!isUpcomingFeatureFlag)
@@ -840,7 +840,7 @@ static bool ParseEnabledFeatureArgs(LangOptions &Opts, ArgList &Args,
840840
}
841841

842842
// If the feature is also not a recognized experimental feature, skip it.
843-
feature = getExperimentalFeature(featureName);
843+
feature = Feature::getExperimentalFeature(featureName);
844844
if (!feature) {
845845
Diags.diagnose(SourceLoc(), diag::unrecognized_feature, featureName,
846846
/*upcoming=*/false);
@@ -850,19 +850,19 @@ static bool ParseEnabledFeatureArgs(LangOptions &Opts, ArgList &Args,
850850

851851
// If the current language mode enables the feature by default then
852852
// diagnose and skip it.
853-
if (auto firstVersion = getFeatureLanguageVersion(*feature)) {
853+
if (auto firstVersion = feature->getLanguageVersion()) {
854854
if (Opts.isSwiftVersionAtLeast(*firstVersion)) {
855855
Diags.diagnose(SourceLoc(),
856856
diag::warning_upcoming_feature_on_by_default,
857-
getFeatureName(*feature), *firstVersion);
857+
feature->getName(), *firstVersion);
858858
continue;
859859
}
860860
}
861861

862862
// If this is a known experimental feature, allow it in +Asserts
863863
// (non-release) builds for testing purposes.
864864
if (Opts.RestrictNonProductionExperimentalFeatures &&
865-
!isFeatureAvailableInProduction(*feature)) {
865+
!feature->isAvailableInProduction()) {
866866
Diags.diagnose(SourceLoc(),
867867
diag::experimental_not_supported_in_production,
868868
featureName);
@@ -872,7 +872,7 @@ static bool ParseEnabledFeatureArgs(LangOptions &Opts, ArgList &Args,
872872

873873
if (featureMode) {
874874
if (isEnableFeatureFlag) {
875-
const auto isAdoptable = isFeatureAdoptable(*feature);
875+
const auto isAdoptable = feature->isAdoptable();
876876

877877
// Diagnose an invalid mode.
878878
StringRef validModeName = "adoption";
@@ -1205,7 +1205,7 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
12051205
// Add a future feature if it is not already implied by the language version.
12061206
auto addFutureFeatureIfNotImplied = [&](Feature feature) {
12071207
// Check if this feature was introduced already in this language version.
1208-
if (auto firstVersion = getFeatureLanguageVersion(feature)) {
1208+
if (auto firstVersion = feature.getLanguageVersion()) {
12091209
if (Opts.isSwiftVersionAtLeast(*firstVersion))
12101210
return;
12111211
}

0 commit comments

Comments
 (0)