Skip to content

[6.2][Frontend] Add a way to print features supported by the compiler #81518

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions include/swift/AST/DiagnosticsFrontend.def
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ GROUPED_WARNING(cannot_disable_feature_with_mode, StrictLanguageFeatures, none,
"'%0' argument '%1' cannot specify a mode",
(StringRef, StringRef))

GROUPED_WARNING(feature_does_not_support_adoption_mode, StrictLanguageFeatures,
GROUPED_WARNING(feature_does_not_support_migration_mode, StrictLanguageFeatures,
none,
"feature '%0' does not support adoption mode",
"feature '%0' does not support migration mode",
(StringRef))

ERROR(error_unknown_library_level, none,
Expand Down
91 changes: 56 additions & 35 deletions include/swift/Basic/Feature.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_BASIC_FEATURES_H
#define SWIFT_BASIC_FEATURES_H
#ifndef SWIFT_BASIC_FEATURE_H
#define SWIFT_BASIC_FEATURE_H

#include "swift/Basic/LLVM.h"

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

/// Enumeration describing all of the named features.
enum class Feature : uint16_t {
struct Feature {
enum class InnerKind : uint16_t {
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) FeatureName,
#include "swift/Basic/Features.def"
};
};

InnerKind kind;

constexpr unsigned numFeatures() {
enum Features {
constexpr Feature(InnerKind kind) : kind(kind) {}
constexpr Feature(unsigned inputKind) : kind(InnerKind(inputKind)) {}

constexpr operator InnerKind() const { return kind; }
constexpr explicit operator unsigned() const { return unsigned(kind); }
constexpr explicit operator size_t() const { return size_t(kind); }

static constexpr unsigned getNumFeatures() {
enum Features {
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) FeatureName,
#include "swift/Basic/Features.def"
NumFeatures
};
return NumFeatures;
}
NumFeatures
};
return NumFeatures;
}

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

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

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

/// Get the feature corresponding to this "future" feature, if there is one.
std::optional<Feature> getUpcomingFeature(llvm::StringRef name);
/// Determine whether the given feature supports migration mode.
bool isMigratable() const;

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

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

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

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

/// Get the major language version in which this feature was introduced, or
/// \c None if it does not have such a version.
std::optional<unsigned> getLanguageVersion() const;
};

#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
constexpr inline Feature Feature::FeatureName = \
Feature::InnerKind::FeatureName;
#include "swift/Basic/Features.def"
}

#endif // SWIFT_BASIC_FEATURES_H
30 changes: 15 additions & 15 deletions include/swift/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -121,36 +121,36 @@
LANGUAGE_FEATURE(FeatureName, SENumber, Description)
#endif

// An upcoming feature that supports adoption mode.
// An upcoming feature that supports migration mode.
//
// If the feature is source-breaking and provides for a
// mechanical code migration, it should implement adoption mode.
// mechanical code migration, it should implement migration mode.
//
// Adoption mode is a feature-oriented code migration mechanism: a mode
// Migration mode is a feature-oriented code migration mechanism: a mode
// of operation that should produce compiler warnings with attached
// fix-its that can be applied to preserve the behavior of the code once
// the upcoming feature is enacted.
// These warnings must belong to a diagnostic group named after the
// feature. Adoption mode itself *and* the fix-its it produces must be
// feature. Migration mode itself *and* the fix-its it produces must be
// source and binary compatible with how the code is compiled when the
// feature is disabled.
#ifndef ADOPTABLE_UPCOMING_FEATURE
#ifndef MIGRATABLE_UPCOMING_FEATURE
#if defined(UPCOMING_FEATURE)
#define ADOPTABLE_UPCOMING_FEATURE(FeatureName, SENumber, Version) \
#define MIGRATABLE_UPCOMING_FEATURE(FeatureName, SENumber, Version) \
UPCOMING_FEATURE(FeatureName, SENumber, Version)
#else
#define ADOPTABLE_UPCOMING_FEATURE(FeatureName, SENumber, Version) \
#define MIGRATABLE_UPCOMING_FEATURE(FeatureName, SENumber, Version) \
LANGUAGE_FEATURE(FeatureName, SENumber, #FeatureName)
#endif
#endif

// See `ADOPTABLE_UPCOMING_FEATURE`.
#ifndef ADOPTABLE_EXPERIMENTAL_FEATURE
// See `MIGRATABLE_UPCOMING_FEATURE`.
#ifndef MIGRATABLE_EXPERIMENTAL_FEATURE
#if defined(EXPERIMENTAL_FEATURE)
#define ADOPTABLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
#define MIGRATABLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd)
#else
#define ADOPTABLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
#define MIGRATABLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
LANGUAGE_FEATURE(FeatureName, 0, #FeatureName)
#endif
#endif
Expand Down Expand Up @@ -278,11 +278,11 @@ UPCOMING_FEATURE(NonfrozenEnumExhaustivity, 192, 6)
UPCOMING_FEATURE(GlobalActorIsolatedTypesUsability, 0434, 6)

// Swift 7
ADOPTABLE_UPCOMING_FEATURE(ExistentialAny, 335, 7)
MIGRATABLE_UPCOMING_FEATURE(ExistentialAny, 335, 7)
UPCOMING_FEATURE(InternalImportsByDefault, 409, 7)
UPCOMING_FEATURE(MemberImportVisibility, 444, 7)
UPCOMING_FEATURE(InferIsolatedConformances, 470, 7)
ADOPTABLE_UPCOMING_FEATURE(NonisolatedNonsendingByDefault, 461, 7)
MIGRATABLE_UPCOMING_FEATURE(NonisolatedNonsendingByDefault, 461, 7)

// Optional language features / modes

Expand Down Expand Up @@ -518,8 +518,8 @@ EXPERIMENTAL_FEATURE(CopyBlockOptimization, true)
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
#undef EXPERIMENTAL_FEATURE
#undef UPCOMING_FEATURE
#undef ADOPTABLE_UPCOMING_FEATURE
#undef ADOPTABLE_EXPERIMENTAL_FEATURE
#undef MIGRATABLE_UPCOMING_FEATURE
#undef MIGRATABLE_EXPERIMENTAL_FEATURE
#undef BASELINE_LANGUAGE_FEATURE
#undef OPTIONAL_LANGUAGE_FEATURE
#undef CONDITIONALLY_SUPPRESSIBLE_EXPERIMENTAL_FEATURE
Expand Down
4 changes: 2 additions & 2 deletions include/swift/Basic/FileTypes.def
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ TYPE("fine-module-trace", FineModuleTrace, "", "")
// Complete dependency information for the given Swift files as JSON.
TYPE("json-dependencies", JSONDependencies, "dependencies.json", "")

// Complete feature information for the given Swift compiler.
TYPE("json-features", JSONFeatures, "features.json", "")
// Complete supported argument information for the given Swift compiler.
TYPE("json-arguments", JSONArguments, "arguments.json", "")

// Gathered compile-time-known value information for the given Swift input file as JSON.
TYPE("const-values", ConstValues, "swiftconstvalues", "")
Expand Down
12 changes: 6 additions & 6 deletions include/swift/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -830,7 +830,7 @@ namespace swift {

/// A wrapper around the feature state enumeration.
struct FeatureState {
enum class Kind : uint8_t { Off, EnabledForAdoption, Enabled };
enum class Kind : uint8_t { Off, EnabledForMigration, Enabled };

private:
Feature feature;
Expand All @@ -843,9 +843,9 @@ namespace swift {
/// Returns whether the feature is enabled.
bool isEnabled() const;

/// Returns whether the feature is enabled in adoption mode. Should only
/// Returns whether the feature is enabled in migration mode. Should only
/// be called if the feature is known to support this mode.
bool isEnabledForAdoption() const;
bool isEnabledForMigration() const;

operator Kind() const { return state; }
};
Expand Down Expand Up @@ -878,9 +878,9 @@ namespace swift {
/// `false` if a feature by this name is not known.
bool hasFeature(llvm::StringRef featureName) const;

/// Enables the given feature (enables in adoption mode if `forAdoption` is
/// `true`).
void enableFeature(Feature feature, bool forAdoption = false);
/// Enables the given feature (enables in migration mode if `forMigration`
/// is `true`).
void enableFeature(Feature feature, bool forMigration = false);

/// Disables the given feature.
void disableFeature(Feature feature);
Expand Down
28 changes: 28 additions & 0 deletions include/swift/Basic/SupportedFeatures.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//===--- SupportedFeatures.h - Supported Features Output --------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file provides a high-level API for supported features info
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_SUPPORTEDFEATURES_H
#define SWIFT_SUPPORTEDFEATURES_H

#include "swift/Basic/LLVM.h"

namespace swift {
namespace features {
void printSupportedFeatures(llvm::raw_ostream &out);
} // namespace features
} // namespace swift

#endif
6 changes: 5 additions & 1 deletion include/swift/Frontend/FrontendOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ class FrontendOptions {

ScanDependencies, ///< Scan dependencies of Swift source files
PrintVersion, ///< Print version information.
PrintFeature, ///< Print supported feature of this compiler
PrintArguments, ///< Print supported arguments of this compiler
};

/// Indicates the action the user requested that the frontend perform.
Expand Down Expand Up @@ -314,6 +314,10 @@ class FrontendOptions {
/// exit.
bool PrintTargetInfo = false;

/// Indicates that the frontend should print the supported features and then
/// exit.
bool PrintSupportedFeatures = false;

/// See the \ref SILOptions.EmitVerboseSIL flag.
bool EmitVerboseSIL = false;

Expand Down
12 changes: 10 additions & 2 deletions include/swift/Option/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -1530,6 +1530,10 @@ def print_target_info : Flag<["-"], "print-target-info">,
Flags<[FrontendOption]>,
HelpText<"Print target information for the given target <triple>, such as x86_64-apple-macos10.9">, MetaVarName<"<triple>">;

def print_supported_features : Flag<["-"], "print-supported-features">,
Flags<[FrontendOption]>,
HelpText<"Print information about features supported by the compiler">;

def target_cpu : Separate<["-"], "target-cpu">, Flags<[FrontendOption, ModuleInterfaceOption]>,
HelpText<"Generate code for a particular CPU variant">;

Expand Down Expand Up @@ -1646,9 +1650,13 @@ def scan_dependencies : Flag<["-"], "scan-dependencies">,
HelpText<"Scan dependencies of the given Swift sources">, ModeOpt,
Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>;

def emit_supported_features : Flag<["-"], "emit-supported-features">,
HelpText<"Emit a JSON file including all supported compiler features">, ModeOpt,
def emit_supported_arguments : Flag<["-"], "emit-supported-arguments">,
HelpText<"Emit a JSON file including all supported compiler arguments">, ModeOpt,
Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>;
def emit_supported_features : Flag<["-"], "emit-supported-features">,
HelpText<"This is a compatibility alias for '-emit-supported-arguments'">, ModeOpt,
Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild, HelpHidden]>,
Alias<emit_supported_arguments>;

def enable_incremental_imports :
Flag<["-"], "enable-incremental-imports">,
Expand Down
2 changes: 1 addition & 1 deletion include/swift/SILOptimizer/OptimizerBridgingImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ bool BridgedPassContext::enableMergeableTraps() const {

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

bool BridgedPassContext::enableMoveInoutStackProtection() const {
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3338,7 +3338,7 @@ static void printCompatibilityCheckIf(ASTPrinter &printer, bool isElseIf,
} else {
first = false;
}
printer << "$" << getFeatureName(feature);
printer << "$" << Feature(feature).getName();
}

#ifndef NDEBUG
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/FeatureSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ void FeatureSet::collectRequiredFeature(Feature feature,

void FeatureSet::collectSuppressibleFeature(Feature feature,
InsertOrRemove operation) {
suppressible.insertOrRemove(numFeatures() - size_t(feature),
suppressible.insertOrRemove(Feature::getNumFeatures() - size_t(feature),
operation == Insert);
}

Expand Down
7 changes: 4 additions & 3 deletions lib/AST/FeatureSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@

namespace swift {

using BasicFeatureSet = FixedBitSet<numFeatures(), Feature>;
using BasicFeatureSet =
FixedBitSet<Feature::getNumFeatures(), Feature::InnerKind>;

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

public:
Expand All @@ -42,7 +43,7 @@ class FeatureSet {

public:
bool empty() const { return i == e; }
Feature next() { return Feature(numFeatures() - *i++); }
Feature next() { return Feature(Feature::getNumFeatures() - *i++); }
};

bool empty() const { return required.empty() && suppressible.empty(); }
Expand Down
1 change: 1 addition & 0 deletions lib/Basic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ add_swift_host_library(swiftBasic STATIC
StableHasher.cpp
Statistic.cpp
StringExtras.cpp
SupportedFeatures.cpp
TargetInfo.cpp
TaskQueue.cpp
ThreadSafeRefCounted.cpp
Expand Down
Loading