[clang] [clang][Modules] Don't treat recovered module-end at EOF as an included header (PR #225099)
Macro Terra via cfe-commits
cfe-commits at lists.llvm.org
Mon Sep 28 01:18:42 PDT 2026
https://github.com/hongtaihu updated https://github.com/llvm/llvm-project/pull/225099
>From 5a4219be1ea7c1c79df6e26b0cd65eaad25b9d73 Mon Sep 17 00:00:00 2001
From: hongtaihu <13541229370 at qq.com>
Date: Mon, 21 Sep 2026 22:33:17 +0800
Subject: [PATCH] [clang][Modules] Don't treat recovered module-end at EOF as
an included header
When a #pragma clang module begin is left unclosed, the parser
synthesizes an annot_module_end at EOF. ActOnAnnotModuleEnd treated any
EOM at EOF as the end of a #included module header and asserted that
this could not happen in the main file.
That is not true for this recovery path: the main file has no include
location. Only use the include location when getIncludeLoc() is valid;
otherwise keep the annotation location.
Fixes #203167
---
clang/lib/Sema/SemaModule.cpp | 11 +++++++----
clang/test/Modules/GH203167-header.cpp | 8 ++++++++
clang/test/Modules/GH203167.cpp | 12 ++++++++++++
clang/test/Modules/Inputs/GH203167.h | 5 +++++
4 files changed, 32 insertions(+), 4 deletions(-)
create mode 100644 clang/test/Modules/GH203167-header.cpp
create mode 100644 clang/test/Modules/GH203167.cpp
create mode 100644 clang/test/Modules/Inputs/GH203167.h
diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp
index 7dbb38bbe078e..da056230fd51c 100644
--- a/clang/lib/Sema/SemaModule.cpp
+++ b/clang/lib/Sema/SemaModule.cpp
@@ -815,13 +815,16 @@ void Sema::ActOnAnnotModuleEnd(SourceLocation EomLoc, Module *Mod) {
// ImportDecl as we would for an imported module.
FileID File = getSourceManager().getFileID(EomLoc);
SourceLocation DirectiveLoc;
- if (EomLoc == getSourceManager().getLocForEndOfFile(File)) {
+ SourceLocation IncludeLoc = getSourceManager().getIncludeLoc(File);
+ if (EomLoc == getSourceManager().getLocForEndOfFile(File) &&
+ IncludeLoc.isValid()) {
// We reached the end of a #included module header. Use the #include loc.
assert(File != getSourceManager().getMainFileID() &&
- "end of submodule in main source file");
- DirectiveLoc = getSourceManager().getIncludeLoc(File);
+ "included module header should not be the main source file");
+ DirectiveLoc = IncludeLoc;
} else {
- // We reached an EOM pragma. Use the pragma location.
+ // We reached an EOM pragma, possibly synthesized at EOF for recovery. Use
+ // the annotation location.
DirectiveLoc = EomLoc;
}
BuildModuleInclude(DirectiveLoc, Mod);
diff --git a/clang/test/Modules/GH203167-header.cpp b/clang/test/Modules/GH203167-header.cpp
new file mode 100644
index 0000000000000..de6f2066ad01a
--- /dev/null
+++ b/clang/test/Modules/GH203167-header.cpp
@@ -0,0 +1,8 @@
+// RUN: not %clang_cc1 -std=c++20 -fmodules -fsyntax-only -I %S/Inputs %s 2> %t
+// RUN: FileCheck %s < %t
+
+#include "GH203167.h"
+
+// CHECK: error: no matching '#pragma clang module endbuild'
+// CHECK: error: no matching '#pragma clang module end'
+// CHECK-NOT: Assertion
diff --git a/clang/test/Modules/GH203167.cpp b/clang/test/Modules/GH203167.cpp
new file mode 100644
index 0000000000000..ff69a19a84d58
--- /dev/null
+++ b/clang/test/Modules/GH203167.cpp
@@ -0,0 +1,12 @@
+// RUN: not %clang_cc1 -std=c++20 -fmodules -fsyntax-only %s 2> %t
+// RUN: FileCheck %s < %t
+
+#pragma clang module build N
+module N {}
+#pragma clang module contents
+#pragma clang module begin N
+int x;
+
+// CHECK: error: no matching '#pragma clang module endbuild'
+// CHECK: error: no matching '#pragma clang module end'
+// CHECK-NOT: Assertion
diff --git a/clang/test/Modules/Inputs/GH203167.h b/clang/test/Modules/Inputs/GH203167.h
new file mode 100644
index 0000000000000..d48f6d1c5aa7f
--- /dev/null
+++ b/clang/test/Modules/Inputs/GH203167.h
@@ -0,0 +1,5 @@
+#pragma clang module build N
+module N {}
+#pragma clang module contents
+#pragma clang module begin N
+int x;
More information about the cfe-commits
mailing list