]>
Commit | Line | Data |
---|---|---|
26edace6 | 1 | /* Support for suggestions about missing #include directives. |
83ffe9cd | 2 | Copyright (C) 2017-2023 Free Software Foundation, Inc. |
26edace6 DM |
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" | |
b8f7ff76 | 21 | #define INCLUDE_MEMORY |
26edace6 DM |
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 | ||
9eea5d2d MW |
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 * | |
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 | { | |
ca32b29e | 82 | const size_t num_c99_cxx11_macros = ARRAY_SIZE (c99_cxx11_macros); |
9eea5d2d MW |
83 | for (size_t i = 0; i < num_c99_cxx11_macros; i++) |
84 | if (strcmp (name, c99_cxx11_macros[i]) == 0) | |
85 | return lib == STDLIB_C ? "<inttypes.h>" : "<cinttypes>"; | |
86 | } | |
87 | ||
88 | return NULL; | |
89 | } | |
90 | ||
26edace6 DM |
91 | /* Given non-NULL NAME, return the header name defining it within either |
92 | the standard library (with '<' and '>'), or NULL. | |
93 | Only handles a subset of the most common names within the stdlibs. */ | |
94 | ||
95 | static const char * | |
96 | get_stdlib_header_for_name (const char *name, enum stdlib lib) | |
97 | { | |
98 | gcc_assert (name); | |
99 | gcc_assert (lib < NUM_STDLIBS); | |
100 | ||
101 | static const stdlib_hint hints[] = { | |
62e98ef1 DM |
102 | /* <assert.h> and <cassert>. */ |
103 | {"assert", {"<assert.h>", "<cassert>"} }, | |
104 | ||
26edace6 DM |
105 | /* <errno.h> and <cerrno>. */ |
106 | {"errno", {"<errno.h>", "<cerrno>"} }, | |
107 | ||
108 | /* <limits.h> and <climits>. */ | |
109 | {"CHAR_BIT", {"<limits.h>", "<climits>"} }, | |
110 | {"CHAR_MAX", {"<limits.h>", "<climits>"} }, | |
111 | {"CHAR_MIN", {"<limits.h>", "<climits>"} }, | |
112 | {"INT_MAX", {"<limits.h>", "<climits>"} }, | |
113 | {"INT_MIN", {"<limits.h>", "<climits>"} }, | |
114 | {"LLONG_MAX", {"<limits.h>", "<climits>"} }, | |
115 | {"LLONG_MIN", {"<limits.h>", "<climits>"} }, | |
116 | {"LONG_MAX", {"<limits.h>", "<climits>"} }, | |
117 | {"LONG_MIN", {"<limits.h>", "<climits>"} }, | |
118 | {"MB_LEN_MAX", {"<limits.h>", "<climits>"} }, | |
119 | {"SCHAR_MAX", {"<limits.h>", "<climits>"} }, | |
120 | {"SCHAR_MIN", {"<limits.h>", "<climits>"} }, | |
121 | {"SHRT_MAX", {"<limits.h>", "<climits>"} }, | |
122 | {"SHRT_MIN", {"<limits.h>", "<climits>"} }, | |
123 | {"UCHAR_MAX", {"<limits.h>", "<climits>"} }, | |
124 | {"UINT_MAX", {"<limits.h>", "<climits>"} }, | |
125 | {"ULLONG_MAX", {"<limits.h>", "<climits>"} }, | |
126 | {"ULONG_MAX", {"<limits.h>", "<climits>"} }, | |
127 | {"USHRT_MAX", {"<limits.h>", "<climits>"} }, | |
128 | ||
ec2be203 DM |
129 | /* <float.h> and <cfloat>. */ |
130 | {"DBL_MAX", {"<float.h>", "<cfloat>"} }, | |
131 | {"DBL_MIN", {"<float.h>", "<cfloat>"} }, | |
132 | {"FLT_MAX", {"<float.h>", "<cfloat>"} }, | |
133 | {"FLT_MIN", {"<float.h>", "<cfloat>"} }, | |
134 | {"LDBL_MAX", {"<float.h>", "<cfloat>"} }, | |
135 | {"LDBL_MIN", {"<float.h>", "<cfloat>"} }, | |
136 | ||
26edace6 DM |
137 | /* <stdarg.h> and <cstdarg>. */ |
138 | {"va_list", {"<stdarg.h>", "<cstdarg>"} }, | |
139 | ||
140 | /* <stddef.h> and <cstddef>. */ | |
141 | {"NULL", {"<stddef.h>", "<cstddef>"} }, | |
142 | {"nullptr_t", {NULL, "<cstddef>"} }, | |
143 | {"offsetof", {"<stddef.h>", "<cstddef>"} }, | |
144 | {"ptrdiff_t", {"<stddef.h>", "<cstddef>"} }, | |
145 | {"size_t", {"<stddef.h>", "<cstddef>"} }, | |
146 | {"wchar_t", {"<stddef.h>", NULL /* a keyword in C++ */} }, | |
147 | ||
62e98ef1 | 148 | /* <stdio.h> and <cstdio>. */ |
26edace6 DM |
149 | {"BUFSIZ", {"<stdio.h>", "<cstdio>"} }, |
150 | {"EOF", {"<stdio.h>", "<cstdio>"} }, | |
151 | {"FILE", {"<stdio.h>", "<cstdio>"} }, | |
152 | {"FILENAME_MAX", {"<stdio.h>", "<cstdio>"} }, | |
62e98ef1 | 153 | {"fopen", {"<stdio.h>", "<cstdio>"} }, |
26edace6 | 154 | {"fpos_t", {"<stdio.h>", "<cstdio>"} }, |
62e98ef1 DM |
155 | {"getchar", {"<stdio.h>", "<cstdio>"} }, |
156 | {"printf", {"<stdio.h>", "<cstdio>"} }, | |
157 | {"snprintf", {"<stdio.h>", "<cstdio>"} }, | |
158 | {"sprintf", {"<stdio.h>", "<cstdio>"} }, | |
26edace6 DM |
159 | {"stderr", {"<stdio.h>", "<cstdio>"} }, |
160 | {"stdin", {"<stdio.h>", "<cstdio>"} }, | |
161 | {"stdout", {"<stdio.h>", "<cstdio>"} }, | |
162 | ||
62e98ef1 | 163 | /* <stdlib.h> and <cstdlib>. */ |
93bfadf3 JW |
164 | {"EXIT_FAILURE", {"<stdlib.h>", "<cstdlib>"} }, |
165 | {"EXIT_SUCCESS", {"<stdlib.h>", "<cstdlib>"} }, | |
166 | {"abort", {"<stdlib.h>", "<cstdlib>"} }, | |
167 | {"atexit", {"<stdlib.h>", "<cstdlib>"} }, | |
168 | {"calloc", {"<stdlib.h>", "<cstdlib>"} }, | |
169 | {"exit", {"<stdlib.h>", "<cstdlib>"} }, | |
62e98ef1 | 170 | {"free", {"<stdlib.h>", "<cstdlib>"} }, |
93bfadf3 | 171 | {"getenv", {"<stdlib.h>", "<cstdlib>"} }, |
62e98ef1 DM |
172 | {"malloc", {"<stdlib.h>", "<cstdlib>"} }, |
173 | {"realloc", {"<stdlib.h>", "<cstdlib>"} }, | |
174 | ||
175 | /* <string.h> and <cstring>. */ | |
176 | {"memchr", {"<string.h>", "<cstring>"} }, | |
177 | {"memcmp", {"<string.h>", "<cstring>"} }, | |
178 | {"memcpy", {"<string.h>", "<cstring>"} }, | |
179 | {"memmove", {"<string.h>", "<cstring>"} }, | |
180 | {"memset", {"<string.h>", "<cstring>"} }, | |
181 | {"strcat", {"<string.h>", "<cstring>"} }, | |
182 | {"strchr", {"<string.h>", "<cstring>"} }, | |
183 | {"strcmp", {"<string.h>", "<cstring>"} }, | |
184 | {"strcpy", {"<string.h>", "<cstring>"} }, | |
185 | {"strlen", {"<string.h>", "<cstring>"} }, | |
186 | {"strncat", {"<string.h>", "<cstring>"} }, | |
187 | {"strncmp", {"<string.h>", "<cstring>"} }, | |
188 | {"strncpy", {"<string.h>", "<cstring>"} }, | |
189 | {"strrchr", {"<string.h>", "<cstring>"} }, | |
190 | {"strspn", {"<string.h>", "<cstring>"} }, | |
191 | {"strstr", {"<string.h>", "<cstring>"} }, | |
192 | ||
26edace6 DM |
193 | /* <stdint.h>. */ |
194 | {"PTRDIFF_MAX", {"<stdint.h>", "<cstdint>"} }, | |
195 | {"PTRDIFF_MIN", {"<stdint.h>", "<cstdint>"} }, | |
196 | {"SIG_ATOMIC_MAX", {"<stdint.h>", "<cstdint>"} }, | |
197 | {"SIG_ATOMIC_MIN", {"<stdint.h>", "<cstdint>"} }, | |
198 | {"SIZE_MAX", {"<stdint.h>", "<cstdint>"} }, | |
199 | {"WINT_MAX", {"<stdint.h>", "<cstdint>"} }, | |
200 | {"WINT_MIN", {"<stdint.h>", "<cstdint>"} }, | |
201 | ||
d489ec08 JW |
202 | /* <time.h>. */ |
203 | {"asctime", {"<time.h>", "<ctime>"} }, | |
204 | {"clock", {"<time.h>", "<ctime>"} }, | |
205 | {"clock_t", {"<time.h>", "<ctime>"} }, | |
206 | {"ctime", {"<time.h>", "<ctime>"} }, | |
207 | {"difftime", {"<time.h>", "<ctime>"} }, | |
208 | {"gmtime", {"<time.h>", "<ctime>"} }, | |
209 | {"localtime", {"<time.h>", "<ctime>"} }, | |
210 | {"mktime", {"<time.h>", "<ctime>"} }, | |
211 | {"strftime", {"<time.h>", "<ctime>"} }, | |
212 | {"time", {"<time.h>", "<ctime>"} }, | |
213 | {"time_t", {"<time.h>", "<ctime>"} }, | |
214 | {"tm", {"<time.h>", "<ctime>"} }, | |
215 | ||
26edace6 DM |
216 | /* <wchar.h>. */ |
217 | {"WCHAR_MAX", {"<wchar.h>", "<cwchar>"} }, | |
218 | {"WCHAR_MIN", {"<wchar.h>", "<cwchar>"} } | |
219 | }; | |
ca32b29e | 220 | const size_t num_hints = ARRAY_SIZE (hints); |
26edace6 | 221 | for (size_t i = 0; i < num_hints; i++) |
01512446 | 222 | if (strcmp (name, hints[i].name) == 0) |
26edace6 | 223 | return hints[i].header[lib]; |
45c50b6a | 224 | |
af114c38 MW |
225 | static const stdlib_hint c99_cxx11_hints[] = { |
226 | /* <stdbool.h>. Defined natively in C++. */ | |
227 | {"bool", {"<stdbool.h>", NULL} }, | |
228 | {"true", {"<stdbool.h>", NULL} }, | |
229 | {"false", {"<stdbool.h>", NULL} }, | |
230 | ||
231 | /* <stdint.h> and <cstdint>. */ | |
232 | {"int8_t", {"<stdint.h>", "<cstdint>"} }, | |
233 | {"uint8_t", {"<stdint.h>", "<cstdint>"} }, | |
234 | {"int16_t", {"<stdint.h>", "<cstdint>"} }, | |
235 | {"uint16_t", {"<stdint.h>", "<cstdint>"} }, | |
236 | {"int32_t", {"<stdint.h>", "<cstdint>"} }, | |
237 | {"uint32_t", {"<stdint.h>", "<cstdint>"} }, | |
238 | {"int64_t", {"<stdint.h>", "<cstdint>"} }, | |
239 | {"uint64_t", {"<stdint.h>", "<cstdint>"} }, | |
240 | {"intptr_t", {"<stdint.h>", "<cstdint>"} }, | |
241 | {"uintptr_t", {"<stdint.h>", "<cstdint>"} }, | |
242 | {"INT8_MAX", {"<stdint.h>", "<cstdint>"} }, | |
243 | {"INT16_MAX", {"<stdint.h>", "<cstdint>"} }, | |
244 | {"INT32_MAX", {"<stdint.h>", "<cstdint>"} }, | |
245 | {"INT64_MAX", {"<stdint.h>", "<cstdint>"} }, | |
246 | {"UINT8_MAX", {"<stdint.h>", "<cstdint>"} }, | |
247 | {"UINT16_MAX", {"<stdint.h>", "<cstdint>"} }, | |
248 | {"UINT32_MAX", {"<stdint.h>", "<cstdint>"} }, | |
249 | {"UINT64_MAX", {"<stdint.h>", "<cstdint>"} }, | |
250 | {"INTPTR_MAX", {"<stdint.h>", "<cstdint>"} }, | |
251 | {"UINTPTR_MAX", {"<stdint.h>", "<cstdint>"} } | |
252 | }; | |
253 | ||
254 | const size_t num_c99_cxx11_hints = sizeof (c99_cxx11_hints) | |
255 | / sizeof (c99_cxx11_hints[0]); | |
256 | if ((lib == STDLIB_C && flag_isoc99) | |
257 | || (lib == STDLIB_CPLUSPLUS && cxx_dialect >= cxx11 )) | |
258 | for (size_t i = 0; i < num_c99_cxx11_hints; i++) | |
259 | if (strcmp (name, c99_cxx11_hints[i].name) == 0) | |
260 | return c99_cxx11_hints[i].header[lib]; | |
45c50b6a | 261 | |
9eea5d2d | 262 | return get_string_macro_hint (name, lib); |
26edace6 DM |
263 | } |
264 | ||
265 | /* Given non-NULL NAME, return the header name defining it within the C | |
266 | standard library (with '<' and '>'), or NULL. */ | |
267 | ||
268 | const char * | |
269 | get_c_stdlib_header_for_name (const char *name) | |
270 | { | |
271 | return get_stdlib_header_for_name (name, STDLIB_C); | |
272 | } | |
273 | ||
274 | /* Given non-NULL NAME, return the header name defining it within the C++ | |
275 | standard library (with '<' and '>'), or NULL. */ | |
276 | ||
277 | const char * | |
278 | get_cp_stdlib_header_for_name (const char *name) | |
279 | { | |
280 | return get_stdlib_header_for_name (name, STDLIB_CPLUSPLUS); | |
281 | } | |
282 | ||
9eea5d2d MW |
283 | /* Given non-NULL NAME, return the header name defining a string macro |
284 | within the C standard library (with '<' and '>'), or NULL. */ | |
285 | const char * | |
286 | get_c_stdlib_header_for_string_macro_name (const char *name) | |
287 | { | |
288 | return get_string_macro_hint (name, STDLIB_C); | |
289 | } | |
290 | ||
1dc83b46 MW |
291 | /* Given non-NULL NAME, return the header name defining a string macro |
292 | within the C++ standard library (with '<' and '>'), or NULL. */ | |
293 | const char * | |
294 | get_cp_stdlib_header_for_string_macro_name (const char *name) | |
295 | { | |
296 | return get_string_macro_hint (name, STDLIB_CPLUSPLUS); | |
297 | } | |
298 | ||
26edace6 DM |
299 | /* Implementation of class suggest_missing_header. */ |
300 | ||
301 | /* suggest_missing_header's ctor. */ | |
302 | ||
303 | suggest_missing_header::suggest_missing_header (location_t loc, | |
304 | const char *name, | |
305 | const char *header_hint) | |
306 | : deferred_diagnostic (loc), m_name_str (name), m_header_hint (header_hint) | |
307 | { | |
308 | gcc_assert (name); | |
309 | gcc_assert (header_hint); | |
310 | } | |
311 | ||
312 | /* suggest_missing_header's dtor. */ | |
313 | ||
314 | suggest_missing_header::~suggest_missing_header () | |
315 | { | |
316 | if (is_suppressed_p ()) | |
317 | return; | |
318 | ||
319 | gcc_rich_location richloc (get_location ()); | |
85204e23 | 320 | maybe_add_include_fixit (&richloc, m_header_hint, true); |
26edace6 DM |
321 | inform (&richloc, |
322 | "%qs is defined in header %qs;" | |
7474c46c | 323 | " this is probably fixable by adding %<#include %s%>", |
26edace6 DM |
324 | m_name_str, m_header_hint, m_header_hint); |
325 | } |