[clang] 6855b9c - [clang][deps] Properly capture the global module and '\n' for all module directives (#148685)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Jul 19 00:47:41 PDT 2025
Author: Naveen Seth Hanig
Date: 2025-07-19T09:47:37+02:00
New Revision: 6855b9c598b3258e8c0e3edffe5458630a0b0105
URL: https://github.com/llvm/llvm-project/commit/6855b9c598b3258e8c0e3edffe5458630a0b0105
DIFF: https://github.com/llvm/llvm-project/commit/6855b9c598b3258e8c0e3edffe5458630a0b0105.diff
LOG: [clang][deps] Properly capture the global module and '\n' for all module directives (#148685)
Previously, the newline after a module directive was not properly
captured and printed by `clang::printDependencyDirectivesAsSource`.
According to P1857R3, each directive must, after skipping horizontal
whitespace, appear at the start of a logical line. Because the newline
after module directives was missing, this invalidated the following
line.
This fixes tests that were previously in violation of P1857R3,
including for Objective-C directives, which should also comply with
P1857R3.
This also ensures that the global module fragment `module;` is captured
by the dependency directives scanner.
Added:
Modified:
clang/lib/Lex/DependencyDirectivesScanner.cpp
clang/lib/Lex/Preprocessor.cpp
clang/lib/Parse/Parser.cpp
clang/unittests/Lex/DependencyDirectivesScannerTest.cpp
Removed:
################################################################################
diff --git a/clang/lib/Lex/DependencyDirectivesScanner.cpp b/clang/lib/Lex/DependencyDirectivesScanner.cpp
index 869c9cea566b6..9ccff5e3342d5 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,
@@ -735,6 +733,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;
@@ -905,14 +910,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);
@@ -925,6 +922,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 46dbb4d4b91b4..ddc87921ea084 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"
"<TokBeforeEOF>\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) {
More information about the cfe-commits
mailing list