Skip to content

[Modules] Don't fail when an unused textual header is missing. #138227

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 8, 2025

Conversation

vsapsai
Copy link
Collaborator

@vsapsai vsapsai commented May 2, 2025

According to the documentation

A header declaration that does not contain exclude nor textual specifies a header that contributes to the enclosing module.

Which means that exclude and textual header don't contribute to the enclosing module and their presence isn't required to build such a module. The keywords tell clang how a header should be treated in a context of the module but they don't add headers to the module.

When a textual header is used, clang still emits "file not found" error pointing to the location where the missing file is included.

According to the documentation
> A header declaration that does not contain `exclude` nor `textual` specifies a header that contributes to the enclosing module.

Which means that `exclude` and `textual` header don't contribute to the
enclosing module and their presence isn't required to build such a module.
The keywords tell clang how a header should be treated in a context of
the module but they don't add headers to the module.

When a textual header *is* used, clang still emits "file not found" error
pointing to the location where the missing file is included.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules labels May 2, 2025
@llvmbot
Copy link
Member

llvmbot commented May 2, 2025

@llvm/pr-subscribers-clang

Author: Volodymyr Sapsai (vsapsai)

Changes

According to the documentation
> A header declaration that does not contain exclude nor textual specifies a header that contributes to the enclosing module.

Which means that exclude and textual header don't contribute to the enclosing module and their presence isn't required to build such a module. The keywords tell clang how a header should be treated in a context of the module but they don't add headers to the module.

When a textual header is used, clang still emits "file not found" error pointing to the location where the missing file is included.


Full diff: https://github.com/llvm/llvm-project/pull/138227.diff

3 Files Affected:

  • (modified) clang/lib/Lex/ModuleMap.cpp (+4-2)
  • (modified) clang/test/Modules/Inputs/submodules/module.modulemap (+4)
  • (modified) clang/test/Modules/missing-header.m (+3)
diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index c2f13fa48d464..1ba02b919a22a 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/lib/Lex/ModuleMap.cpp
@@ -310,8 +310,10 @@ void ModuleMap::resolveHeader(Module *Mod,
   } else if (Header.HasBuiltinHeader && !Header.Size && !Header.ModTime) {
     // There's a builtin header but no corresponding on-disk header. Assume
     // this was supposed to modularize the builtin header alone.
-  } else if (Header.Kind == Module::HK_Excluded) {
-    // Ignore missing excluded header files. They're optional anyway.
+  } else if ((Header.Kind == Module::HK_Excluded) ||
+             (Header.Kind == Module::HK_Textual)) {
+    // Ignore excluded and textual header files as a module can be built with
+    // such headers missing.
   } else {
     // If we find a module that has a missing header, we mark this module as
     // unavailable and store the header directive for displaying diagnostics.
diff --git a/clang/test/Modules/Inputs/submodules/module.modulemap b/clang/test/Modules/Inputs/submodules/module.modulemap
index 1c1b76a08969e..9e8143b8101de 100644
--- a/clang/test/Modules/Inputs/submodules/module.modulemap
+++ b/clang/test/Modules/Inputs/submodules/module.modulemap
@@ -30,3 +30,7 @@ module missing_umbrella_with_inferred_submodules {
   module * { export * }
   export *
 }
+
+module missing_textual_header {
+  textual header "missing_textual.h"
+}
diff --git a/clang/test/Modules/missing-header.m b/clang/test/Modules/missing-header.m
index c162e1b5f08b3..84d82e5ceda32 100644
--- a/clang/test/Modules/missing-header.m
+++ b/clang/test/Modules/missing-header.m
@@ -8,6 +8,9 @@
 @import missing_unavailable_headers.not_missing; // OK
 // CHECK-NOT: missing_unavailable_headers
 
+@import missing_textual_header; // OK
+// CHECK-NOT: missing_textual_header
+
 @import missing_headers;
 // CHECK: module.modulemap:15:27: error: header 'missing.h' not found
 // CHECK: could not build module 'missing_headers'

@llvmbot
Copy link
Member

llvmbot commented May 2, 2025

@llvm/pr-subscribers-clang-modules

Author: Volodymyr Sapsai (vsapsai)

Changes

According to the documentation
> A header declaration that does not contain exclude nor textual specifies a header that contributes to the enclosing module.

Which means that exclude and textual header don't contribute to the enclosing module and their presence isn't required to build such a module. The keywords tell clang how a header should be treated in a context of the module but they don't add headers to the module.

When a textual header is used, clang still emits "file not found" error pointing to the location where the missing file is included.


Full diff: https://github.com/llvm/llvm-project/pull/138227.diff

3 Files Affected:

  • (modified) clang/lib/Lex/ModuleMap.cpp (+4-2)
  • (modified) clang/test/Modules/Inputs/submodules/module.modulemap (+4)
  • (modified) clang/test/Modules/missing-header.m (+3)
diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index c2f13fa48d464..1ba02b919a22a 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/lib/Lex/ModuleMap.cpp
@@ -310,8 +310,10 @@ void ModuleMap::resolveHeader(Module *Mod,
   } else if (Header.HasBuiltinHeader && !Header.Size && !Header.ModTime) {
     // There's a builtin header but no corresponding on-disk header. Assume
     // this was supposed to modularize the builtin header alone.
-  } else if (Header.Kind == Module::HK_Excluded) {
-    // Ignore missing excluded header files. They're optional anyway.
+  } else if ((Header.Kind == Module::HK_Excluded) ||
+             (Header.Kind == Module::HK_Textual)) {
+    // Ignore excluded and textual header files as a module can be built with
+    // such headers missing.
   } else {
     // If we find a module that has a missing header, we mark this module as
     // unavailable and store the header directive for displaying diagnostics.
diff --git a/clang/test/Modules/Inputs/submodules/module.modulemap b/clang/test/Modules/Inputs/submodules/module.modulemap
index 1c1b76a08969e..9e8143b8101de 100644
--- a/clang/test/Modules/Inputs/submodules/module.modulemap
+++ b/clang/test/Modules/Inputs/submodules/module.modulemap
@@ -30,3 +30,7 @@ module missing_umbrella_with_inferred_submodules {
   module * { export * }
   export *
 }
+
+module missing_textual_header {
+  textual header "missing_textual.h"
+}
diff --git a/clang/test/Modules/missing-header.m b/clang/test/Modules/missing-header.m
index c162e1b5f08b3..84d82e5ceda32 100644
--- a/clang/test/Modules/missing-header.m
+++ b/clang/test/Modules/missing-header.m
@@ -8,6 +8,9 @@
 @import missing_unavailable_headers.not_missing; // OK
 // CHECK-NOT: missing_unavailable_headers
 
+@import missing_textual_header; // OK
+// CHECK-NOT: missing_textual_header
+
 @import missing_headers;
 // CHECK: module.modulemap:15:27: error: header 'missing.h' not found
 // CHECK: could not build module 'missing_headers'

@vsapsai
Copy link
Collaborator Author

vsapsai commented May 2, 2025

The change for exclude headers was done in 040e126.

Copy link
Contributor

@Bigcheese Bigcheese left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just looking at the missing_textual_header module alone this is a bit odd, but that's just the semantics of textual headers. Really textual headers just exist to control the non-modular include warning, so this is fine.

@vsapsai vsapsai merged commit 64bb60a into llvm:main May 8, 2025
15 checks passed
@vsapsai vsapsai deleted the accept-missing-textual-header branch May 8, 2025 16:07
@vsapsai
Copy link
Collaborator Author

vsapsai commented May 8, 2025

Thanks for the review!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants