mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
The "featues" part was never actually implemented and Swift Driver is replying on information about arguments, so instead of removing this mode, let's scope it down to "arguments" to be deprecated in the future.
1001 lines
39 KiB
C++
1001 lines
39 KiB
C++
//===--- ArgsToFrontendOptionsConverter -----------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "ArgsToFrontendOptionsConverter.h"
|
|
|
|
#include "ArgsToFrontendInputsConverter.h"
|
|
#include "ArgsToFrontendOutputsConverter.h"
|
|
#include "clang/Driver/Driver.h"
|
|
#include "swift/AST/DiagnosticsFrontend.h"
|
|
#include "swift/Basic/Assertions.h"
|
|
#include "swift/Basic/Platform.h"
|
|
#include "swift/Frontend/Frontend.h"
|
|
#include "swift/Option/Options.h"
|
|
#include "swift/Option/SanitizerOptions.h"
|
|
#include "swift/Parse/Lexer.h"
|
|
#include "swift/Parse/ParseVersion.h"
|
|
#include "swift/Strings.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/TargetParser/Triple.h"
|
|
#include "llvm/CAS/ObjectStore.h"
|
|
#include "llvm/Option/Arg.h"
|
|
#include "llvm/Option/ArgList.h"
|
|
#include "llvm/Option/Option.h"
|
|
#include "llvm/Support/Compression.h"
|
|
#include "llvm/Support/Process.h"
|
|
#include "llvm/Support/FileSystem.h"
|
|
#include "llvm/Support/LineIterator.h"
|
|
#include "llvm/Support/Path.h"
|
|
|
|
using namespace swift;
|
|
using namespace llvm::opt;
|
|
|
|
// This is a separate function so that it shows up in stack traces.
|
|
LLVM_ATTRIBUTE_NOINLINE
|
|
static void debugFailWithAssertion() {
|
|
// This assertion should always fail, per the user's request, and should
|
|
// not be converted to llvm_unreachable.
|
|
assert(0 && "This is an assertion!");
|
|
}
|
|
|
|
// This is a separate function so that it shows up in stack traces.
|
|
LLVM_ATTRIBUTE_NOINLINE
|
|
static void debugFailWithCrash() { LLVM_BUILTIN_TRAP; }
|
|
|
|
bool ArgsToFrontendOptionsConverter::convert(
|
|
SmallVectorImpl<std::unique_ptr<llvm::MemoryBuffer>> *buffers) {
|
|
using namespace options;
|
|
|
|
handleDebugCrashGroupArguments();
|
|
|
|
if (const Arg *A = Args.getLastArg(OPT_dump_api_path)) {
|
|
Opts.DumpAPIPath = A->getValue();
|
|
}
|
|
if (const Arg *A = Args.getLastArg(OPT_group_info_path)) {
|
|
Opts.GroupInfoPath = A->getValue();
|
|
}
|
|
if (const Arg *A = Args.getLastArg(OPT_index_store_path)) {
|
|
Opts.IndexStorePath = A->getValue();
|
|
}
|
|
if (const Arg *A = Args.getLastArg(OPT_prebuilt_module_cache_path)) {
|
|
Opts.PrebuiltModuleCachePath = A->getValue();
|
|
}
|
|
if (auto envPrebuiltModuleCachePath =
|
|
llvm::sys::Process::GetEnv("SWIFT_OVERLOAD_PREBUILT_MODULE_CACHE_PATH")) {
|
|
Opts.PrebuiltModuleCachePath = *envPrebuiltModuleCachePath;
|
|
}
|
|
|
|
if (const Arg *A = Args.getLastArg(OPT_module_cache_path)) {
|
|
Opts.ExplicitModulesOutputPath = A->getValue();
|
|
} else {
|
|
SmallString<128> defaultPath;
|
|
clang::driver::Driver::getDefaultModuleCachePath(defaultPath);
|
|
Opts.ExplicitModulesOutputPath = defaultPath.str().str();
|
|
}
|
|
if (const Arg *A = Args.getLastArg(OPT_sdk_module_cache_path)) {
|
|
Opts.ExplicitSDKModulesOutputPath = A->getValue();
|
|
} else {
|
|
Opts.ExplicitSDKModulesOutputPath = Opts.ExplicitModulesOutputPath;
|
|
}
|
|
if (const Arg *A = Args.getLastArg(OPT_backup_module_interface_path)) {
|
|
Opts.BackupModuleInterfaceDir = A->getValue();
|
|
}
|
|
if (const Arg *A = Args.getLastArg(OPT_bridging_header_directory_for_print)) {
|
|
Opts.BridgingHeaderDirForPrint = A->getValue();
|
|
}
|
|
Opts.IndexIgnoreClangModules |= Args.hasArg(OPT_index_ignore_clang_modules);
|
|
Opts.IndexSystemModules |= Args.hasArg(OPT_index_system_modules);
|
|
Opts.IndexIgnoreStdlib |= Args.hasArg(OPT_index_ignore_stdlib);
|
|
Opts.IndexIncludeLocals |= Args.hasArg(OPT_index_include_locals);
|
|
Opts.SerializeDebugInfoSIL |=
|
|
Args.hasArg(OPT_experimental_serialize_debug_info);
|
|
|
|
Opts.EmitVerboseSIL |= Args.hasArg(OPT_emit_verbose_sil);
|
|
Opts.EmitSortedSIL |= Args.hasArg(OPT_emit_sorted_sil);
|
|
Opts.PrintFullConvention |=
|
|
Args.hasArg(OPT_experimental_print_full_convention);
|
|
|
|
Opts.EnableTesting |= Args.hasArg(OPT_enable_testing);
|
|
Opts.EnablePrivateImports |= Args.hasArg(OPT_enable_private_imports);
|
|
Opts.EnableLibraryEvolution |= Args.hasArg(OPT_enable_library_evolution);
|
|
Opts.FrontendParseableOutput |= Args.hasArg(OPT_frontend_parseable_output);
|
|
Opts.ExplicitInterfaceBuild |= Args.hasArg(OPT_explicit_interface_module_build);
|
|
|
|
Opts.EmitClangHeaderWithNonModularIncludes |=
|
|
Args.hasArg(OPT_emit_clang_header_nonmodular_includes);
|
|
|
|
// FIXME: Remove this flag
|
|
Opts.EnableLibraryEvolution |= Args.hasArg(OPT_enable_resilience);
|
|
|
|
Opts.EnableImplicitDynamic |= Args.hasArg(OPT_enable_implicit_dynamic);
|
|
|
|
if (Args.hasArg(OPT_track_system_dependencies)) {
|
|
Opts.IntermoduleDependencyTracking =
|
|
IntermoduleDepTrackingMode::IncludeSystem;
|
|
} else if (Args.hasArg(OPT_explicit_interface_module_build)) {
|
|
// Always track at least the non-system dependencies for interface building.
|
|
Opts.IntermoduleDependencyTracking =
|
|
IntermoduleDepTrackingMode::ExcludeSystem;
|
|
}
|
|
|
|
if (const Arg *A = Args.getLastArg(OPT_bad_file_descriptor_retry_count)) {
|
|
unsigned limit;
|
|
if (StringRef(A->getValue()).getAsInteger(10, limit)) {
|
|
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
|
|
A->getAsString(Args), A->getValue());
|
|
return true;
|
|
}
|
|
Opts.BadFileDescriptorRetryCount = limit;
|
|
}
|
|
|
|
if (auto A = Args.getLastArg(OPT_user_module_version)) {
|
|
StringRef raw(A->getValue());
|
|
while(raw.count('.') > 3) {
|
|
raw = raw.rsplit('.').first;
|
|
}
|
|
if (Opts.UserModuleVersion.tryParse(raw)) {
|
|
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
|
|
A->getAsString(Args), A->getValue());
|
|
}
|
|
}
|
|
|
|
for (auto A : Args.getAllArgValues(options::OPT_allowable_client)) {
|
|
Opts.AllowableClients.insert(StringRef(A).str());
|
|
}
|
|
|
|
Opts.DisableImplicitModules |= Args.hasArg(OPT_disable_implicit_swift_modules);
|
|
|
|
Opts.ImportPrescan |= Args.hasArg(OPT_import_prescan);
|
|
|
|
Opts.SerializeDependencyScannerCache |= Args.hasArg(OPT_serialize_dependency_scan_cache);
|
|
Opts.ReuseDependencyScannerCache |= Args.hasArg(OPT_reuse_dependency_scan_cache);
|
|
Opts.ValidatePriorDependencyScannerCache |= Args.hasArg(OPT_validate_prior_dependency_scan_cache);
|
|
Opts.EmitDependencyScannerCacheRemarks |= Args.hasArg(OPT_dependency_scan_cache_remarks);
|
|
Opts.ParallelDependencyScan = Args.hasFlag(OPT_parallel_scan,
|
|
OPT_no_parallel_scan,
|
|
true);
|
|
if (const Arg *A = Args.getLastArg(OPT_dependency_scan_cache_path)) {
|
|
Opts.SerializedDependencyScannerCachePath = A->getValue();
|
|
}
|
|
|
|
Opts.ScannerOutputDir = Args.getLastArgValue(OPT_scanner_output_dir);
|
|
Opts.WriteScannerOutput |= Args.hasArg(OPT_scanner_debug_write_output);
|
|
|
|
Opts.DisableCrossModuleIncrementalBuild |=
|
|
Args.hasArg(OPT_disable_incremental_imports);
|
|
|
|
// Always track system dependencies when scanning dependencies.
|
|
if (const Arg *ModeArg = Args.getLastArg(OPT_modes_Group)) {
|
|
if (ModeArg->getOption().matches(OPT_scan_dependencies)) {
|
|
Opts.IntermoduleDependencyTracking =
|
|
IntermoduleDepTrackingMode::IncludeSystem;
|
|
}
|
|
}
|
|
|
|
Opts.SerializeModuleInterfaceDependencyHashes |=
|
|
Args.hasArg(OPT_serialize_module_interface_dependency_hashes);
|
|
|
|
Opts.RemarkOnRebuildFromModuleInterface |=
|
|
Args.hasArg(OPT_Rmodule_interface_rebuild);
|
|
|
|
Opts.DowngradeInterfaceVerificationError |=
|
|
Args.hasArg(OPT_downgrade_typecheck_interface_error);
|
|
computePrintStatsOptions();
|
|
computeDebugTimeOptions();
|
|
computeTBDOptions();
|
|
|
|
Opts.DumpClangLookupTables |= Args.hasArg(OPT_dump_clang_lookup_tables);
|
|
|
|
Opts.CheckOnoneSupportCompleteness = Args.hasArg(OPT_check_onone_completeness);
|
|
|
|
Opts.ParseStdlib |= Args.hasArg(OPT_parse_stdlib);
|
|
|
|
Opts.IgnoreSwiftSourceInfo |= Args.hasArg(OPT_ignore_module_source_info);
|
|
computeHelpOptions();
|
|
|
|
if (Args.hasArg(OPT_print_target_info)) {
|
|
Opts.PrintTargetInfo = true;
|
|
}
|
|
|
|
if (Args.hasArg(OPT_print_supported_features)) {
|
|
Opts.PrintSupportedFeatures = true;
|
|
}
|
|
|
|
if (const Arg *A = Args.getLastArg(OPT_verify_generic_signatures)) {
|
|
Opts.VerifyGenericSignaturesInModule = A->getValue();
|
|
}
|
|
|
|
Opts.AllowModuleWithCompilerErrors |= Args.hasArg(OPT_experimental_allow_module_with_compiler_errors);
|
|
|
|
computeDumpScopeMapLocations();
|
|
|
|
// Ensure that the compiler was built with zlib support if it was the
|
|
// requested AST format.
|
|
if (const Arg *A = Args.getLastArg(OPT_dump_ast_format)) {
|
|
auto format = llvm::StringSwitch<std::optional<FrontendOptions::ASTFormat>>(
|
|
A->getValue())
|
|
.Case("json", FrontendOptions::ASTFormat::JSON)
|
|
.Case("json-zlib", FrontendOptions::ASTFormat::JSONZlib)
|
|
.Case("default", FrontendOptions::ASTFormat::Default)
|
|
.Case("default-with-decl-contexts",
|
|
FrontendOptions::ASTFormat::DefaultWithDeclContext)
|
|
.Default(std::nullopt);
|
|
if (!format.has_value()) {
|
|
Diags.diagnose(SourceLoc(), diag::unknown_dump_ast_format, A->getValue());
|
|
return true;
|
|
}
|
|
if (format != FrontendOptions::ASTFormat::Default &&
|
|
(!Args.hasArg(OPT_dump_ast) && !Args.hasArg(OPT_dump_parse))) {
|
|
Diags.diagnose(SourceLoc(), diag::ast_format_requires_dump_ast);
|
|
return true;
|
|
}
|
|
if (Opts.DumpASTFormat == FrontendOptions::ASTFormat::JSONZlib &&
|
|
!llvm::compression::zlib::isAvailable()) {
|
|
Diags.diagnose(SourceLoc(), diag::json_zlib_not_supported);
|
|
return true;
|
|
}
|
|
Opts.DumpASTFormat = *format;
|
|
}
|
|
|
|
std::optional<FrontendInputsAndOutputs> inputsAndOutputs =
|
|
ArgsToFrontendInputsConverter(Diags, Args).convert(buffers);
|
|
|
|
// None here means error, not just "no inputs". Propagate unconditionally.
|
|
if (!inputsAndOutputs)
|
|
return true;
|
|
|
|
// InputsAndOutputs can only get set up once; if it was set already when we
|
|
// entered this function, we should not set it again (and should assert this
|
|
// is not being done). Further, the computeMainAndSupplementaryOutputFilenames
|
|
// call below needs to only happen when there was a new InputsAndOutputs,
|
|
// since it clobbers the existing one rather than adding to it.
|
|
bool HaveNewInputsAndOutputs = false;
|
|
if (Opts.InputsAndOutputs.hasInputs()) {
|
|
assert(!inputsAndOutputs->hasInputs());
|
|
} else {
|
|
HaveNewInputsAndOutputs = true;
|
|
Opts.InputsAndOutputs = std::move(inputsAndOutputs).value();
|
|
if (Opts.AllowModuleWithCompilerErrors)
|
|
Opts.InputsAndOutputs.setShouldRecoverMissingInputs();
|
|
}
|
|
|
|
if (Args.hasArg(OPT_parse_sil) || Opts.InputsAndOutputs.shouldTreatAsSIL()) {
|
|
Opts.InputMode = FrontendOptions::ParseInputMode::SIL;
|
|
} else if (Opts.InputsAndOutputs.shouldTreatAsModuleInterface()) {
|
|
Opts.InputMode = FrontendOptions::ParseInputMode::SwiftModuleInterface;
|
|
} else if (Args.hasArg(OPT_parse_as_library)) {
|
|
Opts.InputMode = FrontendOptions::ParseInputMode::SwiftLibrary;
|
|
} else {
|
|
Opts.InputMode = FrontendOptions::ParseInputMode::Swift;
|
|
}
|
|
|
|
if (Opts.RequestedAction == FrontendOptions::ActionType::NoneAction) {
|
|
Opts.RequestedAction = determineRequestedAction(Args);
|
|
}
|
|
|
|
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.
|
|
Opts.DisableInterfaceFileLock = true;
|
|
} else {
|
|
Opts.DisableInterfaceFileLock |= Args.hasArg(OPT_disable_interface_lockfile);
|
|
}
|
|
|
|
if (Opts.RequestedAction == FrontendOptions::ActionType::Immediate &&
|
|
Opts.InputsAndOutputs.hasPrimaryInputs()) {
|
|
Diags.diagnose(SourceLoc(), diag::error_immediate_mode_primary_file);
|
|
return true;
|
|
}
|
|
|
|
if (setUpImmediateArgs())
|
|
return true;
|
|
|
|
if (computeModuleName())
|
|
return true;
|
|
|
|
if (HaveNewInputsAndOutputs &&
|
|
computeMainAndSupplementaryOutputFilenames())
|
|
return true;
|
|
|
|
if (checkUnusedSupplementaryOutputPaths())
|
|
return true;
|
|
|
|
if (checkBuildFromInterfaceOnlyOptions())
|
|
return true;
|
|
|
|
Opts.DeterministicCheck |= Args.hasArg(OPT_enable_deterministic_check);
|
|
Opts.CacheReplayPrefixMap = Args.getAllArgValues(OPT_cache_replay_prefix_map);
|
|
|
|
if (FrontendOptions::doesActionGenerateIR(Opts.RequestedAction)) {
|
|
if (Args.hasArg(OPT_experimental_skip_non_inlinable_function_bodies) ||
|
|
Args.hasArg(OPT_experimental_skip_all_function_bodies) ||
|
|
Args.hasArg(
|
|
OPT_experimental_skip_non_inlinable_function_bodies_without_types)) {
|
|
Diags.diagnose(SourceLoc(), diag::cannot_emit_ir_skipping_function_bodies);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (const Arg *A = Args.getLastArg(OPT_module_abi_name))
|
|
Opts.ModuleABIName = A->getValue();
|
|
|
|
if (const Arg *A = Args.getLastArg(OPT_module_link_name))
|
|
Opts.ModuleLinkName = A->getValue();
|
|
|
|
if (const Arg *A = Args.getLastArg(OPT_export_as)) {
|
|
auto exportAs = A->getValue();
|
|
if (!Lexer::isIdentifier(exportAs))
|
|
Diags.diagnose(SourceLoc(), diag::error_bad_export_as_name, exportAs);
|
|
else
|
|
Opts.ExportAsName = exportAs;
|
|
}
|
|
|
|
if (const Arg *A = Args.getLastArg(OPT_public_module_name))
|
|
Opts.PublicModuleName = A->getValue();
|
|
|
|
if (auto A = Args.getLastArg(OPT_swiftinterface_compiler_version)) {
|
|
if (auto version = VersionParser::parseVersionString(
|
|
A->getValue(), SourceLoc(), /*Diags=*/nullptr)) {
|
|
Opts.SwiftInterfaceCompilerVersion = version.value();
|
|
}
|
|
|
|
if (Opts.SwiftInterfaceCompilerVersion.empty() ||
|
|
Opts.SwiftInterfaceCompilerVersion.size() > 5)
|
|
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
|
|
A->getAsString(Args), A->getValue());
|
|
}
|
|
|
|
// This must be called after computing module name, module abi name,
|
|
// and module link name. If computing module aliases is unsuccessful,
|
|
// return early.
|
|
if (!computeModuleAliases())
|
|
return true;
|
|
|
|
if (const Arg *A = Args.getLastArg(OPT_access_notes_path))
|
|
Opts.AccessNotesPath = A->getValue();
|
|
|
|
if (const Arg *A = Args.getLastArg(OPT_serialize_debugging_options,
|
|
OPT_no_serialize_debugging_options)) {
|
|
Opts.SerializeOptionsForDebugging =
|
|
A->getOption().matches(OPT_serialize_debugging_options);
|
|
}
|
|
|
|
Opts.DebugPrefixSerializedDebuggingOptions |=
|
|
Args.hasArg(OPT_prefix_serialized_debugging_options);
|
|
Opts.EnableSourceImport |= Args.hasArg(OPT_enable_source_import);
|
|
Opts.ImportUnderlyingModule |= Args.hasArg(OPT_import_underlying_module);
|
|
Opts.EnableIncrementalDependencyVerifier |= Args.hasArg(OPT_verify_incremental_dependencies);
|
|
Opts.UseSharedResourceFolder = !Args.hasArg(OPT_use_static_resource_dir);
|
|
Opts.DisableBuildingInterface = Args.hasArg(OPT_disable_building_interface);
|
|
if (const Arg *A = Args.getLastArg(options::OPT_clang_header_expose_decls)) {
|
|
Opts.ClangHeaderExposedDecls =
|
|
llvm::StringSwitch<
|
|
std::optional<FrontendOptions::ClangHeaderExposeBehavior>>(
|
|
A->getValue())
|
|
.Case("all-public",
|
|
FrontendOptions::ClangHeaderExposeBehavior::AllPublic)
|
|
.Case("has-expose-attr",
|
|
FrontendOptions::ClangHeaderExposeBehavior::HasExposeAttr)
|
|
.Case("has-expose-attr-or-stdlib",
|
|
FrontendOptions::ClangHeaderExposeBehavior::
|
|
HasExposeAttrOrImplicitDeps)
|
|
.Default(std::nullopt);
|
|
}
|
|
for (const auto &arg :
|
|
Args.getAllArgValues(options::OPT_clang_header_expose_module)) {
|
|
auto splitArg = StringRef(arg).split('=');
|
|
if (splitArg.second.empty()) {
|
|
continue;
|
|
}
|
|
Opts.clangHeaderExposedImports.push_back(
|
|
{splitArg.first.str(), splitArg.second.str()});
|
|
}
|
|
|
|
Opts.StrictImplicitModuleContext = Args.hasArg(OPT_strict_implicit_module_context,
|
|
OPT_no_strict_implicit_module_context,
|
|
false);
|
|
|
|
computeImportObjCHeaderOptions();
|
|
computeImplicitImportModuleNames(OPT_import_module, /*isTestable=*/false);
|
|
computeImplicitImportModuleNames(OPT_testable_import_module, /*isTestable=*/true);
|
|
computeLLVMArgs();
|
|
|
|
Opts.EmitSymbolGraph |= Args.hasArg(OPT_emit_symbol_graph);
|
|
|
|
if (const Arg *A = Args.getLastArg(OPT_emit_symbol_graph_dir)) {
|
|
Opts.SymbolGraphOutputDir = A->getValue();
|
|
}
|
|
|
|
Opts.SkipInheritedDocs = Args.hasArg(OPT_skip_inherited_docs);
|
|
Opts.IncludeSPISymbolsInSymbolGraph = Args.hasArg(OPT_include_spi_symbols);
|
|
|
|
Opts.Static = Args.hasArg(OPT_static);
|
|
|
|
Opts.HermeticSealAtLink = Args.hasArg(OPT_experimental_hermetic_seal_at_link);
|
|
|
|
for (auto A : Args.getAllArgValues(options::OPT_serialized_path_obfuscate)) {
|
|
auto SplitMap = StringRef(A).split('=');
|
|
Opts.serializedPathObfuscator.addMapping(SplitMap.first, SplitMap.second);
|
|
}
|
|
Opts.emptyABIDescriptor = Args.hasArg(OPT_empty_abi_descriptor);
|
|
for (auto A : Args.getAllArgValues(options::OPT_block_list_file)) {
|
|
Opts.BlocklistConfigFilePaths.push_back(A);
|
|
}
|
|
|
|
Opts.DisableSandbox = Args.hasArg(OPT_disable_sandbox);
|
|
|
|
if (computeAvailabilityDomains())
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
void ArgsToFrontendOptionsConverter::handleDebugCrashGroupArguments() {
|
|
using namespace options;
|
|
|
|
if (const Arg *A = Args.getLastArg(OPT_debug_crash_Group)) {
|
|
Option Opt = A->getOption();
|
|
if (Opt.matches(OPT_debug_assert_immediately)) {
|
|
debugFailWithAssertion();
|
|
} else if (Opt.matches(OPT_debug_crash_immediately)) {
|
|
debugFailWithCrash();
|
|
} else if (Opt.matches(OPT_debug_assert_after_parse)) {
|
|
// Set in FrontendOptions
|
|
Opts.CrashMode = FrontendOptions::DebugCrashMode::AssertAfterParse;
|
|
} else if (Opt.matches(OPT_debug_crash_after_parse)) {
|
|
// Set in FrontendOptions
|
|
Opts.CrashMode = FrontendOptions::DebugCrashMode::CrashAfterParse;
|
|
} else {
|
|
llvm_unreachable("Unknown debug_crash_Group option!");
|
|
}
|
|
}
|
|
}
|
|
|
|
void ArgsToFrontendOptionsConverter::computePrintStatsOptions() {
|
|
using namespace options;
|
|
Opts.PrintStats |= Args.hasArg(OPT_print_stats);
|
|
Opts.PrintClangStats |= Args.hasArg(OPT_print_clang_stats);
|
|
Opts.PrintZeroStats |= Args.hasArg(OPT_print_zero_stats);
|
|
#if defined(NDEBUG) && !LLVM_ENABLE_STATS
|
|
if (Opts.PrintStats || Opts.PrintClangStats)
|
|
Diags.diagnose(SourceLoc(), diag::stats_disabled);
|
|
#endif
|
|
}
|
|
|
|
void ArgsToFrontendOptionsConverter::computeDebugTimeOptions() {
|
|
using namespace options;
|
|
if (const Arg *A = Args.getLastArg(OPT_stats_output_dir)) {
|
|
Opts.StatsOutputDir = A->getValue();
|
|
if (Args.getLastArg(OPT_fine_grained_timers)) {
|
|
Opts.FineGrainedTimers = true;
|
|
}
|
|
if (Args.getLastArg(OPT_trace_stats_events)) {
|
|
Opts.TraceStats = true;
|
|
}
|
|
if (Args.getLastArg(OPT_profile_stats_events)) {
|
|
Opts.ProfileEvents = true;
|
|
}
|
|
if (Args.getLastArg(OPT_profile_stats_entities)) {
|
|
Opts.ProfileEntities = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ArgsToFrontendOptionsConverter::computeTBDOptions() {
|
|
using namespace options;
|
|
using Mode = FrontendOptions::TBDValidationMode;
|
|
|
|
if (const Arg *A = Args.getLastArg(OPT_validate_tbd_against_ir_EQ)) {
|
|
StringRef value = A->getValue();
|
|
if (value == "none") {
|
|
Opts.ValidateTBDAgainstIR = Mode::None;
|
|
} else if (value == "missing") {
|
|
Opts.ValidateTBDAgainstIR = Mode::MissingFromTBD;
|
|
} else if (value == "all") {
|
|
Opts.ValidateTBDAgainstIR = Mode::All;
|
|
} else {
|
|
Diags.diagnose(SourceLoc(), diag::error_unsupported_option_argument,
|
|
A->getOption().getPrefixedName(), value);
|
|
}
|
|
} else if (Args.hasArg(OPT_enable_experimental_cxx_interop) ||
|
|
Args.hasArg(OPT_cxx_interoperability_mode)) {
|
|
// TBD validation currently emits diagnostics when C++ interop is enabled,
|
|
// which is likely caused by IRGen incorrectly applying attributes to
|
|
// symbols, forcing the user to pass `-validate-tbd-against-ir=none`.
|
|
// If no explicit TBD validation mode was specified, disable it if C++
|
|
// interop is enabled.
|
|
// See https://github.com/apple/swift/issues/56458.
|
|
// FIXME: the TBD validation diagnostics are correct and should be enabled.
|
|
Opts.ValidateTBDAgainstIR = Mode::None;
|
|
}
|
|
}
|
|
|
|
void ArgsToFrontendOptionsConverter::computeHelpOptions() {
|
|
using namespace options;
|
|
if (const Arg *A = Args.getLastArg(OPT_help, OPT_help_hidden)) {
|
|
if (A->getOption().matches(OPT_help)) {
|
|
Opts.PrintHelp = true;
|
|
} else if (A->getOption().matches(OPT_help_hidden)) {
|
|
Opts.PrintHelpHidden = true;
|
|
} else {
|
|
llvm_unreachable("Unknown help option parsed");
|
|
}
|
|
}
|
|
}
|
|
|
|
void ArgsToFrontendOptionsConverter::computeDumpScopeMapLocations() {
|
|
using namespace options;
|
|
const Arg *A = Args.getLastArg(OPT_modes_Group);
|
|
if (!A || !A->getOption().matches(OPT_dump_scope_maps))
|
|
return;
|
|
StringRef value = A->getValue();
|
|
if (value == "expanded") {
|
|
// Note: fully expanded the scope map.
|
|
return;
|
|
}
|
|
// Parse a comma-separated list of line:column for lookups to
|
|
// perform (and dump the result of).
|
|
SmallVector<StringRef, 4> locations;
|
|
value.split(locations, ',');
|
|
|
|
bool invalid = false;
|
|
for (auto location : locations) {
|
|
auto lineColumnStr = location.split(':');
|
|
unsigned line, column;
|
|
if (lineColumnStr.first.getAsInteger(10, line) ||
|
|
lineColumnStr.second.getAsInteger(10, column)) {
|
|
Diags.diagnose(SourceLoc(), diag::error_invalid_source_location_str,
|
|
location);
|
|
invalid = true;
|
|
continue;
|
|
}
|
|
Opts.DumpScopeMapLocations.push_back({line, column});
|
|
}
|
|
|
|
if (!invalid && Opts.DumpScopeMapLocations.empty())
|
|
Diags.diagnose(SourceLoc(), diag::error_no_source_location_scope_map);
|
|
}
|
|
|
|
bool ArgsToFrontendOptionsConverter::computeAvailabilityDomains() {
|
|
using namespace options;
|
|
|
|
bool hadError = false;
|
|
llvm::SmallSet<std::string, 4> seenDomains;
|
|
|
|
for (const Arg *A :
|
|
Args.filtered_reverse(OPT_define_enabled_availability_domain,
|
|
OPT_define_disabled_availability_domain,
|
|
OPT_define_dynamic_availability_domain)) {
|
|
std::string domain = A->getValue();
|
|
if (!seenDomains.insert(domain).second)
|
|
continue;
|
|
|
|
if (!Lexer::isIdentifier(domain)) {
|
|
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
|
|
A->getAsString(Args), A->getValue());
|
|
hadError = true;
|
|
continue;
|
|
}
|
|
|
|
auto &option = A->getOption();
|
|
if (option.matches(OPT_define_enabled_availability_domain))
|
|
Opts.AvailabilityDomains.EnabledDomains.emplace_back(domain);
|
|
else if (option.matches(OPT_define_disabled_availability_domain))
|
|
Opts.AvailabilityDomains.DisabledDomains.emplace_back(domain);
|
|
else if (option.matches(OPT_define_dynamic_availability_domain))
|
|
Opts.AvailabilityDomains.DynamicDomains.emplace_back(domain);
|
|
}
|
|
|
|
return hadError;
|
|
}
|
|
|
|
FrontendOptions::ActionType
|
|
ArgsToFrontendOptionsConverter::determineRequestedAction(const ArgList &args) {
|
|
using namespace options;
|
|
const Arg *A = args.getLastArg(OPT_modes_Group);
|
|
if (!A) {
|
|
// We don't have a mode, so determine a default.
|
|
if (args.hasArg(OPT_emit_module, OPT_emit_module_path)) {
|
|
// We've been told to emit a module, but have no other mode indicators.
|
|
// As a result, put the frontend into EmitModuleOnly mode.
|
|
// (Setting up module output will be handled below.)
|
|
return FrontendOptions::ActionType::EmitModuleOnly;
|
|
}
|
|
|
|
if (args.hasArg(OPT_version))
|
|
return FrontendOptions::ActionType::PrintVersion;
|
|
|
|
return FrontendOptions::ActionType::NoneAction;
|
|
}
|
|
Option Opt = A->getOption();
|
|
if (Opt.matches(OPT_emit_object))
|
|
return FrontendOptions::ActionType::EmitObject;
|
|
if (Opt.matches(OPT_emit_assembly))
|
|
return FrontendOptions::ActionType::EmitAssembly;
|
|
if (Opt.matches(OPT_emit_irgen))
|
|
return FrontendOptions::ActionType::EmitIRGen;
|
|
if (Opt.matches(OPT_emit_ir))
|
|
return FrontendOptions::ActionType::EmitIR;
|
|
if (Opt.matches(OPT_emit_bc))
|
|
return FrontendOptions::ActionType::EmitBC;
|
|
if (Opt.matches(OPT_emit_sil))
|
|
return FrontendOptions::ActionType::EmitSIL;
|
|
if (Opt.matches(OPT_emit_silgen))
|
|
return FrontendOptions::ActionType::EmitSILGen;
|
|
if (Opt.matches(OPT_emit_lowered_sil))
|
|
return FrontendOptions::ActionType::EmitLoweredSIL;
|
|
if (Opt.matches(OPT_emit_sib))
|
|
return FrontendOptions::ActionType::EmitSIB;
|
|
if (Opt.matches(OPT_emit_sibgen))
|
|
return FrontendOptions::ActionType::EmitSIBGen;
|
|
if (Opt.matches(OPT_emit_pch))
|
|
return FrontendOptions::ActionType::EmitPCH;
|
|
if (Opt.matches(OPT_emit_imported_modules))
|
|
return FrontendOptions::ActionType::EmitImportedModules;
|
|
if (Opt.matches(OPT_scan_dependencies))
|
|
return FrontendOptions::ActionType::ScanDependencies;
|
|
if (Opt.matches(OPT_parse))
|
|
return FrontendOptions::ActionType::Parse;
|
|
if (Opt.matches(OPT_resolve_imports))
|
|
return FrontendOptions::ActionType::ResolveImports;
|
|
if (Opt.matches(OPT_typecheck))
|
|
return FrontendOptions::ActionType::Typecheck;
|
|
if (Opt.matches(OPT_dump_parse))
|
|
return FrontendOptions::ActionType::DumpParse;
|
|
if (Opt.matches(OPT_dump_ast))
|
|
return FrontendOptions::ActionType::DumpAST;
|
|
if (Opt.matches(OPT_merge_modules))
|
|
return FrontendOptions::ActionType::MergeModules;
|
|
if (Opt.matches(OPT_dump_scope_maps))
|
|
return FrontendOptions::ActionType::DumpScopeMaps;
|
|
if (Opt.matches(OPT_dump_availability_scopes))
|
|
return FrontendOptions::ActionType::DumpAvailabilityScopes;
|
|
if (Opt.matches(OPT_dump_interface_hash))
|
|
return FrontendOptions::ActionType::DumpInterfaceHash;
|
|
if (Opt.matches(OPT_dump_type_info))
|
|
return FrontendOptions::ActionType::DumpTypeInfo;
|
|
if (Opt.matches(OPT_print_ast))
|
|
return FrontendOptions::ActionType::PrintAST;
|
|
if (Opt.matches(OPT_print_ast_decl))
|
|
return FrontendOptions::ActionType::PrintASTDecl;
|
|
if (Opt.matches(OPT_emit_pcm))
|
|
return FrontendOptions::ActionType::EmitPCM;
|
|
if (Opt.matches(OPT_dump_pcm))
|
|
return FrontendOptions::ActionType::DumpPCM;
|
|
|
|
if (Opt.matches(OPT_repl) || Opt.matches(OPT_deprecated_integrated_repl))
|
|
return FrontendOptions::ActionType::REPL;
|
|
if (Opt.matches(OPT_interpret))
|
|
return FrontendOptions::ActionType::Immediate;
|
|
if (Opt.matches(OPT_compile_module_from_interface))
|
|
return FrontendOptions::ActionType::CompileModuleFromInterface;
|
|
if (Opt.matches(OPT_typecheck_module_from_interface))
|
|
return FrontendOptions::ActionType::TypecheckModuleFromInterface;
|
|
if (Opt.matches(OPT_emit_supported_arguments))
|
|
return FrontendOptions::ActionType::PrintArguments;
|
|
llvm_unreachable("Unhandled mode option");
|
|
}
|
|
|
|
bool ArgsToFrontendOptionsConverter::setUpImmediateArgs() {
|
|
using namespace options;
|
|
bool treatAsSIL =
|
|
Args.hasArg(OPT_parse_sil) || Opts.InputsAndOutputs.shouldTreatAsSIL();
|
|
|
|
if (Opts.InputsAndOutputs.verifyInputs(
|
|
Diags, treatAsSIL,
|
|
Opts.RequestedAction == FrontendOptions::ActionType::REPL,
|
|
!FrontendOptions::doesActionRequireInputs(Opts.RequestedAction))) {
|
|
return true;
|
|
}
|
|
if (Opts.RequestedAction == FrontendOptions::ActionType::Immediate) {
|
|
Opts.ImmediateArgv.push_back(
|
|
Opts.InputsAndOutputs.getFilenameOfFirstInput()); // argv[0]
|
|
if (const Arg *A = Args.getLastArg(OPT__DASH_DASH)) {
|
|
for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) {
|
|
Opts.ImmediateArgv.push_back(A->getValue(i));
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ArgsToFrontendOptionsConverter::computeModuleAliases() {
|
|
auto list = Args.getAllArgValues(options::OPT_module_alias);
|
|
return ModuleAliasesConverter::computeModuleAliases(list, Opts, Diags);
|
|
}
|
|
|
|
bool ArgsToFrontendOptionsConverter::computeModuleName() {
|
|
// Module name must be computed before computing module
|
|
// aliases. Instead of asserting, clearing ModuleAliasMap
|
|
// here since it can be called redundantly in batch-mode
|
|
Opts.ModuleAliasMap.clear();
|
|
|
|
const Arg *A = Args.getLastArg(options::OPT_module_name);
|
|
if (A) {
|
|
Opts.ModuleName = A->getValue();
|
|
} else if (Opts.ModuleName.empty()) {
|
|
// The user did not specify a module name, so determine a default fallback
|
|
// based on other options.
|
|
|
|
// Note: this code path will only be taken when running the frontend
|
|
// directly; the driver should always pass -module-name when invoking the
|
|
// frontend.
|
|
if (computeFallbackModuleName())
|
|
return true;
|
|
}
|
|
|
|
if (Lexer::isIdentifier(Opts.ModuleName) &&
|
|
(Opts.ModuleName != STDLIB_NAME || Opts.ParseStdlib)) {
|
|
return false;
|
|
}
|
|
if (!FrontendOptions::needsProperModuleName(Opts.RequestedAction) ||
|
|
Opts.isCompilingExactlyOneSwiftFile()) {
|
|
Opts.ModuleName = "main";
|
|
return false;
|
|
}
|
|
auto DID = (Opts.ModuleName == STDLIB_NAME) ? diag::error_stdlib_module_name
|
|
: diag::error_bad_module_name;
|
|
Diags.diagnose(SourceLoc(), DID, Opts.ModuleName, A == nullptr);
|
|
Opts.ModuleName = "__bad__";
|
|
return false; // FIXME: Must continue to run to pass the tests, but should not
|
|
// have to.
|
|
}
|
|
|
|
bool ArgsToFrontendOptionsConverter::computeFallbackModuleName() {
|
|
if (Opts.RequestedAction == FrontendOptions::ActionType::REPL) {
|
|
// Default to a module named "REPL" if we're in REPL mode.
|
|
Opts.ModuleName = "REPL";
|
|
return false;
|
|
}
|
|
// In order to pass some tests, must leave ModuleName empty.
|
|
if (!Opts.InputsAndOutputs.hasInputs()) {
|
|
Opts.ModuleName = std::string();
|
|
// FIXME: This is a bug that should not happen, but does in tests.
|
|
// The compiler should bail out earlier, where "no frontend action was
|
|
// selected".
|
|
return false;
|
|
}
|
|
std::optional<std::vector<std::string>> outputFilenames =
|
|
OutputFilesComputer::getOutputFilenamesFromCommandLineOrFilelist(
|
|
Args, Diags, options::OPT_o, options::OPT_output_filelist);
|
|
|
|
std::string nameToStem =
|
|
outputFilenames && outputFilenames->size() == 1 &&
|
|
outputFilenames->front() != "-" &&
|
|
!llvm::sys::fs::is_directory(outputFilenames->front())
|
|
? outputFilenames->front()
|
|
: Opts.InputsAndOutputs.getFilenameOfFirstInput();
|
|
|
|
Opts.ModuleName = llvm::sys::path::stem(nameToStem).str();
|
|
return false;
|
|
}
|
|
|
|
bool ArgsToFrontendOptionsConverter::
|
|
computeMainAndSupplementaryOutputFilenames() {
|
|
std::vector<std::string> mainOutputs;
|
|
std::vector<std::string> mainOutputForIndexUnits;
|
|
std::vector<SupplementaryOutputPaths> supplementaryOutputs;
|
|
const bool hadError = ArgsToFrontendOutputsConverter(
|
|
Args, Opts.ModuleName, Opts.InputsAndOutputs, Diags)
|
|
.convert(mainOutputs, mainOutputForIndexUnits,
|
|
supplementaryOutputs);
|
|
if (hadError)
|
|
return true;
|
|
Opts.InputsAndOutputs.setMainAndSupplementaryOutputs(mainOutputs,
|
|
supplementaryOutputs,
|
|
mainOutputForIndexUnits);
|
|
// set output type.
|
|
const file_types::ID outputType =
|
|
FrontendOptions::formatForPrincipalOutputFileForAction(
|
|
Opts.RequestedAction);
|
|
Opts.InputsAndOutputs.setPrincipalOutputType(outputType);
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ArgsToFrontendOptionsConverter::checkBuildFromInterfaceOnlyOptions()
|
|
const {
|
|
if (!FrontendOptions::doesActionBuildModuleFromInterface(
|
|
Opts.RequestedAction) &&
|
|
Opts.ExplicitInterfaceBuild) {
|
|
Diags.diagnose(SourceLoc(),
|
|
diag::error_cannot_explicit_interface_build_in_mode);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ArgsToFrontendOptionsConverter::checkUnusedSupplementaryOutputPaths()
|
|
const {
|
|
if (!FrontendOptions::canActionEmitDependencies(Opts.RequestedAction) &&
|
|
Opts.InputsAndOutputs.hasDependenciesFilePath()) {
|
|
Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_dependencies);
|
|
return true;
|
|
}
|
|
if (!FrontendOptions::canActionEmitReferenceDependencies(Opts.RequestedAction)
|
|
&& Opts.InputsAndOutputs.hasReferenceDependenciesFilePath()) {
|
|
Diags.diagnose(SourceLoc(),
|
|
diag::error_mode_cannot_emit_reference_dependencies);
|
|
return true;
|
|
}
|
|
if (!FrontendOptions::canActionEmitClangHeader(Opts.RequestedAction) &&
|
|
Opts.InputsAndOutputs.hasClangHeaderOutputPath()) {
|
|
Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_header);
|
|
return true;
|
|
}
|
|
if (!FrontendOptions::canActionEmitLoadedModuleTrace(Opts.RequestedAction) &&
|
|
Opts.InputsAndOutputs.hasLoadedModuleTracePath()) {
|
|
Diags.diagnose(SourceLoc(),
|
|
diag::error_mode_cannot_emit_loaded_module_trace);
|
|
return true;
|
|
}
|
|
if (!FrontendOptions::canActionEmitModule(Opts.RequestedAction) &&
|
|
Opts.InputsAndOutputs.hasModuleOutputPath()) {
|
|
Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_module);
|
|
return true;
|
|
}
|
|
if (!FrontendOptions::canActionEmitModuleDoc(Opts.RequestedAction) &&
|
|
Opts.InputsAndOutputs.hasModuleDocOutputPath()) {
|
|
Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_module_doc);
|
|
return true;
|
|
}
|
|
if (!FrontendOptions::canActionEmitABIDescriptor(Opts.RequestedAction) &&
|
|
Opts.InputsAndOutputs.hasABIDescriptorOutputPath()) {
|
|
Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_abi_descriptor);
|
|
return true;
|
|
}
|
|
if (!FrontendOptions::canActionEmitAPIDescriptor(Opts.RequestedAction) &&
|
|
Opts.InputsAndOutputs.hasAPIDescriptorOutputPath()) {
|
|
Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_api_descriptor);
|
|
return true;
|
|
}
|
|
if (!FrontendOptions::canActionEmitConstValues(Opts.RequestedAction) &&
|
|
Opts.InputsAndOutputs.hasConstValuesOutputPath()) {
|
|
Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_const_values);
|
|
return true;
|
|
}
|
|
if (!FrontendOptions::canActionEmitModuleSemanticInfo(Opts.RequestedAction) &&
|
|
Opts.InputsAndOutputs.hasModuleSemanticInfoOutputPath()) {
|
|
Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_module_semantic_info);
|
|
return true;
|
|
}
|
|
// If we cannot emit module doc, we cannot emit source information file either.
|
|
if (!FrontendOptions::canActionEmitModuleDoc(Opts.RequestedAction) &&
|
|
Opts.InputsAndOutputs.hasModuleSourceInfoOutputPath()) {
|
|
Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_module_source_info);
|
|
return true;
|
|
}
|
|
if (!FrontendOptions::canActionEmitInterface(Opts.RequestedAction) &&
|
|
(Opts.InputsAndOutputs.hasModuleInterfaceOutputPath() ||
|
|
Opts.InputsAndOutputs.hasPrivateModuleInterfaceOutputPath() ||
|
|
Opts.InputsAndOutputs.hasPackageModuleInterfaceOutputPath())) {
|
|
Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_interface);
|
|
return true;
|
|
}
|
|
if (!FrontendOptions::canActionEmitModuleSummary(Opts.RequestedAction) &&
|
|
Opts.InputsAndOutputs.hasModuleSummaryOutputPath()) {
|
|
Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_module_summary);
|
|
return true;
|
|
}
|
|
if (!FrontendOptions::canActionEmitModule(Opts.RequestedAction) &&
|
|
!Opts.SymbolGraphOutputDir.empty()) {
|
|
Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_symbol_graph);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static inline bool isPCHFilenameExtension(StringRef path) {
|
|
return llvm::sys::path::extension(path)
|
|
.ends_with(file_types::getExtension(file_types::TY_PCH));
|
|
}
|
|
|
|
void ArgsToFrontendOptionsConverter::computeImportObjCHeaderOptions() {
|
|
using namespace options;
|
|
if (const Arg *A = Args.getLastArgNoClaim(OPT_import_objc_header)) {
|
|
// Legacy support for passing PCH file through `-import-objc-header`.
|
|
if (isPCHFilenameExtension(A->getValue()))
|
|
Opts.ImplicitObjCPCHPath = A->getValue();
|
|
else
|
|
Opts.ImplicitObjCHeaderPath = A->getValue();
|
|
// If `-import-object-header` is used, it means the module has a direct
|
|
// bridging header dependency and it can be serialized into binary module.
|
|
Opts.ModuleHasBridgingHeader |= true;
|
|
}
|
|
if (const Arg *A = Args.getLastArgNoClaim(OPT_import_pch))
|
|
Opts.ImplicitObjCPCHPath = A->getValue();
|
|
}
|
|
void ArgsToFrontendOptionsConverter::
|
|
computeImplicitImportModuleNames(OptSpecifier id, bool isTestable) {
|
|
using namespace options;
|
|
for (const Arg *A : Args.filtered(id)) {
|
|
auto *moduleStr = A->getValue();
|
|
if (!Lexer::isIdentifier(moduleStr)) {
|
|
Diags.diagnose(SourceLoc(), diag::error_bad_module_name, moduleStr,
|
|
/*suggestModuleNameFlag*/ false);
|
|
continue;
|
|
}
|
|
Opts.ImplicitImportModuleNames.emplace_back(moduleStr, isTestable);
|
|
}
|
|
}
|
|
void ArgsToFrontendOptionsConverter::computeLLVMArgs() {
|
|
using namespace options;
|
|
for (const Arg *A : Args.filtered(OPT_Xllvm)) {
|
|
Opts.LLVMArgs.push_back(A->getValue());
|
|
}
|
|
}
|
|
|
|
bool ModuleAliasesConverter::computeModuleAliases(std::vector<std::string> args,
|
|
FrontendOptions &options,
|
|
DiagnosticEngine &diags) {
|
|
if (!args.empty()) {
|
|
// ModuleAliasMap should initially be empty as setting
|
|
// it should be called only once
|
|
options.ModuleAliasMap.clear();
|
|
|
|
// validatingModuleName should be true if validating the alias target (an
|
|
// actual module name), or true if validating the alias name (which can be
|
|
// an escaped identifier).
|
|
auto validate = [&options, &diags](StringRef value,
|
|
bool validatingModuleName) -> bool {
|
|
if (!validatingModuleName) {
|
|
if (value == options.ModuleName ||
|
|
value == options.ModuleABIName ||
|
|
value == options.ModuleLinkName ||
|
|
value == STDLIB_NAME) {
|
|
diags.diagnose(SourceLoc(), diag::error_module_alias_forbidden_name, value);
|
|
return false;
|
|
}
|
|
}
|
|
if ((validatingModuleName && !Lexer::isIdentifier(value)) ||
|
|
!Lexer::isValidAsEscapedIdentifier(value)) {
|
|
diags.diagnose(SourceLoc(), diag::error_bad_module_name, value, false);
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
|
|
for (auto item: args) {
|
|
auto str = StringRef(item);
|
|
// splits to an alias and its real name
|
|
auto pair = str.split('=');
|
|
auto lhs = pair.first;
|
|
auto rhs = pair.second;
|
|
|
|
if (rhs.empty()) { // '=' is missing
|
|
diags.diagnose(SourceLoc(), diag::error_module_alias_invalid_format, str);
|
|
return false;
|
|
}
|
|
if (!validate(lhs, false) || !validate(rhs, true)) {
|
|
return false;
|
|
}
|
|
|
|
// First, add the real name as a key to prevent it from being
|
|
// used as an alias
|
|
if (!options.ModuleAliasMap.insert({rhs, StringRef()}).second) {
|
|
diags.diagnose(SourceLoc(), diag::error_module_alias_duplicate, rhs);
|
|
return false;
|
|
}
|
|
// Next, add the alias as a key and the real name as a value to the map
|
|
auto underlyingName = options.ModuleAliasMap.find(rhs)->first();
|
|
if (!options.ModuleAliasMap.insert({lhs, underlyingName}).second) {
|
|
diags.diagnose(SourceLoc(), diag::error_module_alias_duplicate, lhs);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|