/* Support for suggestions about missing #include directives. Copyright (C) 2017-2024 Free Software Foundation, Inc. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #define INCLUDE_MEMORY #include "system.h" #include "coretypes.h" #include "c-family/c-common.h" #include "c-family/name-hint.h" #include "c-family/known-headers.h" #include "gcc-rich-location.h" /* An enum for distinguishing between the C and C++ stdlibs. */ enum stdlib { STDLIB_C, STDLIB_CPLUSPLUS, NUM_STDLIBS }; /* A struct for associating names in a standard library with the header that should be included to locate them, for each of the C and C++ stdlibs (or NULL, for names that aren't in a header for a particular stdlib). */ struct stdlib_hint { const char *name; const char *header[NUM_STDLIBS]; }; /* Given non-NULL NAME, return the header name defining it (as literal string) within either the standard library (with '<' and '>'), or NULL. Only handle string macros, so that this can be used for get_stdlib_header_for_name and get_c_stdlib_header_for_string_macro_name. */ static const char * get_string_macro_hint (const char *name, enum stdlib lib) { /* and . */ static const char *c99_cxx11_macros[] = { "PRId8", "PRId16", "PRId32", "PRId64", "PRIi8", "PRIi16", "PRIi32", "PRIi64", "PRIo8", "PRIo16", "PRIo32", "PRIo64", "PRIu8", "PRIu16", "PRIu32", "PRIu64", "PRIx8", "PRIx16", "PRIx32", "PRIx64", "PRIX8", "PRIX16", "PRIX32", "PRIX64", "PRIdPTR", "PRIiPTR", "PRIoPTR", "PRIuPTR", "PRIxPTR", "PRIXPTR", "SCNd8", "SCNd16", "SCNd32", "SCNd64", "SCNi8", "SCNi16", "SCNi32", "SCNi64", "SCNo8", "SCNo16", "SCNo32", "SCNo64", "SCNu8", "SCNu16", "SCNu32", "SCNu64", "SCNx8", "SCNx16", "SCNx32", "SCNx64", "SCNdPTR", "SCNiPTR", "SCNoPTR", "SCNuPTR", "SCNxPTR" }; if ((lib == STDLIB_C && flag_isoc99) || (lib == STDLIB_CPLUSPLUS && cxx_dialect >= cxx11 )) { const size_t num_c99_cxx11_macros = ARRAY_SIZE (c99_cxx11_macros); for (size_t i = 0; i < num_c99_cxx11_macros; i++) if (strcmp (name, c99_cxx11_macros[i]) == 0) return lib == STDLIB_C ? "" : ""; } return NULL; } /* Given non-NULL NAME, return the header name defining it within either the standard library (with '<' and '>'), or NULL. Only handles a subset of the most common names within the stdlibs. */ static const char * get_stdlib_header_for_name (const char *name, enum stdlib lib) { gcc_assert (name); gcc_assert (lib < NUM_STDLIBS); static const stdlib_hint hints[] = { /* and . */ {"assert", {"", ""} }, /* and . */ {"errno", {"", ""} }, /* and . */ {"CHAR_BIT", {"", ""} }, {"CHAR_MAX", {"", ""} }, {"CHAR_MIN", {"", ""} }, {"INT_MAX", {"", ""} }, {"INT_MIN", {"", ""} }, {"LLONG_MAX", {"", ""} }, {"LLONG_MIN", {"", ""} }, {"LONG_MAX", {"", ""} }, {"LONG_MIN", {"", ""} }, {"MB_LEN_MAX", {"", ""} }, {"SCHAR_MAX", {"", ""} }, {"SCHAR_MIN", {"", ""} }, {"SHRT_MAX", {"", ""} }, {"SHRT_MIN", {"", ""} }, {"UCHAR_MAX", {"", ""} }, {"UINT_MAX", {"", ""} }, {"ULLONG_MAX", {"", ""} }, {"ULONG_MAX", {"", ""} }, {"USHRT_MAX", {"", ""} }, /* and . */ {"DBL_MAX", {"", ""} }, {"DBL_MIN", {"", ""} }, {"FLT_MAX", {"", ""} }, {"FLT_MIN", {"", ""} }, {"LDBL_MAX", {"", ""} }, {"LDBL_MIN", {"", ""} }, /* and . */ {"va_list", {"", ""} }, /* and . */ {"NULL", {"", ""} }, {"nullptr_t", {NULL, ""} }, {"offsetof", {"", ""} }, {"ptrdiff_t", {"", ""} }, {"size_t", {"", ""} }, {"wchar_t", {"", NULL /* a keyword in C++ */} }, /* and . */ {"BUFSIZ", {"", ""} }, {"EOF", {"", ""} }, {"FILE", {"", ""} }, {"FILENAME_MAX", {"", ""} }, {"fopen", {"", ""} }, {"fpos_t", {"", ""} }, {"getchar", {"", ""} }, {"printf", {"", ""} }, {"snprintf", {"", ""} }, {"sprintf", {"", ""} }, {"stderr", {"", ""} }, {"stdin", {"", ""} }, {"stdout", {"", ""} }, /* and . */ {"EXIT_FAILURE", {"", ""} }, {"EXIT_SUCCESS", {"", ""} }, {"abort", {"", ""} }, {"atexit", {"", ""} }, {"calloc", {"", ""} }, {"exit", {"", ""} }, {"free", {"", ""} }, {"getenv", {"", ""} }, {"malloc", {"", ""} }, {"realloc", {"", ""} }, /* and . */ {"memchr", {"", ""} }, {"memcmp", {"", ""} }, {"memcpy", {"", ""} }, {"memmove", {"", ""} }, {"memset", {"", ""} }, {"strcat", {"", ""} }, {"strchr", {"", ""} }, {"strcmp", {"", ""} }, {"strcpy", {"", ""} }, {"strlen", {"", ""} }, {"strncat", {"", ""} }, {"strncmp", {"", ""} }, {"strncpy", {"", ""} }, {"strrchr", {"", ""} }, {"strspn", {"", ""} }, {"strstr", {"", ""} }, /* . */ {"PTRDIFF_MAX", {"", ""} }, {"PTRDIFF_MIN", {"", ""} }, {"SIG_ATOMIC_MAX", {"", ""} }, {"SIG_ATOMIC_MIN", {"", ""} }, {"SIZE_MAX", {"", ""} }, {"WINT_MAX", {"", ""} }, {"WINT_MIN", {"", ""} }, /* . */ {"asctime", {"", ""} }, {"clock", {"", ""} }, {"clock_t", {"", ""} }, {"ctime", {"", ""} }, {"difftime", {"", ""} }, {"gmtime", {"", ""} }, {"localtime", {"", ""} }, {"mktime", {"", ""} }, {"strftime", {"", ""} }, {"time", {"", ""} }, {"time_t", {"", ""} }, {"tm", {"", ""} }, /* . */ {"WCHAR_MAX", {"", ""} }, {"WCHAR_MIN", {"", ""} } }; const size_t num_hints = ARRAY_SIZE (hints); for (size_t i = 0; i < num_hints; i++) if (strcmp (name, hints[i].name) == 0) return hints[i].header[lib]; static const stdlib_hint c99_cxx11_hints[] = { /* . Defined natively in C++. */ {"bool", {"", NULL} }, {"true", {"", NULL} }, {"false", {"", NULL} }, /* and . */ {"int8_t", {"", ""} }, {"uint8_t", {"", ""} }, {"int16_t", {"", ""} }, {"uint16_t", {"", ""} }, {"int32_t", {"", ""} }, {"uint32_t", {"", ""} }, {"int64_t", {"", ""} }, {"uint64_t", {"", ""} }, {"intptr_t", {"", ""} }, {"uintptr_t", {"", ""} }, {"INT8_MAX", {"", ""} }, {"INT16_MAX", {"", ""} }, {"INT32_MAX", {"", ""} }, {"INT64_MAX", {"", ""} }, {"UINT8_MAX", {"", ""} }, {"UINT16_MAX", {"", ""} }, {"UINT32_MAX", {"", ""} }, {"UINT64_MAX", {"", ""} }, {"INTPTR_MAX", {"", ""} }, {"UINTPTR_MAX", {"", ""} } }; const size_t num_c99_cxx11_hints = sizeof (c99_cxx11_hints) / sizeof (c99_cxx11_hints[0]); if ((lib == STDLIB_C && flag_isoc99) || (lib == STDLIB_CPLUSPLUS && cxx_dialect >= cxx11 )) for (size_t i = 0; i < num_c99_cxx11_hints; i++) if (strcmp (name, c99_cxx11_hints[i].name) == 0) return c99_cxx11_hints[i].header[lib]; return get_string_macro_hint (name, lib); } /* Given non-NULL NAME, return the header name defining it within the C standard library (with '<' and '>'), or NULL. */ const char * get_c_stdlib_header_for_name (const char *name) { return get_stdlib_header_for_name (name, STDLIB_C); } /* Given non-NULL NAME, return the header name defining it within the C++ standard library (with '<' and '>'), or NULL. */ const char * get_cp_stdlib_header_for_name (const char *name) { return get_stdlib_header_for_name (name, STDLIB_CPLUSPLUS); } /* Given non-NULL NAME, return the header name defining a string macro within the C standard library (with '<' and '>'), or NULL. */ const char * get_c_stdlib_header_for_string_macro_name (const char *name) { return get_string_macro_hint (name, STDLIB_C); } /* Given non-NULL NAME, return the header name defining a string macro within the C++ standard library (with '<' and '>'), or NULL. */ const char * get_cp_stdlib_header_for_string_macro_name (const char *name) { return get_string_macro_hint (name, STDLIB_CPLUSPLUS); } /* Implementation of class suggest_missing_header. */ /* suggest_missing_header's ctor. */ suggest_missing_header::suggest_missing_header (location_t loc, const char *name, const char *header_hint) : deferred_diagnostic (loc), m_name_str (name), m_header_hint (header_hint) { gcc_assert (name); gcc_assert (header_hint); } /* suggest_missing_header's dtor. */ suggest_missing_header::~suggest_missing_header () { if (is_suppressed_p ()) return; gcc_rich_location richloc (get_location ()); maybe_add_include_fixit (&richloc, m_header_hint, true); inform (&richloc, "%qs is defined in header %qs;" " this is probably fixable by adding %<#include %s%>", m_name_str, m_header_hint, m_header_hint); }