xref: /netbsd-src/external/gpl3/gcc/dist/gcc/c-family/known-headers.cc (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1 /* Support for suggestions about missing #include directives.
2    Copyright (C) 2017-2022 Free Software Foundation, Inc.
3 
4 This file is part of GCC.
5 
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 3, or (at your option) any later
9 version.
10 
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3.  If not see
18 <http://www.gnu.org/licenses/>.  */
19 
20 #include "config.h"
21 #define INCLUDE_MEMORY
22 #include "system.h"
23 #include "coretypes.h"
24 #include "c-family/c-common.h"
25 #include "c-family/name-hint.h"
26 #include "c-family/known-headers.h"
27 #include "gcc-rich-location.h"
28 
29 /* An enum for distinguishing between the C and C++ stdlibs.  */
30 
31 enum stdlib
32 {
33   STDLIB_C,
34   STDLIB_CPLUSPLUS,
35 
36   NUM_STDLIBS
37 };
38 
39 /* A struct for associating names in a standard library with the header
40    that should be included to locate them, for each of the C and C++ stdlibs
41    (or NULL, for names that aren't in a header for a particular stdlib).  */
42 
43 struct stdlib_hint
44 {
45   const char *name;
46   const char *header[NUM_STDLIBS];
47 };
48 
49 /* Given non-NULL NAME, return the header name defining it (as literal
50    string) within either the standard library (with '<' and '>'), or
51    NULL.
52 
53    Only handle string macros, so that this can be used for
54    get_stdlib_header_for_name and
55    get_c_stdlib_header_for_string_macro_name.  */
56 
57 static const char *
get_string_macro_hint(const char * name,enum stdlib lib)58 get_string_macro_hint (const char *name, enum stdlib lib)
59 {
60   /* <inttypes.h> and <cinttypes>.  */
61   static const char *c99_cxx11_macros[] =
62     { "PRId8", "PRId16", "PRId32", "PRId64",
63       "PRIi8", "PRIi16", "PRIi32", "PRIi64",
64       "PRIo8", "PRIo16", "PRIo32", "PRIo64",
65       "PRIu8", "PRIu16", "PRIu32", "PRIu64",
66       "PRIx8", "PRIx16", "PRIx32", "PRIx64",
67       "PRIX8", "PRIX16", "PRIX32", "PRIX64",
68 
69       "PRIdPTR", "PRIiPTR", "PRIoPTR", "PRIuPTR", "PRIxPTR", "PRIXPTR",
70 
71       "SCNd8", "SCNd16", "SCNd32", "SCNd64",
72       "SCNi8", "SCNi16", "SCNi32", "SCNi64",
73       "SCNo8", "SCNo16", "SCNo32", "SCNo64",
74       "SCNu8", "SCNu16", "SCNu32", "SCNu64",
75       "SCNx8", "SCNx16", "SCNx32", "SCNx64",
76 
77       "SCNdPTR", "SCNiPTR", "SCNoPTR", "SCNuPTR", "SCNxPTR" };
78 
79   if ((lib == STDLIB_C && flag_isoc99)
80       || (lib == STDLIB_CPLUSPLUS && cxx_dialect >= cxx11 ))
81     {
82       const size_t num_c99_cxx11_macros
83 	= sizeof (c99_cxx11_macros) / sizeof (c99_cxx11_macros[0]);
84       for (size_t i = 0; i < num_c99_cxx11_macros; i++)
85 	if (strcmp (name, c99_cxx11_macros[i]) == 0)
86 	  return lib == STDLIB_C ? "<inttypes.h>" : "<cinttypes>";
87     }
88 
89   return NULL;
90 }
91 
92 /* Given non-NULL NAME, return the header name defining it within either
93    the standard library (with '<' and '>'), or NULL.
94    Only handles a subset of the most common names within the stdlibs.  */
95 
96 static const char *
get_stdlib_header_for_name(const char * name,enum stdlib lib)97 get_stdlib_header_for_name (const char *name, enum stdlib lib)
98 {
99   gcc_assert (name);
100   gcc_assert (lib < NUM_STDLIBS);
101 
102   static const stdlib_hint hints[] = {
103     /* <assert.h> and <cassert>.  */
104     {"assert", {"<assert.h>",  "<cassert>"} },
105 
106     /* <errno.h> and <cerrno>.  */
107     {"errno", {"<errno.h>", "<cerrno>"} },
108 
109     /* <limits.h> and <climits>.  */
110     {"CHAR_BIT", {"<limits.h>", "<climits>"} },
111     {"CHAR_MAX", {"<limits.h>", "<climits>"} },
112     {"CHAR_MIN", {"<limits.h>", "<climits>"} },
113     {"INT_MAX", {"<limits.h>", "<climits>"} },
114     {"INT_MIN", {"<limits.h>", "<climits>"} },
115     {"LLONG_MAX", {"<limits.h>", "<climits>"} },
116     {"LLONG_MIN", {"<limits.h>", "<climits>"} },
117     {"LONG_MAX", {"<limits.h>", "<climits>"} },
118     {"LONG_MIN", {"<limits.h>", "<climits>"} },
119     {"MB_LEN_MAX", {"<limits.h>", "<climits>"} },
120     {"SCHAR_MAX", {"<limits.h>", "<climits>"} },
121     {"SCHAR_MIN", {"<limits.h>", "<climits>"} },
122     {"SHRT_MAX", {"<limits.h>", "<climits>"} },
123     {"SHRT_MIN", {"<limits.h>", "<climits>"} },
124     {"UCHAR_MAX", {"<limits.h>", "<climits>"} },
125     {"UINT_MAX", {"<limits.h>", "<climits>"} },
126     {"ULLONG_MAX", {"<limits.h>", "<climits>"} },
127     {"ULONG_MAX", {"<limits.h>", "<climits>"} },
128     {"USHRT_MAX", {"<limits.h>", "<climits>"} },
129 
130     /* <float.h> and <cfloat>.  */
131     {"DBL_MAX", {"<float.h>", "<cfloat>"} },
132     {"DBL_MIN", {"<float.h>", "<cfloat>"} },
133     {"FLT_MAX", {"<float.h>", "<cfloat>"} },
134     {"FLT_MIN", {"<float.h>", "<cfloat>"} },
135     {"LDBL_MAX", {"<float.h>", "<cfloat>"} },
136     {"LDBL_MIN", {"<float.h>", "<cfloat>"} },
137 
138     /* <stdarg.h> and <cstdarg>.  */
139     {"va_list", {"<stdarg.h>", "<cstdarg>"} },
140 
141     /* <stddef.h> and <cstddef>.  */
142     {"NULL", {"<stddef.h>", "<cstddef>"} },
143     {"nullptr_t", {NULL, "<cstddef>"} },
144     {"offsetof", {"<stddef.h>", "<cstddef>"} },
145     {"ptrdiff_t", {"<stddef.h>", "<cstddef>"} },
146     {"size_t", {"<stddef.h>", "<cstddef>"} },
147     {"wchar_t", {"<stddef.h>", NULL /* a keyword in C++ */} },
148 
149     /* <stdio.h> and <cstdio>.  */
150     {"BUFSIZ", {"<stdio.h>", "<cstdio>"} },
151     {"EOF", {"<stdio.h>", "<cstdio>"} },
152     {"FILE", {"<stdio.h>", "<cstdio>"} },
153     {"FILENAME_MAX", {"<stdio.h>", "<cstdio>"} },
154     {"fopen", {"<stdio.h>", "<cstdio>"} },
155     {"fpos_t", {"<stdio.h>", "<cstdio>"} },
156     {"getchar", {"<stdio.h>", "<cstdio>"} },
157     {"printf", {"<stdio.h>", "<cstdio>"} },
158     {"snprintf", {"<stdio.h>", "<cstdio>"} },
159     {"sprintf", {"<stdio.h>", "<cstdio>"} },
160     {"stderr", {"<stdio.h>", "<cstdio>"} },
161     {"stdin", {"<stdio.h>", "<cstdio>"} },
162     {"stdout", {"<stdio.h>", "<cstdio>"} },
163 
164     /* <stdlib.h> and <cstdlib>.  */
165     {"EXIT_FAILURE", {"<stdlib.h>", "<cstdlib>"} },
166     {"EXIT_SUCCESS", {"<stdlib.h>", "<cstdlib>"} },
167     {"abort", {"<stdlib.h>", "<cstdlib>"} },
168     {"atexit", {"<stdlib.h>", "<cstdlib>"} },
169     {"calloc", {"<stdlib.h>", "<cstdlib>"} },
170     {"exit", {"<stdlib.h>", "<cstdlib>"} },
171     {"free", {"<stdlib.h>", "<cstdlib>"} },
172     {"getenv", {"<stdlib.h>", "<cstdlib>"} },
173     {"malloc", {"<stdlib.h>", "<cstdlib>"} },
174     {"realloc", {"<stdlib.h>", "<cstdlib>"} },
175 
176     /* <string.h> and <cstring>.  */
177     {"memchr", {"<string.h>", "<cstring>"} },
178     {"memcmp", {"<string.h>", "<cstring>"} },
179     {"memcpy", {"<string.h>", "<cstring>"} },
180     {"memmove", {"<string.h>", "<cstring>"} },
181     {"memset", {"<string.h>", "<cstring>"} },
182     {"strcat", {"<string.h>", "<cstring>"} },
183     {"strchr", {"<string.h>", "<cstring>"} },
184     {"strcmp", {"<string.h>", "<cstring>"} },
185     {"strcpy", {"<string.h>", "<cstring>"} },
186     {"strlen", {"<string.h>", "<cstring>"} },
187     {"strncat", {"<string.h>", "<cstring>"} },
188     {"strncmp", {"<string.h>", "<cstring>"} },
189     {"strncpy", {"<string.h>", "<cstring>"} },
190     {"strrchr", {"<string.h>", "<cstring>"} },
191     {"strspn", {"<string.h>", "<cstring>"} },
192     {"strstr", {"<string.h>", "<cstring>"} },
193 
194     /* <stdint.h>.  */
195     {"PTRDIFF_MAX", {"<stdint.h>", "<cstdint>"} },
196     {"PTRDIFF_MIN", {"<stdint.h>", "<cstdint>"} },
197     {"SIG_ATOMIC_MAX", {"<stdint.h>", "<cstdint>"} },
198     {"SIG_ATOMIC_MIN", {"<stdint.h>", "<cstdint>"} },
199     {"SIZE_MAX", {"<stdint.h>", "<cstdint>"} },
200     {"WINT_MAX", {"<stdint.h>", "<cstdint>"} },
201     {"WINT_MIN", {"<stdint.h>", "<cstdint>"} },
202 
203     /* <time.h>.  */
204     {"asctime", {"<time.h>", "<ctime>"} },
205     {"clock", {"<time.h>", "<ctime>"} },
206     {"clock_t", {"<time.h>", "<ctime>"} },
207     {"ctime", {"<time.h>", "<ctime>"} },
208     {"difftime", {"<time.h>", "<ctime>"} },
209     {"gmtime", {"<time.h>", "<ctime>"} },
210     {"localtime", {"<time.h>", "<ctime>"} },
211     {"mktime", {"<time.h>", "<ctime>"} },
212     {"strftime", {"<time.h>", "<ctime>"} },
213     {"time", {"<time.h>", "<ctime>"} },
214     {"time_t", {"<time.h>", "<ctime>"} },
215     {"tm", {"<time.h>", "<ctime>"} },
216 
217     /* <wchar.h>.  */
218     {"WCHAR_MAX", {"<wchar.h>", "<cwchar>"} },
219     {"WCHAR_MIN", {"<wchar.h>", "<cwchar>"} }
220   };
221   const size_t num_hints = sizeof (hints) / sizeof (hints[0]);
222   for (size_t i = 0; i < num_hints; i++)
223     if (strcmp (name, hints[i].name) == 0)
224       return hints[i].header[lib];
225 
226   static const stdlib_hint c99_cxx11_hints[] = {
227     /* <stdbool.h>.  Defined natively in C++.  */
228     {"bool", {"<stdbool.h>", NULL} },
229     {"true", {"<stdbool.h>", NULL} },
230     {"false", {"<stdbool.h>", NULL} },
231 
232     /* <stdint.h> and <cstdint>.  */
233     {"int8_t", {"<stdint.h>", "<cstdint>"} },
234     {"uint8_t", {"<stdint.h>", "<cstdint>"} },
235     {"int16_t", {"<stdint.h>", "<cstdint>"} },
236     {"uint16_t", {"<stdint.h>", "<cstdint>"} },
237     {"int32_t", {"<stdint.h>", "<cstdint>"} },
238     {"uint32_t", {"<stdint.h>", "<cstdint>"} },
239     {"int64_t", {"<stdint.h>", "<cstdint>"} },
240     {"uint64_t", {"<stdint.h>", "<cstdint>"} },
241     {"intptr_t", {"<stdint.h>", "<cstdint>"} },
242     {"uintptr_t", {"<stdint.h>", "<cstdint>"} },
243     {"INT8_MAX", {"<stdint.h>", "<cstdint>"} },
244     {"INT16_MAX", {"<stdint.h>", "<cstdint>"} },
245     {"INT32_MAX", {"<stdint.h>", "<cstdint>"} },
246     {"INT64_MAX", {"<stdint.h>", "<cstdint>"} },
247     {"UINT8_MAX", {"<stdint.h>", "<cstdint>"} },
248     {"UINT16_MAX", {"<stdint.h>", "<cstdint>"} },
249     {"UINT32_MAX", {"<stdint.h>", "<cstdint>"} },
250     {"UINT64_MAX", {"<stdint.h>", "<cstdint>"} },
251     {"INTPTR_MAX", {"<stdint.h>", "<cstdint>"} },
252     {"UINTPTR_MAX", {"<stdint.h>", "<cstdint>"} }
253   };
254 
255   const size_t num_c99_cxx11_hints = sizeof (c99_cxx11_hints)
256 					     / sizeof (c99_cxx11_hints[0]);
257   if ((lib == STDLIB_C && flag_isoc99)
258       || (lib == STDLIB_CPLUSPLUS && cxx_dialect >= cxx11 ))
259     for (size_t i = 0; i < num_c99_cxx11_hints; i++)
260       if (strcmp (name, c99_cxx11_hints[i].name) == 0)
261 	return c99_cxx11_hints[i].header[lib];
262 
263   return get_string_macro_hint (name, lib);
264 }
265 
266 /* Given non-NULL NAME, return the header name defining it within the C
267    standard library (with '<' and '>'), or NULL.  */
268 
269 const char *
get_c_stdlib_header_for_name(const char * name)270 get_c_stdlib_header_for_name (const char *name)
271 {
272   return get_stdlib_header_for_name (name, STDLIB_C);
273 }
274 
275 /* Given non-NULL NAME, return the header name defining it within the C++
276    standard library (with '<' and '>'), or NULL.  */
277 
278 const char *
get_cp_stdlib_header_for_name(const char * name)279 get_cp_stdlib_header_for_name (const char *name)
280 {
281   return get_stdlib_header_for_name (name, STDLIB_CPLUSPLUS);
282 }
283 
284 /* Given non-NULL NAME, return the header name defining a string macro
285    within the C standard library (with '<' and '>'), or NULL.  */
286 const char *
get_c_stdlib_header_for_string_macro_name(const char * name)287 get_c_stdlib_header_for_string_macro_name (const char *name)
288 {
289   return get_string_macro_hint (name, STDLIB_C);
290 }
291 
292 /* Given non-NULL NAME, return the header name defining a string macro
293    within the C++ standard library (with '<' and '>'), or NULL.  */
294 const char *
get_cp_stdlib_header_for_string_macro_name(const char * name)295 get_cp_stdlib_header_for_string_macro_name (const char *name)
296 {
297   return get_string_macro_hint (name, STDLIB_CPLUSPLUS);
298 }
299 
300 /* Implementation of class suggest_missing_header.  */
301 
302 /* suggest_missing_header's ctor.  */
303 
suggest_missing_header(location_t loc,const char * name,const char * header_hint)304 suggest_missing_header::suggest_missing_header (location_t loc,
305 						const char *name,
306 						const char *header_hint)
307 : deferred_diagnostic (loc), m_name_str (name), m_header_hint (header_hint)
308 {
309   gcc_assert (name);
310   gcc_assert (header_hint);
311 }
312 
313 /* suggest_missing_header's dtor.  */
314 
~suggest_missing_header()315 suggest_missing_header::~suggest_missing_header ()
316 {
317   if (is_suppressed_p ())
318     return;
319 
320   gcc_rich_location richloc (get_location ());
321   maybe_add_include_fixit (&richloc, m_header_hint, true);
322   inform (&richloc,
323 	  "%qs is defined in header %qs;"
324 	  " did you forget to %<#include %s%>?",
325 	  m_name_str, m_header_hint, m_header_hint);
326 }
327