diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h --- a/clang/include/clang/Frontend/CompilerInvocation.h +++ b/clang/include/clang/Frontend/CompilerInvocation.h @@ -22,6 +22,7 @@ #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/Option/OptSpecifier.h" #include #include @@ -197,6 +198,9 @@ /// The returned pointer is what gets appended to Args. void generateCC1CommandLine(llvm::SmallVectorImpl &Args, StringAllocator SA) const; + void generateCC1CommandLine(llvm::SmallVectorImpl &Args, + StringAllocator SA, + ArrayRef Included) const; /// @} /// @name Option Subgroups @@ -246,6 +250,8 @@ /// \returns - True if parsing was successful, false otherwise bool parseSimpleArgs(const llvm::opt::ArgList &Args, DiagnosticsEngine &Diags); + bool parseSimpleArgs(const llvm::opt::ArgList &Args, DiagnosticsEngine &Diags, + ArrayRef Included); }; IntrusiveRefCntPtr diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1439,6 +1439,33 @@ return Success; } +bool CompilerInvocation::parseSimpleArgs( + const ArgList &Args, DiagnosticsEngine &Diags, + ArrayRef Included) { + bool Success = true; + +#define OPTION_WITH_MARSHALLING( \ + PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ + DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ + MERGER, EXTRACTOR, TABLE_INDEX) \ + if ((FLAGS)&options::CC1Option && \ + find(Included, OPT_##ID) != Included.end()) { \ + this->KEYPATH = MERGER(this->KEYPATH, DEFAULT_VALUE); \ + if (IMPLIED_CHECK) \ + this->KEYPATH = MERGER(this->KEYPATH, IMPLIED_VALUE); \ + if (SHOULD_PARSE) \ + if (auto MaybeValue = \ + NORMALIZER(OPT_##ID, TABLE_INDEX, Args, Diags, Success)) \ + this->KEYPATH = MERGER( \ + this->KEYPATH, static_castKEYPATH)>(*MaybeValue)); \ + } +#include "clang/Driver/Options.inc" +#undef OPTION_WITH_MARSHALLING + + return Success; +} + bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, DiagnosticsEngine *Diags, bool DefaultDiagColor) { @@ -3099,8 +3126,92 @@ ParseTargetArgs(Res.getTargetOpts(), Args, Diags); Success &= ParseCodeGenArgs(Res.getCodeGenOpts(), Args, DashX, Diags, Res.getTargetOpts(), Res.getFrontendOpts()); + + // Specify all header search options. + OptSpecifier HeaderSearchOptSpecs[] = { + // Marshalled via TableGen. + OPT_fmodules_user_build_path, + OPT_fprebuilt_implicit_modules, + OPT_fno_prebuilt_implicit_modules, + OPT_fmodules_prune_interval, + OPT_fmodules_prune_after, + OPT_fbuild_session_timestamp, + OPT_fmodules_validate_once_per_build_session, + OPT_fmodules_disable_diagnostic_validation, + OPT_fmodules_validate_system_headers, + OPT_fno_modules_validate_system_headers, + OPT_fvalidate_ast_input_files_content, + OPT_fimplicit_module_maps, + OPT_isysroot, + OPT_nobuiltininc, + OPT_nostdincxx, + OPT_resource_dir, + OPT_v, + OPT_fmodule_map_file_home_is_cwd, + OPT_fmodule_format_EQ, + OPT_nostdsysteminc, + OPT_fdisable_module_hash, + OPT_fmodules_hash_content, + OPT_fmodules_strict_context_hash, + + // Marshalled manually. + OPT_stdlib_EQ, + OPT_fmodules_cache_path, + OPT_fmodule_file, + OPT_fprebuilt_module_path, + OPT_fmodules_ignore_macro, + OPT__sysroot_EQ, + OPT_I, + OPT_F, + OPT_index_header_map, + OPT_iprefix, + OPT_iwithprefix, + OPT_iwithprefixbefore, + OPT_idirafter, + OPT_iquote, + OPT_isystem, + OPT_iwithsysroot, + OPT_iframework, + OPT_iframeworkwithsysroot, + OPT_c_isystem, + OPT_cxx_isystem, + OPT_objc_isystem, + OPT_objcxx_isystem, + OPT_internal_isystem, + OPT_internal_externc_isystem, + OPT_system_header_prefix, + OPT_no_system_header_prefix, + OPT_ivfsoverlay, + }; + + // Prepare string allocator. + SmallVector GeneratedArgsStorage; + auto SA = [&GeneratedArgsStorage](const Twine &Arg) -> const char * { + return GeneratedArgsStorage.emplace_back(Arg.str()).c_str(); + }; + + // Parse header search options from original arguments. ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args, Res.getFileSystemOpts().WorkingDir); + + // Create arg string without header search options. + ArgStringList MarshalledArgStr; + Args.AddAllArgsExcept(MarshalledArgStr, HeaderSearchOptSpecs); + // Fill arg string with header search options. + Res.generateCC1CommandLine(MarshalledArgStr, SA, HeaderSearchOptSpecs); + GenerateHeaderSearchArgs(Res.getHeaderSearchOpts(), MarshalledArgStr, SA); + + InputArgList MarshalledArgs = Opts.ParseArgs( + MarshalledArgStr, MissingArgIndex, MissingArgCount, IncludedFlagsBitmask); + + // Empty the header search options parsed from original arguments. + auto OriginalHeaderSearchOpts = std::make_shared(); + Res.HeaderSearchOpts.swap(OriginalHeaderSearchOpts); + // Parse header search options from generated arguments. + Success &= Res.parseSimpleArgs(MarshalledArgs, Diags, HeaderSearchOptSpecs); + ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), MarshalledArgs, + Res.getFileSystemOpts().WorkingDir); + llvm::Triple T(Res.getTargetOpts().Triple); if (DashX.getFormat() == InputKind::Precompiled || DashX.getLanguage() == Language::LLVM_IR) { @@ -3335,6 +3446,32 @@ GenerateHeaderSearchArgs(getHeaderSearchOpts(), Args, SA); } +void CompilerInvocation::generateCC1CommandLine( + SmallVectorImpl &Args, StringAllocator SA, + ArrayRef Included) const { + // Capture the extracted value as a lambda argument to avoid potential issues + // with lifetime extension of the reference. +#define OPTION_WITH_MARSHALLING( \ + PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ + DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ + MERGER, EXTRACTOR, TABLE_INDEX) \ + if ((FLAGS)&options::CC1Option && \ + find(Included, OPT_##ID) != Included.end()) { \ + [&](const auto &Extracted) { \ + if (ALWAYS_EMIT || \ + (Extracted != \ + static_castKEYPATH)>( \ + (IMPLIED_CHECK) ? (IMPLIED_VALUE) : (DEFAULT_VALUE)))) \ + DENORMALIZER(Args, SPELLING, SA, Option::KIND##Class, TABLE_INDEX, \ + Extracted); \ + }(EXTRACTOR(this->KEYPATH)); \ + } + +#include "clang/Driver/Options.inc" +#undef OPTION_WITH_MARSHALLING +} + IntrusiveRefCntPtr clang::createVFSFromCompilerInvocation(const CompilerInvocation &CI, DiagnosticsEngine &Diags) { diff --git a/llvm/include/llvm/Option/ArgList.h b/llvm/include/llvm/Option/ArgList.h --- a/llvm/include/llvm/Option/ArgList.h +++ b/llvm/include/llvm/Option/ArgList.h @@ -308,6 +308,10 @@ A->render(*this, Output); } + /// AddAllArgsExcept - Render all arguments not matching any of the excluded + /// ids. + void AddAllArgsExcept(ArgStringList &Output, + ArrayRef ExcludeIds = {}) const; /// AddAllArgsExcept - Render all arguments matching any of the given ids /// and not matching any of the excluded ids. void AddAllArgsExcept(ArgStringList &Output, ArrayRef Ids, diff --git a/llvm/lib/Option/ArgList.cpp b/llvm/lib/Option/ArgList.cpp --- a/llvm/lib/Option/ArgList.cpp +++ b/llvm/lib/Option/ArgList.cpp @@ -95,6 +95,23 @@ return std::vector(Values.begin(), Values.end()); } +void ArgList::AddAllArgsExcept(ArgStringList &Output, + ArrayRef ExcludeIds) const { + for (const Arg *Arg : *this) { + bool Excluded = false; + for (OptSpecifier Id : ExcludeIds) { + if (Arg->getOption().matches(Id)) { + Excluded = true; + break; + } + } + if (!Excluded) { + Arg->claim(); + Arg->render(*this, Output); + } + } +} + void ArgList::AddAllArgsExcept(ArgStringList &Output, ArrayRef Ids, ArrayRef ExcludeIds) const {