From 81fc10ac3e4d6901c5736d5fa917675f9a9bb9dc Mon Sep 17 00:00:00 2001 From: Allan Shortlidge Date: Wed, 27 Mar 2024 11:31:17 -0700 Subject: [PATCH] Frontend: Allow any experimental feature to be enabled when compiling a module. When building a module from its interface, do not diagnose whether or not a feature is available in production compilers. This is important since older compilers may be expected to build .swiftinterfaces that were produced by newer compilers where the feature has been enabled by default. Resolves rdar://125500318 --- include/swift/Frontend/FrontendOptions.h | 1 + .../ArgsToFrontendOptionsConverter.cpp | 10 ++--- lib/Frontend/CompilerInvocation.cpp | 16 ++++---- lib/Frontend/Frontend.cpp | 6 +-- lib/Frontend/FrontendOptions.cpp | 41 +++++++++++++++++++ .../ExperimentalFeatures.swiftinterface | 14 +++++++ 6 files changed, 69 insertions(+), 19 deletions(-) create mode 100644 test/ModuleInterface/ExperimentalFeatures.swiftinterface 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 +}