[clang] [clang] Move the diagnostic of unexpected token after module name from phase 4 to phase 7 (PR #187846)
Yihan Wang via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 23 02:19:13 PDT 2026
https://github.com/yronglin updated https://github.com/llvm/llvm-project/pull/187846
>From 8f23870ae44f759d153af87ab1f31ef38433a2d9 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Sat, 21 Mar 2026 15:54:55 +0800
Subject: [PATCH 1/4] [clang] Diag unexpected token after module name in phase
7
Signed-off-by: yronglin <yronglin777 at gmail.com>
---
clang/include/clang/Basic/DiagnosticLexKinds.td | 3 ---
.../include/clang/Basic/DiagnosticParseKinds.td | 3 +++
clang/lib/Lex/PPDirectives.cpp | 16 ----------------
clang/lib/Parse/Parser.cpp | 6 ++++--
clang/test/CXX/basic/basic.link/p3.cpp | 2 +-
clang/test/CXX/drs/cwg2947.cpp | 4 ++--
.../basic/basic.link/module-declaration.cpp | 2 +-
clang/test/CXX/module/cpp.pre/p1.cpp | 6 +++---
8 files changed, 14 insertions(+), 28 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td
index 18143fc9f0feb..ac2cbae643cb3 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -1039,9 +1039,6 @@ def err_pp_module_name_is_macro : Error<
"%select{module|partition}0 name component %1 cannot be a object-like macro">;
def err_pp_module_expected_ident : Error<
"expected %select{identifier after '.' in |}0module name">;
-def err_pp_unexpected_tok_after_module_name : Error<
- "unexpected preprocessing token '%0' after module name, "
- "only ';' and '[' (start of attribute specifier sequence) are allowed">;
def warn_pp_extra_tokens_at_module_directive_eol
: Warning<"extra tokens after semicolon in '%0' directive">,
InGroup<ExtraTokens>;
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 2672bfb2952c8..8891929bd0dd8 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1815,6 +1815,9 @@ def ext_bit_int : Extension<
} // end of Parse Issue category.
let CategoryName = "Modules Issue" in {
+def err_unexpected_tok_after_module_name : Error<
+ "unexpected '%0' after module name, only ';' and '[' (start of attribute "
+ "specifier sequence) are allowed">;
def err_unexpected_module_or_import_decl : Error<
"%select{module|import}0 declaration can only appear at the top level">;
def err_attribute_not_module_attr : Error<
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index c161f6a03593e..018593e9d56be 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -4420,22 +4420,6 @@ void Preprocessor::HandleCXXModuleDirective(Token ModuleTok) {
break;
}
- // Consume the pp-import-suffix and expand any macros in it now, if we're not
- // at the semicolon already.
- std::optional<Token> NextPPTok =
- DirToks.back().is(tok::eod) ? peekNextPPToken() : DirToks.back();
-
- // Only ';' and '[' are allowed after module name.
- // We also check 'private' because the previous is not a module name.
- if (NextPPTok) {
- if (NextPPTok->is(tok::raw_identifier))
- LookUpIdentifierInfo(*NextPPTok);
- if (!NextPPTok->isOneOf(tok::semi, tok::eod, tok::l_square,
- tok::kw_private))
- Diag(*NextPPTok, diag::err_pp_unexpected_tok_after_module_name)
- << getSpelling(*NextPPTok);
- }
-
if (!DirToks.back().isOneOf(tok::semi, tok::eod)) {
// Consume the pp-import-suffix and expand any macros in it now. We'll add
// it back into the token stream later.
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 6a21acd9dc4ef..2d21957ed6937 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -2383,9 +2383,11 @@ Parser::ParseModuleDecl(Sema::ModuleImportState &ImportState) {
}
// This should already diagnosed in phase 4, just skip unil semicolon.
- if (!Tok.isOneOf(tok::semi, tok::l_square))
+ if (!Tok.isOneOf(tok::semi, tok::l_square)) {
+ Diag(Tok, diag::err_unexpected_tok_after_module_name)
+ << PP.getSpelling(Tok);
SkipUntil(tok::semi, SkipUntilFlags::StopBeforeMatch);
-
+ }
// We don't support any module attributes yet; just parse them and diagnose.
ParsedAttributes Attrs(AttrFactory);
MaybeParseCXX11Attributes(Attrs);
diff --git a/clang/test/CXX/basic/basic.link/p3.cpp b/clang/test/CXX/basic/basic.link/p3.cpp
index bc3622c7bbd64..0784a7d879d7d 100644
--- a/clang/test/CXX/basic/basic.link/p3.cpp
+++ b/clang/test/CXX/basic/basic.link/p3.cpp
@@ -14,7 +14,7 @@ constexpr int n = 123;
export module m; // #1
module y = {}; // expected-error {{multiple module declarations}}
-// expected-error at -1 {{unexpected preprocessing token '=' after module name, only ';' and '[' (start of attribute specifier sequence) are allowed}}
+// expected-error at -1 {{unexpected '=' after module name, only ';' and '[' (start of attribute specifier sequence) are allowed}}
// expected-note@#1 {{previous module declaration}}
::import x = {};
diff --git a/clang/test/CXX/drs/cwg2947.cpp b/clang/test/CXX/drs/cwg2947.cpp
index 3d9d738f40de3..1fa59b4e00ab2 100644
--- a/clang/test/CXX/drs/cwg2947.cpp
+++ b/clang/test/CXX/drs/cwg2947.cpp
@@ -37,7 +37,7 @@
//--- cwg2947_example1.cpp
// #define DOT_BAR .bar
export module foo DOT_BAR; // error: expansion of DOT_BAR; does not begin with ; or [
-// expected-error at -1 {{unexpected preprocessing token '.' after module name, only ';' and '[' (start of attribute specifier sequence) are allowed}}
+// expected-error at -1 {{unexpected '.' after module name, only ';' and '[' (start of attribute specifier sequence) are allowed}}
//--- cwg2947_example2.cpp
export module M MOD_ATTR; // OK
@@ -46,7 +46,7 @@ export module M MOD_ATTR; // OK
//--- cwg2947_example3.cpp
export module a
.b; // error: preprocessing token after pp-module-name is not ; or [
-// expected-error at -1 {{unexpected preprocessing token '.' after module name, only ';' and '[' (start of attribute specifier sequence) are allowed}}
+// expected-error at -1 {{unexpected '.' after module name, only ';' and '[' (start of attribute specifier sequence) are allowed}}
//--- cwg2947_example4.cpp
export module M [[
diff --git a/clang/test/CXX/module/basic/basic.link/module-declaration.cpp b/clang/test/CXX/module/basic/basic.link/module-declaration.cpp
index 52ba1d9f82f2f..b22fc87aa296c 100644
--- a/clang/test/CXX/module/basic/basic.link/module-declaration.cpp
+++ b/clang/test/CXX/module/basic/basic.link/module-declaration.cpp
@@ -47,7 +47,7 @@ export module x;
//--- invalid_module_name.cppm
export module z elderberry;
-// expected-error at -1 {{unexpected preprocessing token 'elderberry' after module name, only ';' and '[' (start of attribute specifier sequence) are allowed}}
+// expected-error at -1 {{unexpected 'elderberry' after module name, only ';' and '[' (start of attribute specifier sequence) are allowed}}
//--- empty_attribute.cppm
// expected-no-diagnostics
diff --git a/clang/test/CXX/module/cpp.pre/p1.cpp b/clang/test/CXX/module/cpp.pre/p1.cpp
index 989915004ff57..dc5a3c36d4139 100644
--- a/clang/test/CXX/module/cpp.pre/p1.cpp
+++ b/clang/test/CXX/module/cpp.pre/p1.cpp
@@ -153,7 +153,7 @@ export module m:n;
//--- unexpected_character_in_pp_module_suffix.cpp
export module m();
-// expected-error at -1 {{unexpected preprocessing token '(' after module name, only ';' and '[' (start of attribute specifier sequence) are allowed}}
+// expected-error at -1 {{unexpected '(' after module name, only ';' and '[' (start of attribute specifier sequence) are allowed}}
//--- semi_in_same_line.cpp
export module m // OK
@@ -189,13 +189,13 @@ module x;
//--- func_like_macro.cpp
// #define m(x) x
export module m
- (foo); // expected-error {{unexpected preprocessing token '(' after module name, only ';' and '[' (start of attribute specifier sequence) are allowed}}
+ (foo); // expected-error {{unexpected '(' after module name, only ';' and '[' (start of attribute specifier sequence) are allowed}}
//--- lparen.cpp
// #define m(x) x
// #define LPAREN (
export module m
- LPAREN foo); // expected-error {{unexpected preprocessing token 'LPAREN' after module name, only ';' and '[' (start of attribute specifier sequence) are allowed}}
+ LPAREN foo); // expected-error {{unexpected '(' after module name, only ';' and '[' (start of attribute specifier sequence) are allowed}}
//--- control_line.cpp
#if 0 // #1
>From 81572a573eee9d75bce675e8255a767306733d85 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Fri, 12 Jun 2026 01:40:42 +0800
Subject: [PATCH 2/4] Don't diag when Tok is eof
Signed-off-by: yronglin <yronglin777 at gmail.com>
---
clang/lib/Parse/Parser.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 2d21957ed6937..808fa25cb9487 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -2382,12 +2382,12 @@ Parser::ParseModuleDecl(Sema::ModuleImportState &ImportState) {
return nullptr;
}
- // This should already diagnosed in phase 4, just skip unil semicolon.
- if (!Tok.isOneOf(tok::semi, tok::l_square)) {
+ if (Tok.isNoneOf(tok::semi, tok::l_square, tok::eof)) {
Diag(Tok, diag::err_unexpected_tok_after_module_name)
<< PP.getSpelling(Tok);
SkipUntil(tok::semi, SkipUntilFlags::StopBeforeMatch);
}
+
// We don't support any module attributes yet; just parse them and diagnose.
ParsedAttributes Attrs(AttrFactory);
MaybeParseCXX11Attributes(Attrs);
>From 6e309cd2d52bcbc0e00919351ed54f500f6891fb Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Thu, 23 Jul 2026 01:23:08 -0700
Subject: [PATCH 3/4] Add release notes
Signed-off-by: yronglin <yronglin777 at gmail.com>
---
clang/docs/ReleaseNotes.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 08397eae28557..4e0bb8c38d0f8 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -358,6 +358,9 @@ features cannot lower the translation-unit ABI level;
template was instantiated after the global module fragment was closed,
producing a spurious "no matching function" error with no candidate notes.
(#GH210822)
+
+- Fixed a crash when module directive export module foo not following a
+ semicolon and there are no rest pp-tokens in current module file. (#GH187771)
- Fixed a crash when a lambda parameter pack was given a default argument that
is a pack expansion referencing an enclosing function's parameter pack (e.g.
>From eed99ecd7c9c80b21aba7d0dc3757e3f08f4c553 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Thu, 23 Jul 2026 02:18:49 -0700
Subject: [PATCH 4/4] Add -E tests
Signed-off-by: yronglin <yronglin777 at gmail.com>
---
clang/test/Preprocessor/modules.cpp | 7 +++++++
1 file changed, 7 insertions(+)
create mode 100644 clang/test/Preprocessor/modules.cpp
diff --git a/clang/test/Preprocessor/modules.cpp b/clang/test/Preprocessor/modules.cpp
new file mode 100644
index 0000000000000..00b3a032337dc
--- /dev/null
+++ b/clang/test/Preprocessor/modules.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -std=c++20 -E -verify %s | FileCheck %s
+
+// We will emit error in phase 7, so no diagnostics in -E mode.
+// expected-no-diagnostics
+
+// CHECK: export __preprocessed_module M
+export module M
More information about the cfe-commits
mailing list