diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1915,7 +1915,8 @@ MarshallingInfoFlag<"FrontendOpts.IsSystemModule">; def fmodule_map_file : Joined<["-"], "fmodule-map-file=">, Group, Flags<[NoXarchOption,CC1Option]>, MetaVarName<"">, - HelpText<"Load this module map file">; + HelpText<"Load this module map file">, + MarshallingInfoStringVector<"FrontendOpts.ModuleMapFiles">; def fmodule_file : Joined<["-"], "fmodule-file=">, Group, Flags<[NoXarchOption,CC1Option]>, MetaVarName<"[=]">, HelpText<"Specify the mapping of module name to precompiled module file, or load a module file if name is omitted.">; 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 @@ -323,6 +323,23 @@ return Res; } +static Optional> +normalizeStringVector(OptSpecifier Opt, int, const ArgList &Args, + DiagnosticsEngine &) { + return Args.getAllArgValues(Opt); +} + +static void denormalizeStringVector(SmallVectorImpl &Args, + const char *Spelling, + CompilerInvocation::StringAllocator SA, + Option::OptionClass OptClass, + unsigned TableIndex, + const std::vector &Values) { + for (const std::string &Value : Values) { + denormalizeString(Args, Spelling, SA, OptClass, TableIndex, Value); + } +} + static Optional normalizeTriple(OptSpecifier Opt, int TableIndex, const ArgList &Args, DiagnosticsEngine &Diags) { @@ -1715,7 +1732,6 @@ Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm); Opts.ASTDumpDecls = Args.hasArg(OPT_ast_dump, OPT_ast_dump_EQ); Opts.ASTDumpAll = Args.hasArg(OPT_ast_dump_all, OPT_ast_dump_all_EQ); - Opts.ModuleMapFiles = Args.getAllArgValues(OPT_fmodule_map_file); // Only the -fmodule-file= form. for (const auto *A : Args.filtered(OPT_fmodule_file)) { StringRef Val = A->getValue(); diff --git a/clang/unittests/Frontend/CompilerInvocationTest.cpp b/clang/unittests/Frontend/CompilerInvocationTest.cpp --- a/clang/unittests/Frontend/CompilerInvocationTest.cpp +++ b/clang/unittests/Frontend/CompilerInvocationTest.cpp @@ -18,6 +18,7 @@ using namespace clang; using ::testing::Contains; +using ::testing::HasSubstr; using ::testing::StrEq; namespace { @@ -408,6 +409,45 @@ ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("legacy")))); } +TEST_F(CommandLineTest, StringVectorEmpty) { + const char *Args[] = {""}; + + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + + ASSERT_FALSE(Diags->hasErrorOccurred()); + ASSERT_TRUE(Invocation.getFrontendOpts().ModuleMapFiles.empty()); + + Invocation.generateCC1CommandLine(GeneratedArgs, *this); + ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-fmodule-map-file=")))); +} + +TEST_F(CommandLineTest, StringVectorSingle) { + const char *Args[] = {"-fmodule-map-file=a"}; + + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + + ASSERT_FALSE(Diags->hasErrorOccurred()); + ASSERT_EQ(Invocation.getFrontendOpts().ModuleMapFiles, + std::vector({"a"})); + + Invocation.generateCC1CommandLine(GeneratedArgs, *this); + ASSERT_EQ(count(GeneratedArgs, StringRef("-fmodule-map-file=a")), 1); +} + +TEST_F(CommandLineTest, StringVectorMultiple) { + const char *Args[] = {"-fmodule-map-file=a", "-fmodule-map-file=b"}; + + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + + ASSERT_FALSE(Diags->hasErrorOccurred()); + ASSERT_TRUE(Invocation.getFrontendOpts().ModuleMapFiles == + std::vector({"a", "b"})); + + Invocation.generateCC1CommandLine(GeneratedArgs, *this); + ASSERT_EQ(count(GeneratedArgs, StringRef("-fmodule-map-file=a")), 1); + ASSERT_EQ(count(GeneratedArgs, StringRef("-fmodule-map-file=b")), 1); +} + // Tree of boolean options that can be (directly or transitively) implied by // their parent: // diff --git a/llvm/include/llvm/Option/OptParser.td b/llvm/include/llvm/Option/OptParser.td --- a/llvm/include/llvm/Option/OptParser.td +++ b/llvm/include/llvm/Option/OptParser.td @@ -167,6 +167,12 @@ code Denormalizer = "denormalizeString"; } +class MarshallingInfoStringVector + : MarshallingInfo({})"> { + code Normalizer = "normalizeStringVector"; + code Denormalizer = "denormalizeStringVector"; +} + class MarshallingInfoFlag : MarshallingInfo { code Normalizer = "normalizeSimpleFlag";