https://github.com/ian-twilightcoder created 
https://github.com/llvm/llvm-project/pull/165057

The C standard behavior of `assert` cannot be accomplished with clang modules, 
either as a normal modular header, or a textual header.

As a normal modular header:
#define NDEBUG
#include <assert.h>
This pattern doesn't work, NDEBUG has to be passed on the command line to take 
effect, and then will effect all `assert`s in the includer.

As a textual header:
#define NDEBUG
#include <modular_header_that_has_an_assert.h>
This pattern doesn't work for similar reasons, 
modular_header_that_has_an_assert.h captured the value of NDEBUG when its 
module built and won't pick it up from the includer. -DNDEBUG can be passed 
when building the module, but will similarly effect the entire module. This has 
the additional problem that every module will contain a declaration for 
`assert`, which can possibly conflict with each other if they use different 
values of NDEBUG.

So really <assert.h> just doesn't work properly with clang modules. Avoid the 
issue by not mentioning it in the Modules documentation, and use "X macros" as 
the example for textual headers.

Don't use [extern_c] in the example modules, that should very rarely be used. 
Don't put multiple `header` declarations in a submodule, that has the confusing 
effect of "fusing" the headers. e.g. <sys/errno.h> does not include <errno.h>, 
but if it's in the same submodule, then an `#include <sys/errno.h>` will 
mysteriously also include <errno.h>.

>From 5f9fcfd314c203533a31d5fd79518810446de20d Mon Sep 17 00:00:00 2001
From: Ian Anderson <[email protected]>
Date: Fri, 24 Oct 2025 16:45:29 -0700
Subject: [PATCH] [clang][docs] assert.h is not a good candidate for a textual
 header

The C standard behavior of `assert` cannot be accomplished with clang modules, 
either as a normal modular header, or a textual header.

As a normal modular header:
#define NDEBUG
#include <assert.h>
This pattern doesn't work, NDEBUG has to be passed on the command line to take 
effect, and then will effect all `assert`s in the includer.

As a textual header:
#define NDEBUG
#include <modular_header_that_has_an_assert.h>
This pattern doesn't work for similar reasons, 
modular_header_that_has_an_assert.h captured the value of NDEBUG when its 
module built and won't pick it up from the includer. -DNDEBUG can be passed 
when building the module, but will similarly effect the entire module. This has 
the additional problem that every module will contain a declaration for 
`assert`, which can possibly conflict with each other if they use different 
values of NDEBUG.

So really <assert.h> just doesn't work properly with clang modules. Avoid the 
issue by not mentioning it in the Modules documentation, and use "X macros" as 
the example for textual headers.

Don't use [extern_c] in the example modules, that should very rarely be used.
Don't put multiple `header` declarations in a submodule, that has the confusing 
effect of "fusing" the headers. e.g. <sys/errno.h> does not include <errno.h>, 
but if it's in the same submodule, then an `#include <sys/errno.h>` will 
mysteriously also include <errno.h>.
---
 clang/docs/Modules.rst | 17 +++++------------
 1 file changed, 5 insertions(+), 12 deletions(-)

diff --git a/clang/docs/Modules.rst b/clang/docs/Modules.rst
index acbe45e0be970..e45ee9ff9eac2 100644
--- a/clang/docs/Modules.rst
+++ b/clang/docs/Modules.rst
@@ -421,13 +421,7 @@ As an example, the module map file for the C standard 
library might look a bit l
 
 .. parsed-literal::
 
-  module std [system] [extern_c] {
-    module assert {
-      textual header "assert.h"
-      header "bits/assert-decls.h"
-      export *
-    }
-
+  module std [system] {
     module complex {
       header "complex.h"
       export *
@@ -440,7 +434,6 @@ As an example, the module map file for the C standard 
library might look a bit l
 
     module errno {
       header "errno.h"
-      header "sys/errno.h"
       export *
     }
 
@@ -673,14 +666,14 @@ of checking *use-declaration*\s, and must still be a 
lexically-valid header
 file. In the future, we intend to pre-tokenize such headers and include the
 token sequence within the prebuilt module representation.
 
-A header with the ``exclude`` specifier is excluded from the module. It will 
not be included when the module is built, nor will it be considered to be part 
of the module, even if an ``umbrella`` header or directory would otherwise make 
it part of the module.
+A header with the ``exclude`` specifier is excluded from the module. It will 
not be included when the module is built, nor will it be considered to be part 
of the module, even if an ``umbrella`` directory would otherwise make it part 
of the module.
 
-**Example:** The C header ``assert.h`` is an excellent candidate for a textual 
header, because it is meant to be included multiple times (possibly with 
different ``NDEBUG`` settings). However, declarations within it should 
typically be split into a separate modular header.
+**Example:** A "X macro" header is an excellent candidate for a textual 
header, because it is can't be compiled standalone, and by itself does not 
contain any declarations.
 
 .. parsed-literal::
 
-  module std [system] {
-    textual header "assert.h"
+  module MyLib [system] {
+    textual header "xmacros.h"
   }
 
 A given header shall not be referenced by more than one *header-declaration*.

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to