diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index 7f2a3109912a4..76347d51f81e5 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -568,6 +568,7 @@ class FrontendOptions { static bool doesActionGenerateIR(ActionType); static bool doesActionProduceOutput(ActionType); static bool doesActionProduceTextualOutput(ActionType); + static bool doesActionBuildModuleFromInterface(ActionType); static bool needsProperModuleName(ActionType); static file_types::ID formatForPrincipalOutputFileForAction(ActionType); }; diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index 1686578dde36d..a0e2a2a167c3b 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -227,8 +227,8 @@ bool ArgsToFrontendOptionsConverter::convert( Opts.RequestedAction = determineRequestedAction(Args); } - if (Opts.RequestedAction == FrontendOptions::ActionType::CompileModuleFromInterface || - Opts.RequestedAction == FrontendOptions::ActionType::TypecheckModuleFromInterface) { + if (FrontendOptions::doesActionBuildModuleFromInterface( + Opts.RequestedAction)) { // The situations where we use this action, e.g. explicit module building and // generating prebuilt module cache, don't need synchronization. We should avoid // using lock files for them. @@ -695,10 +695,8 @@ bool ArgsToFrontendOptionsConverter:: bool ArgsToFrontendOptionsConverter::checkBuildFromInterfaceOnlyOptions() const { - if (Opts.RequestedAction != - FrontendOptions::ActionType::CompileModuleFromInterface && - Opts.RequestedAction != - FrontendOptions::ActionType::TypecheckModuleFromInterface && + if (!FrontendOptions::doesActionBuildModuleFromInterface( + Opts.RequestedAction) && Opts.ExplicitInterfaceBuild) { Diags.diagnose(SourceLoc(), diag::error_cannot_explicit_interface_build_in_mode); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 7a439b73b45bb..96ac571cbc01d 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -582,6 +582,9 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, DiagnosticEngine &Diags, const FrontendOptions &FrontendOpts) { using namespace options; + bool buildingFromInterface = + FrontendOptions::doesActionBuildModuleFromInterface( + FrontendOpts.RequestedAction); bool HadError = false; if (auto A = Args.getLastArg(OPT_swift_version)) { @@ -791,10 +794,7 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, OPT_disable_testable_attr_requires_testable_module)) { Opts.EnableTestableAttrRequiresTestableModule = A->getOption().matches(OPT_enable_testable_attr_requires_testable_module); - } else if (FrontendOpts.RequestedAction == - FrontendOptions::ActionType::TypecheckModuleFromInterface || - FrontendOpts.RequestedAction == - FrontendOptions::ActionType::CompileModuleFromInterface) { + } else if (buildingFromInterface) { Opts.EnableObjCAttrRequiresFoundation = false; } @@ -873,7 +873,7 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, // (non-release) builds for testing purposes. if (auto feature = getExperimentalFeature(value)) { #ifdef NDEBUG - if (!isFeatureAvailableInProduction(*feature)) { + if (!buildingFromInterface && !isFeatureAvailableInProduction(*feature)) { Diags.diagnose(SourceLoc(), diag::experimental_not_supported_in_production, A->getValue()); HadError = true; @@ -1142,10 +1142,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, } // If built from interface, non-resilient access should not be allowed. if (Opts.AllowNonResilientAccess && - (FrontendOpts.RequestedAction == - FrontendOptions::ActionType::CompileModuleFromInterface || - FrontendOpts.RequestedAction == - FrontendOptions::ActionType::TypecheckModuleFromInterface)) { + FrontendOptions::doesActionBuildModuleFromInterface( + FrontendOpts.RequestedAction)) { Diags.diagnose( SourceLoc(), diag::warn_ignore_option_overriden_by, "-experimental-allow-non-resilient-access", diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 7b8b3c2d39d3d..7727ee64fbff9 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -276,10 +276,8 @@ void CompilerInstance::recordPrimaryInputBuffer(unsigned BufID) { } bool CompilerInstance::setUpASTContextIfNeeded() { - if ((Invocation.getFrontendOptions().RequestedAction == - FrontendOptions::ActionType::CompileModuleFromInterface || - Invocation.getFrontendOptions().RequestedAction == - FrontendOptions::ActionType::TypecheckModuleFromInterface) && + if (FrontendOptions::doesActionBuildModuleFromInterface( + Invocation.getFrontendOptions().RequestedAction) && !Invocation.getFrontendOptions().ExplicitInterfaceBuild) { // Compiling a module interface from source uses its own CompilerInstance // with options read from the input file. Don't bother setting up an diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp index 8580edba2861b..30f596e2393cc 100644 --- a/lib/Frontend/FrontendOptions.cpp +++ b/lib/Frontend/FrontendOptions.cpp @@ -956,6 +956,47 @@ bool FrontendOptions::doesActionGenerateIR(ActionType action) { llvm_unreachable("unhandled action"); } +bool FrontendOptions::doesActionBuildModuleFromInterface(ActionType action) { + switch (action) { + case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: + return true; + case ActionType::NoneAction: + case ActionType::Parse: + case ActionType::DumpParse: + case ActionType::DumpInterfaceHash: + case ActionType::DumpAST: + case ActionType::PrintAST: + case ActionType::PrintASTDecl: + case ActionType::DumpScopeMaps: + case ActionType::DumpTypeRefinementContexts: + case ActionType::DumpTypeInfo: + case ActionType::Typecheck: + case ActionType::ResolveImports: + case ActionType::MergeModules: + case ActionType::EmitModuleOnly: + case ActionType::EmitPCH: + case ActionType::EmitSILGen: + case ActionType::EmitSIL: + case ActionType::EmitSIBGen: + case ActionType::EmitSIB: + case ActionType::EmitImportedModules: + case ActionType::EmitPCM: + case ActionType::DumpPCM: + case ActionType::ScanDependencies: + case ActionType::PrintVersion: + case ActionType::PrintFeature: + case ActionType::Immediate: + case ActionType::REPL: + case ActionType::EmitIRGen: + case ActionType::EmitIR: + case ActionType::EmitBC: + case ActionType::EmitAssembly: + case ActionType::EmitObject: + return false; + } + llvm_unreachable("unhandled action"); +} const PrimarySpecificPaths & FrontendOptions::getPrimarySpecificPathsForAtMostOnePrimary() const { diff --git a/test/ModuleInterface/ExperimentalFeatures.swiftinterface b/test/ModuleInterface/ExperimentalFeatures.swiftinterface new file mode 100644 index 0000000000000..ea62897cc0166 --- /dev/null +++ b/test/ModuleInterface/ExperimentalFeatures.swiftinterface @@ -0,0 +1,14 @@ +// swift-interface-format-version: 1.0 +// swift-module-flags: -module-name ExperimentalFeatures -enable-experimental-feature ParserRoundTrip + +// 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 + +import Swift +extension Int { + public static var fortytwo: Int = 42 +}