[ModuleInterface] Add mechanism to exclude experimental flags from th… (#66088)

* [ModuleInterface] Add mechanism to exclude experimental flags from the module interface

rdar://109722548

* Separate filtered flags from the typical/unfiltered case
This commit is contained in:
Dario Rexin
2023-05-24 09:03:01 -07:00
committed by GitHub
parent efe6d58152
commit 2bb08e37f6
5 changed files with 51 additions and 4 deletions

View File

@@ -66,6 +66,10 @@ llvm::Optional<Feature> getExperimentalFeature(llvm::StringRef name);
/// \c None if it does not have such a version.
llvm::Optional<unsigned> getFeatureLanguageVersion(Feature feature);
/// Determine whether this feature should be included in the
/// module interface
bool includeInModuleInterface(Feature feature);
}
#endif // SWIFT_BASIC_FEATURES_H

View File

@@ -62,6 +62,11 @@
langOpts.hasFeature(#FeatureName))
#endif
#ifndef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
# define EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE(FeatureName, AvailableInProd) \
EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd)
#endif
LANGUAGE_FEATURE(AsyncAwait, 296, "async/await", true)
LANGUAGE_FEATURE(EffectfulProp, 310, "Effectful properties", true)
LANGUAGE_FEATURE(MarkerProtocol, 0, "@_marker protocol", true)
@@ -134,8 +139,8 @@ EXPERIMENTAL_FEATURE(ModuleInterfaceExportAs, true)
EXPERIMENTAL_FEATURE(AccessLevelOnImport, true)
/// Whether to enable experimental layout string value witnesses
EXPERIMENTAL_FEATURE(LayoutStringValueWitnesses, true)
EXPERIMENTAL_FEATURE(LayoutStringValueWitnessesInstantiation, true)
EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE(LayoutStringValueWitnesses, true)
EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE(LayoutStringValueWitnessesInstantiation, true)
/// Whether to enable experimental differentiable programming features:
/// `@differentiable` declaration attribute, etc.
@@ -196,6 +201,7 @@ EXPERIMENTAL_FEATURE(ReferenceBindings, false)
/// Enable the explicit 'import Builtin' and allow Builtin usage.
EXPERIMENTAL_FEATURE(BuiltinModule, true)
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
#undef EXPERIMENTAL_FEATURE
#undef UPCOMING_FEATURE
#undef SUPPRESSIBLE_LANGUAGE_FEATURE

View File

@@ -461,7 +461,7 @@ bool swift::isFeatureAvailableInProduction(Feature feature) {
switch (feature) {
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option) \
case Feature::FeatureName: return true;
#define EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
#define EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
case Feature::FeatureName: return AvailableInProd;
#include "swift/Basic/Features.def"
}
@@ -480,7 +480,7 @@ llvm::Optional<Feature> swift::getUpcomingFeature(llvm::StringRef name) {
llvm::Optional<Feature> swift::getExperimentalFeature(llvm::StringRef name) {
return llvm::StringSwitch<Optional<Feature>>(name)
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option)
#define EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
#define EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
.Case(#FeatureName, Feature::FeatureName)
#include "swift/Basic/Features.def"
.Default(None);
@@ -496,6 +496,17 @@ llvm::Optional<unsigned> swift::getFeatureLanguageVersion(Feature feature) {
}
}
bool swift::includeInModuleInterface(Feature feature) {
switch (feature) {
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option) \
case Feature::FeatureName: return true;
#define EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE(FeatureName, AvailableInProd) \
case Feature::FeatureName: return false;
#include "swift/Basic/Features.def"
}
llvm_unreachable("covered switch");
}
DiagnosticBehavior LangOptions::getAccessNoteFailureLimit() const {
switch (AccessNoteBehavior) {
case AccessNoteDiagnosticBehavior::Ignore:

View File

@@ -417,6 +417,19 @@ static void ParseModuleInterfaceArgs(ModuleInterfaceOptions &Opts,
}
}
/// Checks if an arg is generally allowed to be included
/// in a module interface
static bool ShouldIncludeModuleInterfaceArg(const Arg *A) {
if (!A->getOption().matches(options::OPT_enable_experimental_feature))
return true;
if (auto feature = getExperimentalFeature(A->getValue())) {
return swift::includeInModuleInterface(*feature);
}
return true;
}
/// Save a copy of any flags marked as ModuleInterfaceOption, if running
/// in a mode that is going to emit a .swiftinterface file.
static void SaveModuleInterfaceArgs(ModuleInterfaceOptions &Opts,
@@ -428,6 +441,9 @@ static void SaveModuleInterfaceArgs(ModuleInterfaceOptions &Opts,
ArgStringList RenderedArgsIgnorable;
ArgStringList RenderedArgsIgnorablePrivate;
for (auto A : Args) {
if (!ShouldIncludeModuleInterfaceArg(A))
continue;
if (A->getOption().hasFlag(options::ModuleInterfaceOptionIgnorablePrivate)) {
A->render(Args, RenderedArgsIgnorablePrivate);
} else if (A->getOption().hasFlag(options::ModuleInterfaceOptionIgnorable)) {

View File

@@ -0,0 +1,10 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -enable-library-evolution -emit-module-interface-path %t.swiftinterface -module-name t %s -target-min-inlining-version 42 -emit-module -o /dev/null -O -enable-experimental-feature LayoutStringValueWitnesses -enable-experimental-feature LayoutStringValueWitnessesInstantiation
// RUN: %FileCheck %s < %t.swiftinterface -check-prefix=CHECK-SWIFTINTERFACE
//
// CHECK-SWIFTINTERFACE: swift-module-flags-ignorable:
// CHECK-SWIFTINTERFACE-NOT: -enable-experimental-feature LayoutStringValueWitnesses
// CHECK-SWIFTINTERFACE-NOT: -enable-experimental-feature LayoutStringValueWitnessesInstantiation
public func foo() { }