Index: include/clang/Lex/DependencyDirectivesSourceMinimizer.h =================================================================== --- include/clang/Lex/DependencyDirectivesSourceMinimizer.h +++ include/clang/Lex/DependencyDirectivesSourceMinimizer.h @@ -47,6 +47,9 @@ pp_else, pp_endif, decl_at_import, + cxx_export_decl, + cxx_module_decl, + cxx_import_decl, pp_eof, }; Index: lib/Lex/DependencyDirectivesSourceMinimizer.cpp =================================================================== --- lib/Lex/DependencyDirectivesSourceMinimizer.cpp +++ lib/Lex/DependencyDirectivesSourceMinimizer.cpp @@ -59,6 +59,7 @@ LLVM_NODISCARD bool minimizeImpl(const char *First, const char *const End); LLVM_NODISCARD bool lexPPLine(const char *&First, const char *const End); LLVM_NODISCARD bool lexAt(const char *&First, const char *const End); + LLVM_NODISCARD bool lexModule(const char *&First, const char *const End); LLVM_NODISCARD bool lexDefine(const char *&First, const char *const End); LLVM_NODISCARD bool lexPragma(const char *&First, const char *const End); LLVM_NODISCARD bool lexEndif(const char *&First, const char *const End); @@ -576,6 +577,59 @@ return false; } +bool Minimizer::lexModule(const char *&First, const char *const End) { + IdInfo Id = lexIdentifier(First, End); + First = Id.Last; + bool Export = false; + if (Id.Name == "export") { + Export = true; + skipWhitespace(First, End); + if (!isIdentifierBody(*First)) { + skipLine(First, End); + return false; + } + Id = lexIdentifier(First, End); + First = Id.Last; + } + + if (Id.Name != "module" && Id.Name != "import") { + skipLine(First, End); + return false; + } + + skipWhitespace(First, End); + + // Ignore this as a module directive if the next character can't be part of + // an import. + + switch (*First) { + case ':': + case '<': + case '"': + break; + default: + if (!isIdentifierBody(*First)) { + skipLine(First, End); + return false; + } + } + + if (Export) { + makeToken(cxx_export_decl); + append("export "); + } + + if (Id.Name == "module") + makeToken(cxx_module_decl); + else + makeToken(cxx_import_decl); + append(Id.Name); + append(" "); + printToNewline(First, End); + append("\n"); + return false; +} + bool Minimizer::lexDefine(const char *&First, const char *const End) { makeToken(pp_define); append("#define "); @@ -677,6 +731,18 @@ return false; } +static bool isStartOfRelevantLine(char First) { + switch (First) { + case '#': + case '@': + case 'i': + case 'e': + case 'm': + return true; + } + return false; +} + bool Minimizer::lexPPLine(const char *&First, const char *const End) { assert(First != End); @@ -685,7 +751,7 @@ if (First == End) return false; - if (*First != '#' && *First != '@') { + if (!isStartOfRelevantLine(*First)) { skipLine(First, End); assert(First <= End); return false; @@ -695,6 +761,9 @@ if (*First == '@') return lexAt(First, End); + if (*First == 'i' || *First == 'e' || *First == 'm') + return lexModule(First, End); + // Handle preprocessing directives. ++First; // Skip over '#'. skipWhitespace(First, End); Index: unittests/Lex/DependencyDirectivesSourceMinimizerTest.cpp =================================================================== --- unittests/Lex/DependencyDirectivesSourceMinimizerTest.cpp +++ unittests/Lex/DependencyDirectivesSourceMinimizerTest.cpp @@ -60,7 +60,9 @@ "#__include_macros \n" "#import \n" "@import A;\n" - "#pragma clang module import A\n", + "#pragma clang module import A\n" + "export module m;\n" + "import m;\n", Out, Tokens)); EXPECT_EQ(pp_define, Tokens[0].K); EXPECT_EQ(pp_undef, Tokens[1].K); @@ -76,7 +78,10 @@ EXPECT_EQ(pp_import, Tokens[11].K); EXPECT_EQ(decl_at_import, Tokens[12].K); EXPECT_EQ(pp_pragma_import, Tokens[13].K); - EXPECT_EQ(pp_eof, Tokens[14].K); + EXPECT_EQ(cxx_export_decl, Tokens[14].K); + EXPECT_EQ(cxx_module_decl, Tokens[15].K); + EXPECT_EQ(cxx_import_decl, Tokens[16].K); + EXPECT_EQ(pp_eof, Tokens[17].K); } TEST(MinimizeSourceToDependencyDirectivesTest, Define) { @@ -568,4 +573,48 @@ EXPECT_STREQ("#pragma once\n#include \n", Out.data()); } +TEST(MinimizeSourceToDependencyDirectivesTest, CxxModules) { + SmallVector Out; + SmallVector Tokens; + + StringRef Source = R"( + module; + #include "textual-header.h" + + export module m; + exp\ +ort \ + import \ + :l [[rename]]; + + export void f(); + + void h() { + import.a = 3; + import = 3; + import <<= 3; + import->a = 3; + import(); + import . a(); + + import a b d e d e f e; + import foo [[no_unique_address]]; + import foo(); + import f(:sefse); + import f(->a = 3); + } + )"; + ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out, Tokens)); + EXPECT_STREQ("#include \"textual-header.h\"\nexport module m;\n" + "export import :l [[rename]];\n" + "import <<= 3;\nimport a b d e d e f e;\n" + "import foo [[no_unique_address]];\nimport foo();\n" + "import f(:sefse);\nimport f(->a = 3);\n", Out.data()); + ASSERT_EQ(Tokens.size(), 12u); + EXPECT_EQ(Tokens[0].K, + minimize_source_to_dependency_directives::pp_include); + EXPECT_EQ(Tokens[2].K, + minimize_source_to_dependency_directives::cxx_module_decl); +} + } // end anonymous namespace