1/* Support for suggestions about missing #include directives.
2 Copyright (C) 2017-2023 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 3, or (at your option) any later
9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
17along 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
31enum 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
43struct 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
57static const char *
58get_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 = ARRAY_SIZE (c99_cxx11_macros);
83 for (size_t i = 0; i < num_c99_cxx11_macros; i++)
84 if (strcmp (s1: name, s2: c99_cxx11_macros[i]) == 0)
85 return lib == STDLIB_C ? "<inttypes.h>" : "<cinttypes>";
86 }
87
88 return NULL;
89}
90
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
95static const char *
96get_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[] = {
102 /* <assert.h> and <cassert>. */
103 {.name: "assert", .header: {"<assert.h>", "<cassert>"} },
104
105 /* <errno.h> and <cerrno>. */
106 {.name: "errno", .header: {"<errno.h>", "<cerrno>"} },
107
108 /* <limits.h> and <climits>. */
109 {.name: "CHAR_BIT", .header: {"<limits.h>", "<climits>"} },
110 {.name: "CHAR_MAX", .header: {"<limits.h>", "<climits>"} },
111 {.name: "CHAR_MIN", .header: {"<limits.h>", "<climits>"} },
112 {.name: "INT_MAX", .header: {"<limits.h>", "<climits>"} },
113 {.name: "INT_MIN", .header: {"<limits.h>", "<climits>"} },
114 {.name: "LLONG_MAX", .header: {"<limits.h>", "<climits>"} },
115 {.name: "LLONG_MIN", .header: {"<limits.h>", "<climits>"} },
116 {.name: "LONG_MAX", .header: {"<limits.h>", "<climits>"} },
117 {.name: "LONG_MIN", .header: {"<limits.h>", "<climits>"} },
118 {.name: "MB_LEN_MAX", .header: {"<limits.h>", "<climits>"} },
119 {.name: "SCHAR_MAX", .header: {"<limits.h>", "<climits>"} },
120 {.name: "SCHAR_MIN", .header: {"<limits.h>", "<climits>"} },
121 {.name: "SHRT_MAX", .header: {"<limits.h>", "<climits>"} },
122 {.name: "SHRT_MIN", .header: {"<limits.h>", "<climits>"} },
123 {.name: "UCHAR_MAX", .header: {"<limits.h>", "<climits>"} },
124 {.name: "UINT_MAX", .header: {"<limits.h>", "<climits>"} },
125 {.name: "ULLONG_MAX", .header: {"<limits.h>", "<climits>"} },
126 {.name: "ULONG_MAX", .header: {"<limits.h>", "<climits>"} },
127 {.name: "USHRT_MAX", .header: {"<limits.h>", "<climits>"} },
128
129 /* <float.h> and <cfloat>. */
130 {.name: "DBL_MAX", .header: {"<float.h>", "<cfloat>"} },
131 {.name: "DBL_MIN", .header: {"<float.h>", "<cfloat>"} },
132 {.name: "FLT_MAX", .header: {"<float.h>", "<cfloat>"} },
133 {.name: "FLT_MIN", .header: {"<float.h>", "<cfloat>"} },
134 {.name: "LDBL_MAX", .header: {"<float.h>", "<cfloat>"} },
135 {.name: "LDBL_MIN", .header: {"<float.h>", "<cfloat>"} },
136
137 /* <stdarg.h> and <cstdarg>. */
138 {.name: "va_list", .header: {"<stdarg.h>", "<cstdarg>"} },
139
140 /* <stddef.h> and <cstddef>. */
141 {.name: "NULL", .header: {"<stddef.h>", "<cstddef>"} },
142 {.name: "nullptr_t", .header: {NULL, "<cstddef>"} },
143 {.name: "offsetof", .header: {"<stddef.h>", "<cstddef>"} },
144 {.name: "ptrdiff_t", .header: {"<stddef.h>", "<cstddef>"} },
145 {.name: "size_t", .header: {"<stddef.h>", "<cstddef>"} },
146 {.name: "wchar_t", .header: {"<stddef.h>", NULL /* a keyword in C++ */} },
147
148 /* <stdio.h> and <cstdio>. */
149 {.name: "BUFSIZ", .header: {"<stdio.h>", "<cstdio>"} },
150 {.name: "EOF", .header: {"<stdio.h>", "<cstdio>"} },
151 {.name: "FILE", .header: {"<stdio.h>", "<cstdio>"} },
152 {.name: "FILENAME_MAX", .header: {"<stdio.h>", "<cstdio>"} },
153 {.name: "fopen", .header: {"<stdio.h>", "<cstdio>"} },
154 {.name: "fpos_t", .header: {"<stdio.h>", "<cstdio>"} },
155 {.name: "getchar", .header: {"<stdio.h>", "<cstdio>"} },
156 {.name: "printf", .header: {"<stdio.h>", "<cstdio>"} },
157 {.name: "snprintf", .header: {"<stdio.h>", "<cstdio>"} },
158 {.name: "sprintf", .header: {"<stdio.h>", "<cstdio>"} },
159 {.name: "stderr", .header: {"<stdio.h>", "<cstdio>"} },
160 {.name: "stdin", .header: {"<stdio.h>", "<cstdio>"} },
161 {.name: "stdout", .header: {"<stdio.h>", "<cstdio>"} },
162
163 /* <stdlib.h> and <cstdlib>. */
164 {.name: "EXIT_FAILURE", .header: {"<stdlib.h>", "<cstdlib>"} },
165 {.name: "EXIT_SUCCESS", .header: {"<stdlib.h>", "<cstdlib>"} },
166 {.name: "abort", .header: {"<stdlib.h>", "<cstdlib>"} },
167 {.name: "atexit", .header: {"<stdlib.h>", "<cstdlib>"} },
168 {.name: "calloc", .header: {"<stdlib.h>", "<cstdlib>"} },
169 {.name: "exit", .header: {"<stdlib.h>", "<cstdlib>"} },
170 {.name: "free", .header: {"<stdlib.h>", "<cstdlib>"} },
171 {.name: "getenv", .header: {"<stdlib.h>", "<cstdlib>"} },
172 {.name: "malloc", .header: {"<stdlib.h>", "<cstdlib>"} },
173 {.name: "realloc", .header: {"<stdlib.h>", "<cstdlib>"} },
174
175 /* <string.h> and <cstring>. */
176 {.name: "memchr", .header: {"<string.h>", "<cstring>"} },
177 {.name: "memcmp", .header: {"<string.h>", "<cstring>"} },
178 {.name: "memcpy", .header: {"<string.h>", "<cstring>"} },
179 {.name: "memmove", .header: {"<string.h>", "<cstring>"} },
180 {.name: "memset", .header: {"<string.h>", "<cstring>"} },
181 {.name: "strcat", .header: {"<string.h>", "<cstring>"} },
182 {.name: "strchr", .header: {"<string.h>", "<cstring>"} },
183 {.name: "strcmp", .header: {"<string.h>", "<cstring>"} },
184 {.name: "strcpy", .header: {"<string.h>", "<cstring>"} },
185 {.name: "strlen", .header: {"<string.h>", "<cstring>"} },
186 {.name: "strncat", .header: {"<string.h>", "<cstring>"} },
187 {.name: "strncmp", .header: {"<string.h>", "<cstring>"} },
188 {.name: "strncpy", .header: {"<string.h>", "<cstring>"} },
189 {.name: "strrchr", .header: {"<string.h>", "<cstring>"} },
190 {.name: "strspn", .header: {"<string.h>", "<cstring>"} },
191 {.name: "strstr", .header: {"<string.h>", "<cstring>"} },
192
193 /* <stdint.h>. */
194 {.name: "PTRDIFF_MAX", .header: {"<stdint.h>", "<cstdint>"} },
195 {.name: "PTRDIFF_MIN", .header: {"<stdint.h>", "<cstdint>"} },
196 {.name: "SIG_ATOMIC_MAX", .header: {"<stdint.h>", "<cstdint>"} },
197 {.name: "SIG_ATOMIC_MIN", .header: {"<stdint.h>", "<cstdint>"} },
198 {.name: "SIZE_MAX", .header: {"<stdint.h>", "<cstdint>"} },
199 {.name: "WINT_MAX", .header: {"<stdint.h>", "<cstdint>"} },
200 {.name: "WINT_MIN", .header: {"<stdint.h>", "<cstdint>"} },
201
202 /* <time.h>. */
203 {.name: "asctime", .header: {"<time.h>", "<ctime>"} },
204 {.name: "clock", .header: {"<time.h>", "<ctime>"} },
205 {.name: "clock_t", .header: {"<time.h>", "<ctime>"} },
206 {.name: "ctime", .header: {"<time.h>", "<ctime>"} },
207 {.name: "difftime", .header: {"<time.h>", "<ctime>"} },
208 {.name: "gmtime", .header: {"<time.h>", "<ctime>"} },
209 {.name: "localtime", .header: {"<time.h>", "<ctime>"} },
210 {.name: "mktime", .header: {"<time.h>", "<ctime>"} },
211 {.name: "strftime", .header: {"<time.h>", "<ctime>"} },
212 {.name: "time", .header: {"<time.h>", "<ctime>"} },
213 {.name: "time_t", .header: {"<time.h>", "<ctime>"} },
214 {.name: "tm", .header: {"<time.h>", "<ctime>"} },
215
216 /* <wchar.h>. */
217 {.name: "WCHAR_MAX", .header: {"<wchar.h>", "<cwchar>"} },
218 {.name: "WCHAR_MIN", .header: {"<wchar.h>", "<cwchar>"} }
219 };
220 const size_t num_hints = ARRAY_SIZE (hints);
221 for (size_t i = 0; i < num_hints; i++)
222 if (strcmp (s1: name, s2: hints[i].name) == 0)
223 return hints[i].header[lib];
224
225 static const stdlib_hint c99_cxx11_hints[] = {
226 /* <stdbool.h>. Defined natively in C++. */
227 {.name: "bool", .header: {"<stdbool.h>", NULL} },
228 {.name: "true", .header: {"<stdbool.h>", NULL} },
229 {.name: "false", .header: {"<stdbool.h>", NULL} },
230
231 /* <stdint.h> and <cstdint>. */
232 {.name: "int8_t", .header: {"<stdint.h>", "<cstdint>"} },
233 {.name: "uint8_t", .header: {"<stdint.h>", "<cstdint>"} },
234 {.name: "int16_t", .header: {"<stdint.h>", "<cstdint>"} },
235 {.name: "uint16_t", .header: {"<stdint.h>", "<cstdint>"} },
236 {.name: "int32_t", .header: {"<stdint.h>", "<cstdint>"} },
237 {.name: "uint32_t", .header: {"<stdint.h>", "<cstdint>"} },
238 {.name: "int64_t", .header: {"<stdint.h>", "<cstdint>"} },
239 {.name: "uint64_t", .header: {"<stdint.h>", "<cstdint>"} },
240 {.name: "intptr_t", .header: {"<stdint.h>", "<cstdint>"} },
241 {.name: "uintptr_t", .header: {"<stdint.h>", "<cstdint>"} },
242 {.name: "INT8_MAX", .header: {"<stdint.h>", "<cstdint>"} },
243 {.name: "INT16_MAX", .header: {"<stdint.h>", "<cstdint>"} },
244 {.name: "INT32_MAX", .header: {"<stdint.h>", "<cstdint>"} },
245 {.name: "INT64_MAX", .header: {"<stdint.h>", "<cstdint>"} },
246 {.name: "UINT8_MAX", .header: {"<stdint.h>", "<cstdint>"} },
247 {.name: "UINT16_MAX", .header: {"<stdint.h>", "<cstdint>"} },
248 {.name: "UINT32_MAX", .header: {"<stdint.h>", "<cstdint>"} },
249 {.name: "UINT64_MAX", .header: {"<stdint.h>", "<cstdint>"} },
250 {.name: "INTPTR_MAX", .header: {"<stdint.h>", "<cstdint>"} },
251 {.name: "UINTPTR_MAX", .header: {"<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 (s1: name, s2: c99_cxx11_hints[i].name) == 0)
260 return c99_cxx11_hints[i].header[lib];
261
262 return get_string_macro_hint (name, lib);
263}
264
265/* Given non-NULL NAME, return the header name defining it within the C
266 standard library (with '<' and '>'), or NULL. */
267
268const char *
269get_c_stdlib_header_for_name (const char *name)
270{
271 return get_stdlib_header_for_name (name, lib: 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
277const char *
278get_cp_stdlib_header_for_name (const char *name)
279{
280 return get_stdlib_header_for_name (name, lib: STDLIB_CPLUSPLUS);
281}
282
283/* Given non-NULL NAME, return the header name defining a string macro
284 within the C standard library (with '<' and '>'), or NULL. */
285const char *
286get_c_stdlib_header_for_string_macro_name (const char *name)
287{
288 return get_string_macro_hint (name, lib: STDLIB_C);
289}
290
291/* Given non-NULL NAME, return the header name defining a string macro
292 within the C++ standard library (with '<' and '>'), or NULL. */
293const char *
294get_cp_stdlib_header_for_string_macro_name (const char *name)
295{
296 return get_string_macro_hint (name, lib: STDLIB_CPLUSPLUS);
297}
298
299/* Implementation of class suggest_missing_header. */
300
301/* suggest_missing_header's ctor. */
302
303suggest_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
314suggest_missing_header::~suggest_missing_header ()
315{
316 if (is_suppressed_p ())
317 return;
318
319 gcc_rich_location richloc (get_location ());
320 maybe_add_include_fixit (&richloc, m_header_hint, true);
321 inform (&richloc,
322 "%qs is defined in header %qs;"
323 " this is probably fixable by adding %<#include %s%>",
324 m_name_str, m_header_hint, m_header_hint);
325}
326

source code of gcc/c-family/known-headers.cc