tahonermann wrote: There is some interesting MSVC behavior that I'm not planning to replicate with the changes being done for this issue but that I thought are worth documenting (here at least, perhaps in Clang docs as well).
MSVC documentation for the [`/external`](https://learn.microsoft.com/en-us/cpp/build/reference/external-external-headers-diagnostics?view=msvc-170) suite of options includes the `/external:Wn` option (where `Wn` is one of `W0`, `W1`, `W2`,`W3`, or `W4`) to specify the warning level that is used for "external" header search paths; paths specified with the `/external:I` or `/external:env` option, the `%EXTERNAL_INCLUDE%` environment variable, or included with a angle bracket enclosed path (`#include <file.h>`) when the `/external:anglebrackets` option is enabled. The warning levels are meaningless to Clang, so Clang currently maps `/external:W0` to `-Wno-system-headers` and the rest to `-Wsystem-headers`. Clang does not yet implement `/external:anglebrackets`. This all seems fine. There are two interesting behaviors that MSVC exhibits related to the `/I` and `%INCLUDE%` environment variable. 1. By default, paths specified by `/I` or `%INCLUDE%` are treated as user paths; whether warnings are issued for them is subject to use of one of the [warning level options](https://learn.microsoft.com/en-us/cpp/build/reference/compiler-option-warning-level?view=msvc-170) like `/Wall` and `/W4`; the `/external:Wn` option has no effect on them. 2. However, when a path specified by `/external:I`, `/external:env`, or `%EXTERNAL_INCLUDE%` matches the *beginning* of a path in a `/I` or `%INCLUDE%` path, then the `/external:Wn` specified warning level is applied to that path. The path match does not have to occur at a path component boundary (unless the external path ends in a path separator). Matched paths are treated like system paths. In the following example, each header file has code that triggers [MSVC warning C4245](https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-4-c4245?view=msvc-170); a warning that is issued at warning level 4. ``` > type incbar\a.h const unsigned int sysinc1 = -1; > type incbaz\b.h const unsigned int sysinc2 = -1; > type incfoo\c.h const unsigned int extinc = -1; > type t.cpp #include <a.h> #include <b.h> #include <c.h> > set INCLUDE=incbar;incbaz;incfoo # No warnings issued by default. > cl /nologo /c t.cpp t.cpp # Warnings issued with `/W4`. > cl /nologo /c /W4 t.cpp t.cpp incbar\a.h(1): warning C4245: 'initializing': conversion from 'int' to 'unsigned int', signed/unsigned mismatch incbaz\b.h(1): warning C4245: 'initializing': conversion from 'int' to 'unsigned int', signed/unsigned mismatch incfoo\c.h(1): warning C4245: 'initializing': conversion from 'int' to 'unsigned int', signed/unsigned mismatch # No warnings issued with `/external:W4`. > cl /nologo /c /external:W4 t.cpp t.cpp # Warnings issued for all three search directories with `/external:W4` and `/external:I inc`. # Not shown here, but if a `inc` directory existed, it would also be searched for header files. > cl /nologo /c /external:W4 /external:I inc t.cpp t.cpp incbar\a.h(1): warning C4245: 'initializing': conversion from 'int' to 'unsigned int', signed/unsigned mismatch incbaz\b.h(1): warning C4245: 'initializing': conversion from 'int' to 'unsigned int', signed/unsigned mismatch incfoo\c.h(1): warning C4245: 'initializing': conversion from 'int' to 'unsigned int', signed/unsigned mismatch # Warnings issued for only `incbar/a.h` and `incbaz.h` with `/external:W4` and `/external:I incb`. # Not shown here, but if a `incb` directory existed, it would also be searched for header files. > cl /nologo /c /external:W4 /external:I incb t.cpp t.cpp incbar\a.h(1): warning C4245: 'initializing': conversion from 'int' to 'unsigned int', signed/unsigned mismatch incbaz\b.h(1): warning C4245: 'initializing': conversion from 'int' to 'unsigned int', signed/unsigned mismatch # No warnings issued when the external include path ends with a path separator that doesn't match another path. # Not shown here, but if a `incb` directory existed, it would be searched for header files. > cl /nologo /c /external:W4 /external:I incb\ t.cpp t.cpp ``` My intent with changes made for this issue is to (continue to) treat all paths specified by `/I` as user paths and all paths specified by `/external:I`, `/external:env`, `%INCLUDE%`, or `%EXTERNAL_INCLUDE%` as system paths. Ideally, I think we would do the following at some point to improve compatibility with MSVC. 1. Treat paths specified by `%INCLUDE%` as user paths by default. 2. After building the header search path in `InitHeaderSearch::Realize()`, alter the `SrcMgr::CharacteristicKind` value stored in the `Lookup` member of `DirectoryLookupInfo` in the `IncludePath` member of `InitHeaderSearch` to indicate a system path for each path that is a prefix match for an external path (where the prefix need not match on a path component boundary). https://github.com/llvm/llvm-project/pull/105738 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits