From b11b64273bea77764a76a728567e5ab79fcc9643 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 d81d113b1a887..1fb68c09cf1b9 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 +}