[libc++] Diagnose when header search paths are set up incorrectly

An issue I often see in codebases compiled for unusual platforms is
that header search paths are specified manually and are subtly wrong.
For example, people will manually add `-isystem <some-toolchain>/usr/include`,
which ends up messing up the layering of header search paths required by
libc++ (because the C Standard Library now appears *before* libc++ in
the search paths). Without this patch, this will end up causing
compilation errors that are pretty inscrutable. This patch aims to
improve the user experience by diagnosing this issue explicitly.

In all cases I can think of, I would expect that a compilation error
occur if these header search paths are not layered properly. This
should only provide an explicit diagnostic instead of failing due
to seemingly unrelated compilation errors.

Differential Revision: https://reviews.llvm.org/D131441
This commit is contained in:
Louis Dionne 2022-08-08 17:03:56 -04:00
parent 8f8c8168f3
commit 8cedff10a1
17 changed files with 154 additions and 2 deletions

View File

@ -36,8 +36,16 @@ int toupper(int c);
#include <__assert> // all public C++ headers provide the assertion handler
#include <__config>
#include <ctype.h>
#ifndef _LIBCPP_CTYPE_H
# error <cctype> tried including <ctype.h> but didn't find libc++'s <ctype.h> header. \
This usually means that your header search paths are not configured properly. \
The header search paths should contain the C++ Standard Library headers before \
any C Standard Library.
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

View File

@ -24,8 +24,17 @@ Macros:
#include <__assert> // all public C++ headers provide the assertion handler
#include <__config>
#include <errno.h>
#ifndef _LIBCPP_ERRNO_H
# error <cerrno> tried including <errno.h> but didn't find libc++'s <errno.h> header. \
This usually means that your header search paths are not configured properly. \
The header search paths should contain the C++ Standard Library headers before \
any C Standard Library, and you are probably using compiler flags that make that \
not be the case.
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

View File

@ -54,8 +54,17 @@ int feupdateenv(const fenv_t* envp);
#include <__assert> // all public C++ headers provide the assertion handler
#include <__config>
#include <fenv.h>
#ifndef _LIBCPP_FENV_H
# error <cfenv> tried including <fenv.h> but didn't find libc++'s <fenv.h> header. \
This usually means that your header search paths are not configured properly. \
The header search paths should contain the C++ Standard Library headers before \
any C Standard Library, and you are probably using compiler flags that make that \
not be the case.
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

View File

@ -71,8 +71,17 @@ Macros:
#include <__assert> // all public C++ headers provide the assertion handler
#include <__config>
#include <float.h>
#ifndef _LIBCPP_FLOAT_H
# error <cfloat> tried including <float.h> but didn't find libc++'s <float.h> header. \
This usually means that your header search paths are not configured properly. \
The header search paths should contain the C++ Standard Library headers before \
any C Standard Library, and you are probably using compiler flags that make that \
not be the case.
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

View File

@ -237,8 +237,17 @@ uintmax_t wcstoumax(const wchar_t* restrict nptr, wchar_t** restrict endptr, int
#include <__assert> // all public C++ headers provide the assertion handler
#include <__config>
#include <cstdint>
#include <inttypes.h>
#ifndef _LIBCPP_INTTYPES_H
# error <cinttypes> tried including <inttypes.h> but didn't find libc++'s <inttypes.h> header. \
This usually means that your header search paths are not configured properly. \
The header search paths should contain the C++ Standard Library headers before \
any C Standard Library, and you are probably using compiler flags that make that \
not be the case.
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

View File

@ -39,8 +39,17 @@ Macros:
#include <__assert> // all public C++ headers provide the assertion handler
#include <__config>
#include <limits.h>
#ifndef _LIBCPP_LIMITS_H
# error <climits> tried including <limits.h> but didn't find libc++'s <limits.h> header. \
This usually means that your header search paths are not configured properly. \
The header search paths should contain the C++ Standard Library headers before \
any C Standard Library, and you are probably using compiler flags that make that \
not be the case.
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

View File

@ -36,8 +36,17 @@ lconv* localeconv();
#include <__assert> // all public C++ headers provide the assertion handler
#include <__config>
#include <locale.h>
#ifndef _LIBCPP_LOCALE_H
# error <clocale> tried including <locale.h> but didn't find libc++'s <locale.h> header. \
This usually means that your header search paths are not configured properly. \
The header search paths should contain the C++ Standard Library headers before \
any C Standard Library, and you are probably using compiler flags that make that \
not be the case.
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

View File

@ -306,10 +306,19 @@ constexpr long double lerp(long double a, long double b, long double t) noexcept
#include <__assert> // all public C++ headers provide the assertion handler
#include <__config>
#include <math.h>
#include <type_traits>
#include <version>
#include <math.h>
#ifndef _LIBCPP_MATH_H
# error <cmath> tried including <math.h> but didn't find libc++'s <math.h> header. \
This usually means that your header search paths are not configured properly. \
The header search paths should contain the C++ Standard Library headers before \
any C Standard Library, and you are probably using compiler flags that make that \
not be the case.
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

View File

@ -32,8 +32,17 @@ void longjmp(jmp_buf env, int val);
#include <__assert> // all public C++ headers provide the assertion handler
#include <__config>
#include <setjmp.h>
#ifndef _LIBCPP_SETJMP_H
# error <csetjmp> tried including <setjmp.h> but didn't find libc++'s <setjmp.h> header. \
This usually means that your header search paths are not configured properly. \
The header search paths should contain the C++ Standard Library headers before \
any C Standard Library, and you are probably using compiler flags that make that \
not be the case.
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

View File

@ -38,9 +38,18 @@ Types:
#include <__type_traits/enable_if.h>
#include <__type_traits/integral_constant.h>
#include <__type_traits/is_integral.h>
#include <stddef.h>
#include <version>
#include <stddef.h>
#ifndef _LIBCPP_STDDEF_H
# error <cstddef> tried including <stddef.h> but didn't find libc++'s <stddef.h> header. \
This usually means that your header search paths are not configured properly. \
The header search paths should contain the C++ Standard Library headers before \
any C Standard Library, and you are probably using compiler flags that make that \
not be the case.
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

View File

@ -142,8 +142,17 @@ Types:
#include <__assert> // all public C++ headers provide the assertion handler
#include <__config>
#include <stdint.h>
#ifndef _LIBCPP_STDINT_H
# error <cstdint> tried including <stdint.h> but didn't find libc++'s <stdint.h> header. \
This usually means that your header search paths are not configured properly. \
The header search paths should contain the C++ Standard Library headers before \
any C Standard Library, and you are probably using compiler flags that make that \
not be the case.
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

View File

@ -97,8 +97,17 @@ void perror(const char* s);
#include <__assert> // all public C++ headers provide the assertion handler
#include <__config>
#include <stdio.h>
#ifndef _LIBCPP_STDIO_H
# error <cstdio> tried including <stdio.h> but didn't find libc++'s <stdio.h> header. \
This usually means that your header search paths are not configured properly. \
The header search paths should contain the C++ Standard Library headers before \
any C Standard Library, and you are probably using compiler flags that make that \
not be the case.
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

View File

@ -83,8 +83,17 @@ void *aligned_alloc(size_t alignment, size_t size); // C11
#include <__assert> // all public C++ headers provide the assertion handler
#include <__config>
#include <stdlib.h>
#ifndef _LIBCPP_STDLIB_H
# error <cstdlib> tried including <stdlib.h> but didn't find libc++'s <stdlib.h> header. \
This usually means that your header search paths are not configured properly. \
The header search paths should contain the C++ Standard Library headers before \
any C Standard Library, and you are probably using compiler flags that make that \
not be the case.
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

View File

@ -58,8 +58,17 @@ size_t strlen(const char* s);
#include <__assert> // all public C++ headers provide the assertion handler
#include <__config>
#include <string.h>
#ifndef _LIBCPP_STRING_H
# error <cstring> tried including <string.h> but didn't find libc++'s <string.h> header. \
This usually means that your header search paths are not configured properly. \
The header search paths should contain the C++ Standard Library headers before \
any C Standard Library, and you are probably using compiler flags that make that \
not be the case.
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

View File

@ -36,8 +36,17 @@ size_t c32rtomb(char* s, char32_t c32, mbstate_t* ps);
#include <__assert> // all public C++ headers provide the assertion handler
#include <__config>
#include <uchar.h>
#ifndef _LIBCPP_UCHAR_H
# error <cuchar> tried including <uchar.h> but didn't find libc++'s <uchar.h> header. \
This usually means that your header search paths are not configured properly. \
The header search paths should contain the C++ Standard Library headers before \
any C Standard Library, and you are probably using compiler flags that make that \
not be the case.
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

View File

@ -105,8 +105,17 @@ size_t wcsrtombs(char* restrict dst, const wchar_t** restrict src, size_t len,
#include <__assert> // all public C++ headers provide the assertion handler
#include <__config>
#include <cwctype>
#include <wchar.h>
#ifndef _LIBCPP_WCHAR_H
# error <cwchar> tried including <wchar.h> but didn't find libc++'s <wchar.h> header. \
This usually means that your header search paths are not configured properly. \
The header search paths should contain the C++ Standard Library headers before \
any C Standard Library, and you are probably using compiler flags that make that \
not be the case.
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

View File

@ -52,8 +52,17 @@ wctrans_t wctrans(const char* property);
#include <__assert> // all public C++ headers provide the assertion handler
#include <__config>
#include <cctype>
#include <wctype.h>
#ifndef _LIBCPP_WCTYPE_H
# error <cwctype> tried including <wctype.h> but didn't find libc++'s <wctype.h> header. \
This usually means that your header search paths are not configured properly. \
The header search paths should contain the C++ Standard Library headers before \
any C Standard Library, and you are probably using compiler flags that make that \
not be the case.
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif