1/* Precompiled header implementation for the C languages.
2 Copyright (C) 2000-2023 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 3, or (at your option)
9any later version.
10
11GCC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for 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#include "system.h"
22#include "coretypes.h"
23#include "target.h"
24#include "c-common.h"
25#include "timevar.h"
26#include "flags.h"
27#include "debug.h"
28#include "c-pragma.h"
29#include "langhooks.h"
30#include "hosthooks.h"
31
32/* This is a list of flag variables that must match exactly, and their
33 names for the error message. The possible values for *flag_var must
34 fit in a 'signed char'. */
35
36static const struct c_pch_matching
37{
38 int *flag_var;
39 const char *flag_name;
40} pch_matching[] = {
41 { .flag_var: &flag_exceptions, .flag_name: "-fexceptions" },
42};
43
44enum {
45 MATCH_SIZE = ARRAY_SIZE (pch_matching)
46};
47
48/* Information about flags and suchlike that affect PCH validity.
49
50 Before this structure is read, both an initial 8-character identification
51 string, and a 16-byte checksum, have been read and validated. */
52
53struct c_pch_validity
54{
55 uint32_t pch_write_symbols;
56 signed char match[MATCH_SIZE];
57 size_t target_data_length;
58};
59
60#define IDENT_LENGTH 8
61
62/* The file we'll be writing the PCH to. */
63static FILE *pch_outfile;
64
65static const char *get_ident (void);
66
67/* Compute an appropriate 8-byte magic number for the PCH file, so that
68 utilities like file(1) can identify it, and so that GCC can quickly
69 ignore non-PCH files and PCH files that are of a completely different
70 format. */
71
72static const char *
73get_ident (void)
74{
75 static char result[IDENT_LENGTH];
76 static const char templ[] = "gpch.014";
77 static const char c_language_chars[] = "Co+O";
78
79 memcpy (dest: result, src: templ, IDENT_LENGTH);
80 result[4] = c_language_chars[c_language];
81
82 return result;
83}
84
85/* Whether preprocessor state should be saved by pch_init. */
86
87static bool pch_ready_to_save_cpp_state = false;
88
89/* Prepare to write a PCH file, if one is being written. This is
90 called at the start of compilation. */
91
92void
93pch_init (void)
94{
95 FILE *f;
96 struct c_pch_validity v;
97 void *target_validity;
98 static const char partial_pch[] = "gpcWrite";
99
100 if (!pch_file)
101 return;
102
103 f = fopen (filename: pch_file, modes: "w+b");
104 if (f == NULL)
105 fatal_error (input_location, "cannot create precompiled header %s: %m",
106 pch_file);
107 pch_outfile = f;
108
109 memset (s: &v, c: '\0', n: sizeof (v));
110 v.pch_write_symbols = write_symbols;
111 {
112 size_t i;
113 for (i = 0; i < MATCH_SIZE; i++)
114 {
115 v.match[i] = *pch_matching[i].flag_var;
116 gcc_assert (v.match[i] == *pch_matching[i].flag_var);
117 }
118 }
119 target_validity = targetm.get_pch_validity (&v.target_data_length);
120
121 if (fwrite (ptr: partial_pch, IDENT_LENGTH, n: 1, s: f) != 1
122 || fwrite (ptr: executable_checksum, size: 16, n: 1, s: f) != 1
123 || fwrite (ptr: &v, size: sizeof (v), n: 1, s: f) != 1
124 || fwrite (ptr: target_validity, size: v.target_data_length, n: 1, s: f) != 1)
125 fatal_error (input_location, "cannot write to %s: %m", pch_file);
126
127 /* Let the debugging format deal with the PCHness. */
128 (*debug_hooks->handle_pch) (0);
129
130 if (pch_ready_to_save_cpp_state)
131 pch_cpp_save_state ();
132
133 XDELETE (target_validity);
134}
135
136/* Whether preprocessor state has been saved in a PCH file. */
137
138static bool pch_cpp_state_saved = false;
139
140/* Save preprocessor state in a PCH file, after implicitly included
141 headers have been read. If the PCH file has not yet been opened,
142 record that state should be saved when it is opened. */
143
144void
145pch_cpp_save_state (void)
146{
147 if (!pch_cpp_state_saved)
148 {
149 if (pch_outfile)
150 {
151 cpp_save_state (parse_in, pch_outfile);
152 pch_cpp_state_saved = true;
153 }
154 else
155 pch_ready_to_save_cpp_state = true;
156 }
157}
158
159/* Write the PCH file. This is called at the end of a compilation which
160 will produce a PCH file. */
161
162void
163c_common_write_pch (void)
164{
165 timevar_push (tv: TV_PCH_SAVE);
166
167 targetm.prepare_pch_save ();
168
169 (*debug_hooks->handle_pch) (1);
170
171 prepare_target_option_nodes_for_pch ();
172
173 cpp_write_pch_deps (parse_in, pch_outfile);
174
175 gt_pch_save (f: pch_outfile);
176
177 timevar_push (tv: TV_PCH_CPP_SAVE);
178 cpp_write_pch_state (parse_in, pch_outfile);
179 timevar_pop (tv: TV_PCH_CPP_SAVE);
180
181 if (fseek (stream: pch_outfile, off: 0, SEEK_SET) != 0
182 || fwrite (ptr: get_ident (), IDENT_LENGTH, n: 1, s: pch_outfile) != 1)
183 fatal_error (input_location, "cannot write %s: %m", pch_file);
184
185 fclose (stream: pch_outfile);
186
187 timevar_pop (tv: TV_PCH_SAVE);
188}
189
190/* Check the PCH file called NAME, open on FD, to see if it can be
191 used in this compilation. Return 1 if valid, 0 if the file can't
192 be used now but might be if it's seen later in the compilation, and
193 2 if this file could never be used in the compilation. */
194
195int
196c_common_valid_pch (cpp_reader *pfile, const char *name, int fd)
197{
198 int sizeread;
199 int result;
200 char ident[IDENT_LENGTH + 16];
201 const char *pch_ident;
202 struct c_pch_validity v;
203
204 /* Perform a quick test of whether this is a valid
205 precompiled header for the current language. */
206
207 /* C++ modules and PCH don't play together. */
208 if (flag_modules)
209 return 2;
210
211 sizeread = read (fd: fd, buf: ident, IDENT_LENGTH + 16);
212 if (sizeread == -1)
213 fatal_error (input_location, "cannot read %s: %m", name);
214 else if (sizeread != IDENT_LENGTH + 16)
215 {
216 cpp_warning (pfile, CPP_W_INVALID_PCH, msgid: "%s: too short to be a PCH file",
217 name);
218 return 2;
219 }
220
221 pch_ident = get_ident();
222 if (memcmp (s1: ident, s2: pch_ident, IDENT_LENGTH) != 0)
223 {
224 if (memcmp (s1: ident, s2: pch_ident, n: 5) == 0)
225 /* It's a PCH, for the right language, but has the wrong version. */
226 cpp_warning (pfile, CPP_W_INVALID_PCH,
227 msgid: "%s: not compatible with this GCC version", name);
228 else if (memcmp (s1: ident, s2: pch_ident, n: 4) == 0)
229 /* It's a PCH for the wrong language. */
230 cpp_warning (pfile, CPP_W_INVALID_PCH, msgid: "%s: not for %s", name,
231 lang_hooks.name);
232 else
233 /* Not any kind of PCH. */
234 cpp_warning (pfile, CPP_W_INVALID_PCH, msgid: "%s: not a PCH file", name);
235 return 2;
236 }
237 if (memcmp (s1: ident + IDENT_LENGTH, s2: executable_checksum, n: 16) != 0)
238 {
239 cpp_warning (pfile, CPP_W_INVALID_PCH,
240 msgid: "%s: created by a different GCC executable", name);
241 return 2;
242 }
243
244 /* At this point, we know it's a PCH file created by this
245 executable, so it ought to be long enough that we can read a
246 c_pch_validity structure. */
247 if (read (fd: fd, buf: &v, nbytes: sizeof (v)) != sizeof (v))
248 fatal_error (input_location, "cannot read %s: %m", name);
249
250 /* The allowable debug info combinations are that either the PCH file
251 was built with the same as is being used now, or the PCH file was
252 built for some kind of debug info but now none is in use. */
253 if (v.pch_write_symbols != write_symbols
254 && write_symbols != NO_DEBUG)
255 {
256 char *created_str = xstrdup (debug_set_names (w_symbols: v.pch_write_symbols));
257 char *used_str = xstrdup (debug_set_names (write_symbols));
258 cpp_warning (pfile, CPP_W_INVALID_PCH,
259 msgid: "%s: created with '%s' debug info, but used with '%s'", name,
260 created_str, used_str);
261 free (ptr: created_str);
262 free (ptr: used_str);
263 return 2;
264 }
265
266 /* Check flags that must match exactly. */
267 {
268 size_t i;
269 for (i = 0; i < MATCH_SIZE; i++)
270 if (*pch_matching[i].flag_var != v.match[i])
271 {
272 cpp_warning (pfile, CPP_W_INVALID_PCH,
273 msgid: "%s: settings for %s do not match", name,
274 pch_matching[i].flag_name);
275 return 2;
276 }
277 }
278
279 /* Check the target-specific validity data. */
280 {
281 void *this_file_data = xmalloc (v.target_data_length);
282 const char *msg;
283
284 if ((size_t) read (fd: fd, buf: this_file_data, nbytes: v.target_data_length)
285 != v.target_data_length)
286 fatal_error (input_location, "cannot read %s: %m", name);
287 msg = targetm.pch_valid_p (this_file_data, v.target_data_length);
288 free (ptr: this_file_data);
289 if (msg != NULL)
290 {
291 cpp_warning (pfile, CPP_W_INVALID_PCH, msgid: "%s: %s", name, msg);
292 return 2;
293 }
294 }
295
296 /* Check the preprocessor macros are the same as when the PCH was
297 generated. */
298
299 result = cpp_valid_state (pfile, name, fd);
300 if (result == -1)
301 return 2;
302 else
303 return result == 0;
304}
305
306/* If non-NULL, this function is called after a precompile header file
307 is loaded. */
308void (*lang_post_pch_load) (void);
309
310/* Load in the PCH file NAME, open on FD. It was originally searched for
311 by ORIG_NAME. */
312
313void
314c_common_read_pch (cpp_reader *pfile, const char *name,
315 int fd, const char *orig_name ATTRIBUTE_UNUSED)
316{
317 FILE *f;
318 struct save_macro_data *smd;
319 expanded_location saved_loc;
320 bool saved_trace_includes;
321
322 timevar_push (tv: TV_PCH_RESTORE);
323
324 f = fdopen (fd, "rb");
325 if (f == NULL)
326 {
327 cpp_errno (pfile, CPP_DL_ERROR, msgid: "calling fdopen");
328 close (fd: fd);
329 goto end;
330 }
331
332 cpp_get_callbacks (parse_in)->valid_pch = NULL;
333
334 /* Save the location and then restore it after reading the PCH. */
335 saved_loc = expand_location (line_table->highest_line);
336 saved_trace_includes = line_table->trace_includes;
337
338 timevar_push (tv: TV_PCH_CPP_RESTORE);
339 cpp_prepare_state (pfile, &smd);
340 timevar_pop (tv: TV_PCH_CPP_RESTORE);
341
342 gt_pch_restore (f);
343 cpp_set_line_map (pfile, line_table);
344 rebuild_location_adhoc_htab (line_table);
345
346 timevar_push (tv: TV_PCH_CPP_RESTORE);
347 if (cpp_read_state (pfile, name, f, smd) != 0)
348 {
349 fclose (stream: f);
350 timevar_pop (tv: TV_PCH_CPP_RESTORE);
351 goto end;
352 }
353 timevar_pop (tv: TV_PCH_CPP_RESTORE);
354
355
356 fclose (stream: f);
357
358 line_table->trace_includes = saved_trace_includes;
359 linemap_add (line_table, LC_ENTER, sysp: 0, to_file: saved_loc.file, to_line: saved_loc.line);
360
361 /* Give the front end a chance to take action after a PCH file has
362 been loaded. */
363 if (lang_post_pch_load)
364 (*lang_post_pch_load) ();
365
366end:
367 timevar_pop (tv: TV_PCH_RESTORE);
368}
369
370/* Indicate that no more PCH files should be read. */
371
372void
373c_common_no_more_pch (void)
374{
375 if (cpp_get_callbacks (parse_in)->valid_pch)
376 {
377 cpp_get_callbacks (parse_in)->valid_pch = NULL;
378 void *addr = NULL;
379 host_hooks.gt_pch_use_address (addr, 0, -1, 0);
380 }
381}
382
383/* Handle #pragma GCC pch_preprocess, to load in the PCH file. */
384
385void
386c_common_pch_pragma (cpp_reader *pfile, const char *name)
387{
388 int fd;
389
390 if (!cpp_get_options (pfile)->preprocessed)
391 {
392 error ("%<pch_preprocess%> pragma should only be used "
393 "with %<-fpreprocessed%>");
394 inform (input_location, "use %<#include%> instead");
395 return;
396 }
397
398 fd = open (file: name, O_RDONLY | O_BINARY, 0666);
399 if (fd == -1)
400 fatal_error (input_location, "%s: couldn%'t open PCH file: %m", name);
401
402 if (c_common_valid_pch (pfile, name, fd) != 1)
403 {
404 if (!cpp_get_options (pfile)->warn_invalid_pch)
405 inform (input_location, "use %<-Winvalid-pch%> for more information");
406 fatal_error (input_location, "%s: PCH file was invalid", name);
407 }
408
409 c_common_read_pch (pfile, name, fd, orig_name: name);
410
411 close (fd: fd);
412}
413
414

source code of gcc/c-family/c-pch.cc