diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 9b6a6d3ebcef1..d82eb555990fc 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -593,6 +593,14 @@ namespace swift { /// type-checking, SIL verification, and IR emission, bool BypassResilienceChecks = false; + /// Whether or not to allow experimental features that are only available + /// in "production". +#ifdef NDEBUG + bool RestrictNonProductionExperimentalFeatures = true; +#else + bool RestrictNonProductionExperimentalFeatures = false; +#endif + bool isConcurrencyModelTaskToThread() const { return ActiveConcurrencyModel == ConcurrencyModel::TaskToThread; } diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index f3f8424980250..c899778331179 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -872,17 +872,14 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, // If this is a known experimental feature, allow it in +Asserts // (non-release) builds for testing purposes. if (auto feature = getExperimentalFeature(value)) { -#ifdef NDEBUG - if (!buildingFromInterface && !isFeatureAvailableInProduction(*feature)) { + if (Opts.RestrictNonProductionExperimentalFeatures && + !isFeatureAvailableInProduction(*feature)) { Diags.diagnose(SourceLoc(), diag::experimental_not_supported_in_production, A->getValue()); HadError = true; } else { Opts.enableFeature(*feature); } -#else - Opts.enableFeature(*feature); -#endif if (*feature == Feature::NoncopyableGenerics2) Opts.enableFeature(Feature::NoncopyableGenerics); diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index f08716782e633..030e1075ef509 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -2066,6 +2066,12 @@ InterfaceSubContextDelegateImpl::runInSubCompilerInstance(StringRef moduleName, bool StrictImplicitModuleContext = subInvocation.getFrontendOptions().StrictImplicitModuleContext; + // It isn't appropriate to restrict use of experimental features in another + // module since it may have been built with a different compiler that allowed + // the use of the feature. + subInvocation.getLangOptions().RestrictNonProductionExperimentalFeatures = + false; + // Save the target triple from the original context. llvm::Triple originalTargetTriple(subInvocation.getLangOptions().Target); diff --git a/test/Frontend/experimental-features-asserts.swift b/test/Frontend/experimental-features-asserts.swift new file mode 100644 index 0000000000000..ad764d1ce76d5 --- /dev/null +++ b/test/Frontend/experimental-features-asserts.swift @@ -0,0 +1,12 @@ +// This test verifies that command line parsing allows use of any features with +// an asserts compilers. + +// REQUIRES: asserts + +// 'AccessLevelOnImport' is allowed in production +// RUN: %target-swift-frontend -typecheck %s -enable-experimental-feature AccessLevelOnImport -verify + +// 'ParserValidation' is NOT allowed in production, but we are building with an asserts compiler. +// RUN: %target-swift-frontend -typecheck %s -enable-experimental-feature ParserValidation + +import Swift diff --git a/test/Frontend/experimental-features-no-asserts.swift b/test/Frontend/experimental-features-no-asserts.swift new file mode 100644 index 0000000000000..60957d37edcf9 --- /dev/null +++ b/test/Frontend/experimental-features-no-asserts.swift @@ -0,0 +1,14 @@ +// This test verifies that command line parsing restricts use of features that +// are not allowed non-production compilers. + +// REQUIRES: no_asserts + +// 'AccessLevelOnImport' is allowed in production +// RUN: %target-swift-frontend -typecheck %s -enable-experimental-feature AccessLevelOnImport -verify + +// 'ParserValidation' is NOT allowed in production +// RUN: not %target-swift-frontend -typecheck %s -enable-experimental-feature ParserValidation 2>&1 | %FileCheck %s + +// CHECK: :0: error: experimental feature 'ParserValidation' cannot be enabled in production compiler + +import Swift diff --git a/test/ModuleInterface/ExperimentalFeatures.swiftinterface b/test/ModuleInterface/experimental-features.swift similarity index 56% rename from test/ModuleInterface/ExperimentalFeatures.swiftinterface rename to test/ModuleInterface/experimental-features.swift index ea62897cc0166..812c28c168ee8 100644 --- a/test/ModuleInterface/ExperimentalFeatures.swiftinterface +++ b/test/ModuleInterface/experimental-features.swift @@ -1,14 +1,25 @@ -// swift-interface-format-version: 1.0 -// swift-module-flags: -module-name ExperimentalFeatures -enable-experimental-feature ParserRoundTrip +// RUN: %empty-directory(%t) +// RUN: split-file %s %t // Building a module from this interface should always succeed, even though // ParserRoundTrip is an experimental feature that is not enabled in production // compilers. -// RUN: %target-swift-frontend -compile-module-from-interface -module-name ExperimentalFeatures -o /dev/null %s -verify -// RUN: %target-swift-frontend -typecheck-module-from-interface -module-name ExperimentalFeatures %s -verify +// RUN: %target-swift-frontend -typecheck %t/Client.swift -I %t +// RUN: %target-swift-frontend -compile-module-from-interface -module-name ExperimentalFeatures -o /dev/null %t/ExperimentalFeatures.swiftinterface -verify +// RUN: %target-swift-frontend -typecheck-module-from-interface -module-name ExperimentalFeatures %t/ExperimentalFeatures.swiftinterface -verify + +//--- ExperimentalFeatures.swiftinterface +// swift-interface-format-version: 1.0 +// swift-module-flags: -module-name ExperimentalFeatures -enable-experimental-feature ParserRoundTrip import Swift extension Int { public static var fortytwo: Int = 42 } + +//--- Client.swift + +import ExperimentalFeatures + +_ = Int.fortytwo