diff --git a/clang/lib/Lex/DependencyDirectivesScanner.cpp b/clang/lib/Lex/DependencyDirectivesScanner.cpp index d894c265a07a2..a1876f868474a 100644 --- a/clang/lib/Lex/DependencyDirectivesScanner.cpp +++ b/clang/lib/Lex/DependencyDirectivesScanner.cpp @@ -560,15 +560,13 @@ bool Scanner::lexModuleDirectiveBody(DirectiveKind Kind, const char *&First, if (Tok.is(tok::semi)) break; } + + const auto &Tok = lexToken(First, End); pushDirective(Kind); - skipWhitespace(First, End); - if (First == End) + if (Tok.is(tok::eof) || Tok.is(tok::eod)) return false; - if (!isVerticalWhitespace(*First)) - return reportError( - DirectiveLoc, diag::err_dep_source_scanner_unexpected_tokens_at_import); - skipNewline(First, End); - return false; + return reportError(DirectiveLoc, + diag::err_dep_source_scanner_unexpected_tokens_at_import); } dependency_directives_scan::Token &Scanner::lexToken(const char *&First, @@ -728,6 +726,13 @@ bool Scanner::lexModule(const char *&First, const char *const End) { return false; break; } + case ';': { + // Handle the global module fragment `module;`. + if (Id == "module" && !Export) + break; + skipLine(First, End); + return false; + } case '<': case '"': break; @@ -898,14 +903,6 @@ bool Scanner::lexPPLine(const char *&First, const char *const End) { CurDirToks.clear(); }); - // Handle "@import". - if (*First == '@') - return lexAt(First, End); - - // Handle module directives for C++20 modules. - if (*First == 'i' || *First == 'e' || *First == 'm') - return lexModule(First, End); - if (*First == '_') { if (isNextIdentifierOrSkipLine("_Pragma", First, End)) return lex_Pragma(First, End); @@ -918,6 +915,14 @@ bool Scanner::lexPPLine(const char *&First, const char *const End) { auto ScEx2 = make_scope_exit( [&]() { TheLexer.setParsingPreprocessorDirective(false); }); + // Handle "@import". + if (*First == '@') + return lexAt(First, End); + + // Handle module directives for C++20 modules. + if (*First == 'i' || *First == 'e' || *First == 'm') + return lexModule(First, End); + // Lex '#'. const dependency_directives_scan::Token &HashTok = lexToken(First, End); if (HashTok.is(tok::hashhash)) { diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index bcd3ea60ce3da..e278846f6f36d 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -950,6 +950,8 @@ void Preprocessor::Lex(Token &Result) { case tok::period: ModuleDeclState.handlePeriod(); break; + case tok::eod: + break; case tok::identifier: // Check "import" and "module" when there is no open bracket. The two // identifiers are not meaningful with open brackets. diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 8834bf80c4016..ff50b3f83908c 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -2519,6 +2519,7 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc, break; } ExpectAndConsumeSemi(diag::err_module_expected_semi); + TryConsumeToken(tok::eod); if (SeenError) return nullptr; diff --git a/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp b/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp index d2ef27155df94..2bfb5113daff1 100644 --- a/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp +++ b/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp @@ -640,14 +640,14 @@ TEST(MinimizeSourceToDependencyDirectivesTest, AtImport) { EXPECT_STREQ("@import A;\n", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives("@import A\n;", Out)); - EXPECT_STREQ("@import A;\n", Out.data()); + EXPECT_STREQ("@import A\n;\n", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives("@import A.B;\n", Out)); EXPECT_STREQ("@import A.B;\n", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives( - "@import /*x*/ A /*x*/ . /*x*/ B /*x*/ \n /*x*/ ; /*x*/", Out)); - EXPECT_STREQ("@import A.B;\n", Out.data()); + "@import /*x*/ A /*x*/ . /*x*/ B /*x*/ \\n /*x*/ ; /*x*/", Out)); + EXPECT_STREQ("@import A.B\\n;\n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, EmptyIncludesAndImports) { @@ -1122,16 +1122,23 @@ ort \ )"; ASSERT_FALSE( minimizeSourceToDependencyDirectives(Source, Out, Tokens, Directives)); - EXPECT_STREQ("#include \"textual-header.h\"\nexport module m;" - "exp\\\nort import:l[[rename]];" - "import<<=3;import a b d e d e f e;" - "import foo[[no_unique_address]];import foo();" - "import f(:sefse);import f(->a=3);" + + EXPECT_STREQ("module;\n" + "#include \"textual-header.h\"\n" + "export module m;\n" + "exp\\\nort import:l[[rename]];\n" + "import<<=3;\n" + "import a b d e d e f e;\n" + "import foo[[no_unique_address]];\n" + "import foo();\n" + "import f(:sefse);\n" + "import f(->a=3);\n" "\n", Out.data()); - ASSERT_EQ(Directives.size(), 11u); - EXPECT_EQ(Directives[0].Kind, pp_include); - EXPECT_EQ(Directives[1].Kind, cxx_export_module_decl); + ASSERT_EQ(Directives.size(), 12u); + EXPECT_EQ(Directives[0].Kind, cxx_module_decl); + EXPECT_EQ(Directives[1].Kind, pp_include); + EXPECT_EQ(Directives[2].Kind, cxx_export_module_decl); } TEST(MinimizeSourceToDependencyDirectivesTest, ObjCMethodArgs) {