[clang] [clang][modules] Headers meant to be included multiple times can be completely invisible in clang module builds (PR #83660)

Ian Anderson via cfe-commits cfe-commits at lists.llvm.org
Tue Apr 16 14:40:41 PDT 2024


ian-twilightcoder wrote:

Wall of text incoming... Sorry but our documentation in this area is poor, so I feel like I need to spell out the assumptions behind this change.

First of all, this _should_ be a relatively minor change that should affect a very limited set of circumstances.
1. Only `#import` should be affected, not `#include`.
2. Only headers marked `textual header` in a module map should be affected, nothing else.
3. Headers that use `#pragma once` or have header guards should not be affected.
4. Module map reading should not be affected.

That should end up being a rather narrow change, and if something else got affected I'd like to know what and fix it.


`#import` is already treated differently if modules are enabled. This adds another case to the special treatment, but doesn't introduce that fact that sometimes `#import`ed headers will be re-entered when building with modules. We can say we don't like `#import` behaving differently when modules are enabled. However, it's not going to be any harder to undo this special treatment than it will to undo the other ones, if we ever care enough to try, so I don't think this is such an egregious change.

`textual header`s are already treated differently as well. To better define that, there are 4 different types of headers in a clang modules world.

1. Headers covered by a `header` statement in a module map - ye olde standard include-once header.
2. Headers covered by a `textual header` statement in a module map - usually headers that are intended to be included multiple times. Generally these are X macro generator headers, or special headers like <assert.h> or clang's <stdarg.h> and <stddef.h> which are designed to have different behavior based on the preprocessor environment of the includer.
3. Headers covered by an `exclude header` statement in a module map - headers that can't be used in a module. Sometimes these are just obsolete headers, and sometimes it's headers that have dependencies that can't be used in a module.
4. Headers that are not listed in any module map. These are essentially the same thing as excluded headers.

There's a semantic difference between textual and excluded headers. Textual headers are anointed to be safe to use in modules, and excluded headers are not supposed to be included from any modular header. (If I had my way, `-Wnon-modular-include-in-module` would default to an error much like `-Wmodule-import-in-extern-c` does, but that can be a soap box for another day.) Textual headers are already treated differently from excluded headers in a few ways, such as they respect `[no_undeclared_includes]`/`use`, while excluded headers don't.

All this to say that `#import`ed headers are already treated different when modules are enabled, and textual headers are already treated different than excluded headers. I think it's fine to tweak this different treatment, especially since it's solving a real world problem that occurs in a fully modularized system. I also think it's preferable to focus the change down to the very specific problem, which is `#import`ed textual headers, instead of trying to fix all of the submodule visibility problems we can think of.

https://github.com/llvm/llvm-project/pull/83660


More information about the cfe-commits mailing list