static void list_top(char *fn) { int status,done; #define BUFLEN 256 char buf[BUFLEN]; gmx_cpp_t handle; char *cppopts[] = { NULL }; status = cpp_open_file(fn,&handle,cppopts); if (status != 0) gmx_fatal(FARGS,cpp_error(&handle,status)); do { status = cpp_read_line(&handle,BUFLEN,buf); done = (status == eCPP_EOF); if (!done) { if (status != eCPP_OK) gmx_fatal(FARGS,cpp_error(&handle,status)); else printf("%s\n",buf); } } while (!done); status = cpp_close_file(&handle); if (status != eCPP_OK) gmx_fatal(FARGS,cpp_error(&handle,status)); }
/* Returns TRUE if the sequence starting at buffer->cur is invalid in an identifier. FIRST is TRUE if this starts an identifier. */ static bool forms_identifier_p (cpp_reader *pfile, int first) { cpp_buffer *buffer = pfile->buffer; if (*buffer->cur == '$') { if (!CPP_OPTION (pfile, dollars_in_ident)) return false; buffer->cur++; if (CPP_OPTION (pfile, warn_dollars) && !pfile->state.skipping) { CPP_OPTION (pfile, warn_dollars) = 0; cpp_error (pfile, CPP_DL_PEDWARN, "'$' in identifier or number"); } return true; } /* Is this a syntactically valid UCN? */ if (0 && *buffer->cur == '\\' && (buffer->cur[1] == 'u' || buffer->cur[1] == 'U')) { buffer->cur += 2; if (_cpp_valid_ucn (pfile, &buffer->cur, buffer->rlimit, 1 + !first)) return true; buffer->cur -= 2; } return false; }
/* Skips whitespace, saving the next non-whitespace character. */ static void skip_whitespace (cpp_reader *pfile, cppchar_t c) { cpp_buffer *buffer = pfile->buffer; bool saw_NUL = false; do { /* Horizontal space always OK. */ if (c == ' ' || c == '\t') ; /* Just \f \v or \0 left. */ else if (c == '\0') saw_NUL = true; else if (pfile->state.in_directive && CPP_PEDANTIC (pfile)) cpp_error_with_line (pfile, CPP_DL_PEDWARN, pfile->line_table->highest_line, CPP_BUF_COL (buffer), "%s in preprocessing directive", c == '\f' ? "form feed" : "vertical tab"); c = *buffer->cur++; } /* We only want non-vertical space, i.e. ' ' \t \f \v \0. */ while (is_nvspace (c)); if (saw_NUL) cpp_error (pfile, CPP_DL_WARNING, "null character(s) ignored"); buffer->cur--; }
bool cpp_errno_filename (cpp_reader *pfile, int level, const char *filename) { if (filename[0] == '\0') filename = _("stdout"); return cpp_error (pfile, level, "%s: %s", filename, xstrerror (errno)); }
bool cpp_errno (cpp_reader *pfile, int level, const char *msgid) { if (msgid[0] == '\0') msgid = _("stdout"); return cpp_error (pfile, level, "%s: %s", msgid, xstrerror (errno)); }
/* Lex an identifier starting at BUFFER->CUR - 1. */ static cpp_hashnode * lex_identifier (cpp_reader *pfile, const uchar *base) { cpp_hashnode *result; const uchar *cur; do { cur = pfile->buffer->cur; /* N.B. ISIDNUM does not include $. */ while (ISIDNUM (*cur)) cur++; pfile->buffer->cur = cur; } while (forms_identifier_p (pfile, false)); result = (cpp_hashnode *) ht_lookup (pfile->hash_table, base, cur - base, HT_ALLOC); /* Rarely, identifiers require diagnostics when lexed. */ if (__builtin_expect ((result->flags & NODE_DIAGNOSTIC) && !pfile->state.skipping, 0)) { /* It is allowed to poison the same identifier twice. */ if ((result->flags & NODE_POISONED) && !pfile->state.poisoned_ok) cpp_error (pfile, CPP_DL_ERROR, "attempt to use poisoned \"%s\"", NODE_NAME (result)); /* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the replacement list of a variadic macro. */ if (result == pfile->spec_nodes.n__VA_ARGS__ && !pfile->state.va_args_ok) cpp_error (pfile, CPP_DL_PEDWARN, "__VA_ARGS__ can only appear in the expansion" " of a C99 variadic macro"); } return result; }
static void sanity_checks (cpp_reader *pfile) { cppchar_t test = 0; size_t max_precision = 2 * CHAR_BIT * sizeof (cpp_num_part); /* Sanity checks for assumptions about CPP arithmetic and target type precisions made by cpplib. */ test--; if (test < 1) cpp_error (pfile, CPP_DL_ICE, "cppchar_t must be an unsigned type"); if (CPP_OPTION (pfile, precision) > max_precision) cpp_error (pfile, CPP_DL_ICE, "preprocessor arithmetic has maximum precision of %lu bits;" " target requires %lu bits", (unsigned long) max_precision, (unsigned long) CPP_OPTION (pfile, precision)); if (CPP_OPTION (pfile, precision) < CPP_OPTION (pfile, int_precision)) cpp_error (pfile, CPP_DL_ICE, "CPP arithmetic must be at least as precise as a target int"); if (CPP_OPTION (pfile, char_precision) < 8) cpp_error (pfile, CPP_DL_ICE, "target char is less than 8 bits wide"); if (CPP_OPTION (pfile, wchar_precision) < CPP_OPTION (pfile, char_precision)) cpp_error (pfile, CPP_DL_ICE, "target wchar_t is narrower than target char"); if (CPP_OPTION (pfile, int_precision) < CPP_OPTION (pfile, char_precision)) cpp_error (pfile, CPP_DL_ICE, "target int is narrower than target char"); /* This is assumed in eval_token() and could be fixed if necessary. */ if (sizeof (cppchar_t) > sizeof (cpp_num_part)) cpp_error (pfile, CPP_DL_ICE, "CPP half-integer narrower than CPP character"); if (CPP_OPTION (pfile, wchar_precision) > BITS_PER_CPPCHAR_T) cpp_error (pfile, CPP_DL_ICE, "CPP on this host cannot handle wide character constants over" " %lu bits, but the target requires %lu bits", (unsigned long) BITS_PER_CPPCHAR_T, (unsigned long) CPP_OPTION (pfile, wchar_precision)); }
/* Lexes a string, character constant, or angle-bracketed header file name. The stored string contains the spelling, including opening quote and leading any leading 'L'. It returns the type of the literal, or CPP_OTHER if it was not properly terminated. The spelling is NUL-terminated, but it is not guaranteed that this is the first NUL since embedded NULs are preserved. */ static void lex_string (cpp_reader *pfile, cpp_token *token, const uchar *base) { bool saw_NUL = false; const uchar *cur; cppchar_t terminator; enum cpp_ttype type; cur = base; terminator = *cur++; if (terminator == 'L') terminator = *cur++; if (terminator == '\"') type = *base == 'L' ? CPP_WSTRING: CPP_STRING; else if (terminator == '\'') type = *base == 'L' ? CPP_WCHAR: CPP_CHAR; else terminator = '>', type = CPP_HEADER_NAME; for (;;) { cppchar_t c = *cur++; /* In #include-style directives, terminators are not escapable. */ if (c == '\\' && !pfile->state.angled_headers && *cur != '\n') cur++; else if (c == terminator) break; else if (c == '\n') { cur--; type = CPP_OTHER; break; } else if (c == '\0') saw_NUL = true; } if (saw_NUL && !pfile->state.skipping) cpp_error (pfile, CPP_DL_WARNING, "null character(s) preserved in literal"); pfile->buffer->cur = cur; create_literal (pfile, token, base, cur - base, type); }
/* Write the spelling of a token TOKEN to BUFFER. The buffer must already contain the enough space to hold the token's spelling. Returns a pointer to the character after the last character written. FIXME: Would be nice if we didn't need the PFILE argument. */ unsigned char * cpp_spell_token (cpp_reader *pfile, const cpp_token *token, unsigned char *buffer) { switch (TOKEN_SPELL (token)) { case SPELL_OPERATOR: { const unsigned char *spelling; unsigned char c; if (token->flags & DIGRAPH) spelling = digraph_spellings[(int) token->type - (int) CPP_FIRST_DIGRAPH]; else if (token->flags & NAMED_OP) goto spell_ident; else spelling = TOKEN_NAME (token); while ((c = *spelling++) != '\0') *buffer++ = c; } break; spell_ident: case SPELL_IDENT: memcpy (buffer, NODE_NAME (token->val.node), NODE_LEN (token->val.node)); buffer += NODE_LEN (token->val.node); break; case SPELL_LITERAL: memcpy (buffer, token->val.str.text, token->val.str.len); buffer += token->val.str.len; break; case SPELL_NONE: cpp_error (pfile, CPP_DL_ICE, "unspellable token %s", TOKEN_NAME (token)); break; } return buffer; }
/* SDCC specific sdcc_hash pragma */ static void do_pragma_sdcc_hash (cpp_reader *pfile) { const cpp_token *tok = _cpp_lex_token (pfile); if (tok->type == CPP_PLUS) { CPP_OPTION(pfile, allow_naked_hash)++; } else if (tok->type == CPP_MINUS) { CPP_OPTION(pfile, allow_naked_hash)--; } else { cpp_error (pfile, CPP_DL_ERROR, "invalid #pragma sdcc_hash directive, need '+' or '-'"); } }
/* SDCC specific pedantic_parse_number pragma */ static void do_pragma_pedantic_parse_number (cpp_reader *pfile) { const cpp_token *tok = _cpp_lex_token (pfile); if (tok->type == CPP_PLUS) { CPP_OPTION(pfile, pedantic_parse_number)++; } else if (tok->type == CPP_MINUS) { CPP_OPTION(pfile, pedantic_parse_number)--; } else { cpp_error (pfile, CPP_DL_ERROR, "invalid #pragma pedantic_parse_number directive, need '+' or '-'"); } }
/* SDCC _asm specific switch _asm block preprocessing on / off */ static void do_pragma_preproc_asm (cpp_reader *pfile) { const cpp_token *tok = _cpp_lex_token (pfile); if (tok->type == CPP_PLUS) { CPP_OPTION(pfile, preproc_asm)++; } else if (tok->type == CPP_MINUS) { CPP_OPTION(pfile, preproc_asm)--; } else { cpp_error (pfile, CPP_DL_ERROR, "invalid #pragma preproc_asm directive, need '+' or '-'"); } }
/* Returns TRUE if traditional macro recursion is detected. */ static bool recursive_macro (cpp_reader *pfile, cpp_hashnode *node) { bool recursing = !!(node->flags & NODE_DISABLED); /* Object-like macros that are already expanding are necessarily recursive. However, it is possible to have traditional function-like macros that are not infinitely recursive but recurse to any given depth. Further, it is easy to construct examples that get ever longer until the point they stop recursing. So there is no easy way to detect true recursion; instead we assume any expansion more than 20 deep since the first invocation of this macro must be recursing. */ if (recursing && node->value.macro->fun_like) { size_t depth = 0; cpp_context *context = pfile->context; do { depth++; if (context->macro == node && depth > 20) break; context = context->prev; } while (context); recursing = context != NULL; } if (recursing) cpp_error (pfile, CPP_DL_ERROR, "detected recursion whilst expanding macro \"%s\"", NODE_NAME (node)); return recursing; }
/* Read and record the parameters, if any, of a function-like macro definition. Destroys pfile->out.cur. Returns true on success, false on failure (syntax error or a duplicate parameter). On success, CUR (pfile->context) is just past the closing parenthesis. */ static bool scan_parameters (cpp_reader *pfile, cpp_macro *macro) { const uchar *cur = CUR (pfile->context) + 1; bool ok; for (;;) { cur = skip_whitespace (pfile, cur, true /* skip_comments */); if (is_idstart (*cur)) { ok = false; if (_cpp_save_parameter (pfile, macro, lex_identifier (pfile, cur))) break; cur = skip_whitespace (pfile, CUR (pfile->context), true /* skip_comments */); if (*cur == ',') { cur++; continue; } ok = (*cur == ')'); break; } ok = (*cur == ')' && macro->paramc == 0); break; } if (!ok) cpp_error (pfile, CPP_DL_ERROR, "syntax error in macro parameter list"); CUR (pfile->context) = cur + (*cur == ')'); return ok; }
bool cpp_errno (cpp_reader *pfile, int level, const char *msgid) { return cpp_error (pfile, level, "%s: %s", _(msgid), xstrerror (errno)); }
/* Lex a token into pfile->cur_token, which is also incremented, to get diagnostics pointing to the correct location. Does not handle issues such as token lookahead, multiple-include optimization, directives, skipping etc. This function is only suitable for use by _cpp_lex_token, and in special cases like lex_expansion_token which doesn't care for any of these issues. When meeting a newline, returns CPP_EOF if parsing a directive, otherwise returns to the start of the token buffer if permissible. Returns the location of the lexed token. */ cpp_token * _cpp_lex_direct (cpp_reader *pfile) { cppchar_t c; cpp_buffer *buffer; const unsigned char *comment_start; cpp_token *result = pfile->cur_token++; fresh_line: result->flags = 0; buffer = pfile->buffer; if (buffer->need_line) { if (!_cpp_get_fresh_line (pfile)) { result->type = CPP_EOF; if (!pfile->state.in_directive) { /* Tell the compiler the line number of the EOF token. */ result->line = pfile->line; result->flags = BOL; } return result; } if (!pfile->keep_tokens) { pfile->cur_run = &pfile->base_run; result = pfile->base_run.base; pfile->cur_token = result + 1; } result->flags = BOL; if (pfile->state.parsing_args == 2) result->flags |= PREV_WHITE; } buffer = pfile->buffer; update_tokens_line: result->line = pfile->line; skipped_white: if (buffer->cur >= buffer->notes[buffer->cur_note].pos && !pfile->overlaid_buffer) { _cpp_process_line_notes (pfile, false); result->line = pfile->line; } c = *buffer->cur++; result->col = CPP_BUF_COLUMN (buffer, buffer->cur); switch (c) { case ' ': case '\t': case '\f': case '\v': case '\0': result->flags |= PREV_WHITE; skip_whitespace (pfile, c); goto skipped_white; case '\n': pfile->line++; buffer->need_line = true; goto fresh_line; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': result->type = CPP_NUMBER; lex_number (pfile, &result->val.str); break; case 'L': /* 'L' may introduce wide characters or strings. */ if (*buffer->cur == '\'' || *buffer->cur == '"') { lex_string (pfile, result, buffer->cur - 1); break; } /* Fall through. */ case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': result->type = CPP_NAME; result->val.node = lex_identifier (pfile, buffer->cur - 1); /* Convert named operators to their proper types. */ if (result->val.node->flags & NODE_OPERATOR) { result->flags |= NAMED_OP; result->type = result->val.node->directive_index; } break; case '\'': case '"': lex_string (pfile, result, buffer->cur - 1); break; case '/': /* A potential block or line comment. */ comment_start = buffer->cur; c = *buffer->cur; if (c == '*') { if (_cpp_skip_block_comment (pfile)) cpp_error (pfile, CPP_DL_ERROR, "unterminated comment"); } else if (c == '/' && (CPP_OPTION (pfile, cplusplus_comments) || CPP_IN_SYSTEM_HEADER (pfile))) { /* Warn about comments only if pedantically GNUC89, and not in system headers. */ if (CPP_OPTION (pfile, lang) == CLK_GNUC89 && CPP_PEDANTIC (pfile) && ! buffer->warned_cplusplus_comments) { cpp_error (pfile, CPP_DL_PEDWARN, "C++ style comments are not allowed in ISO C90"); cpp_error (pfile, CPP_DL_PEDWARN, "(this will be reported only once per input file)"); buffer->warned_cplusplus_comments = 1; } if (skip_line_comment (pfile) && CPP_OPTION (pfile, warn_comments)) cpp_error (pfile, CPP_DL_WARNING, "multi-line comment"); } else if (c == '=') { buffer->cur++; result->type = CPP_DIV_EQ; break; } else { result->type = CPP_DIV; break; } if (!pfile->state.save_comments) { result->flags |= PREV_WHITE; goto update_tokens_line; } /* Save the comment as a token in its own right. */ save_comment (pfile, result, comment_start, c); break; case '<': if (pfile->state.angled_headers) { lex_string (pfile, result, buffer->cur - 1); break; } result->type = CPP_LESS; if (*buffer->cur == '=') buffer->cur++, result->type = CPP_LESS_EQ; else if (*buffer->cur == '<') { buffer->cur++; IF_NEXT_IS ('=', CPP_LSHIFT_EQ, CPP_LSHIFT); } else if (*buffer->cur == '?' && CPP_OPTION (pfile, cplusplus)) { buffer->cur++; IF_NEXT_IS ('=', CPP_MIN_EQ, CPP_MIN); } else if (CPP_OPTION (pfile, digraphs)) { if (*buffer->cur == ':') { buffer->cur++; result->flags |= DIGRAPH; result->type = CPP_OPEN_SQUARE; } else if (*buffer->cur == '%') { buffer->cur++; result->flags |= DIGRAPH; result->type = CPP_OPEN_BRACE; } } break; case '>': result->type = CPP_GREATER; if (*buffer->cur == '=') buffer->cur++, result->type = CPP_GREATER_EQ; else if (*buffer->cur == '>') { buffer->cur++; IF_NEXT_IS ('=', CPP_RSHIFT_EQ, CPP_RSHIFT); } else if (*buffer->cur == '?' && CPP_OPTION (pfile, cplusplus)) { buffer->cur++; IF_NEXT_IS ('=', CPP_MAX_EQ, CPP_MAX); } break; case '%': result->type = CPP_MOD; if (*buffer->cur == '=') buffer->cur++, result->type = CPP_MOD_EQ; else if (CPP_OPTION (pfile, digraphs)) { if (*buffer->cur == ':') { buffer->cur++; result->flags |= DIGRAPH; result->type = CPP_HASH; if (*buffer->cur == '%' && buffer->cur[1] == ':') buffer->cur += 2, result->type = CPP_PASTE; } else if (*buffer->cur == '>') { buffer->cur++; result->flags |= DIGRAPH; result->type = CPP_CLOSE_BRACE; } } break; case '.': result->type = CPP_DOT; if (ISDIGIT (*buffer->cur)) { result->type = CPP_NUMBER; lex_number (pfile, &result->val.str); } else if (*buffer->cur == '.' && buffer->cur[1] == '.') buffer->cur += 2, result->type = CPP_ELLIPSIS; else if (*buffer->cur == '*' && CPP_OPTION (pfile, cplusplus)) buffer->cur++, result->type = CPP_DOT_STAR; break; case '+': result->type = CPP_PLUS; if (*buffer->cur == '+') buffer->cur++, result->type = CPP_PLUS_PLUS; else if (*buffer->cur == '=') buffer->cur++, result->type = CPP_PLUS_EQ; break; case '-': result->type = CPP_MINUS; if (*buffer->cur == '>') { buffer->cur++; result->type = CPP_DEREF; if (*buffer->cur == '*' && CPP_OPTION (pfile, cplusplus)) buffer->cur++, result->type = CPP_DEREF_STAR; } else if (*buffer->cur == '-') buffer->cur++, result->type = CPP_MINUS_MINUS; else if (*buffer->cur == '=') buffer->cur++, result->type = CPP_MINUS_EQ; break; case '&': result->type = CPP_AND; if (*buffer->cur == '&') buffer->cur++, result->type = CPP_AND_AND; else if (*buffer->cur == '=') buffer->cur++, result->type = CPP_AND_EQ; break; case '|': result->type = CPP_OR; if (*buffer->cur == '|') buffer->cur++, result->type = CPP_OR_OR; else if (*buffer->cur == '=') buffer->cur++, result->type = CPP_OR_EQ; break; case ':': result->type = CPP_COLON; if (*buffer->cur == ':' && CPP_OPTION (pfile, cplusplus)) buffer->cur++, result->type = CPP_SCOPE; else if (*buffer->cur == '>' && CPP_OPTION (pfile, digraphs)) { buffer->cur++; result->flags |= DIGRAPH; result->type = CPP_CLOSE_SQUARE; } break; case '*': IF_NEXT_IS ('=', CPP_MULT_EQ, CPP_MULT); break; case '=': IF_NEXT_IS ('=', CPP_EQ_EQ, CPP_EQ); break; case '!': IF_NEXT_IS ('=', CPP_NOT_EQ, CPP_NOT); break; case '^': IF_NEXT_IS ('=', CPP_XOR_EQ, CPP_XOR); break; case '#': IF_NEXT_IS ('#', CPP_PASTE, CPP_HASH); break; case '?': result->type = CPP_QUERY; break; case '~': result->type = CPP_COMPL; break; case ',': result->type = CPP_COMMA; break; case '(': result->type = CPP_OPEN_PAREN; break; case ')': result->type = CPP_CLOSE_PAREN; break; case '[': result->type = CPP_OPEN_SQUARE; break; case ']': result->type = CPP_CLOSE_SQUARE; break; case '{': result->type = CPP_OPEN_BRACE; break; case '}': result->type = CPP_CLOSE_BRACE; break; case ';': result->type = CPP_SEMICOLON; break; /* @ is a punctuator in Objective-C. */ case '@': result->type = CPP_ATSIGN; break; case '$': case '\\': { const uchar *base = --buffer->cur; if (forms_identifier_p (pfile, true)) { result->type = CPP_NAME; result->val.node = lex_identifier (pfile, base); break; } buffer->cur++; } default: create_literal (pfile, result, buffer->cur - 1, 1, CPP_OTHER); break; } return result; }
int c_common_valid_pch (cpp_reader *pfile, const char *name, int fd) { int sizeread; int result; char ident[IDENT_LENGTH + 16]; const char *pch_ident; struct c_pch_validity v; /* Perform a quick test of whether this is a valid precompiled header for the current language. */ gcc_assert (memcmp (executable_checksum, no_checksum, 16) != 0); sizeread = read (fd, ident, IDENT_LENGTH + 16); if (sizeread == -1) fatal_error ("can%'t read %s: %m", name); else if (sizeread != IDENT_LENGTH + 16) { if (cpp_get_options (pfile)->warn_invalid_pch) cpp_error (pfile, CPP_DL_WARNING, "%s: too short to be a PCH file", name); return 2; } pch_ident = get_ident(); if (memcmp (ident, pch_ident, IDENT_LENGTH) != 0) { if (cpp_get_options (pfile)->warn_invalid_pch) { if (memcmp (ident, pch_ident, 5) == 0) /* It's a PCH, for the right language, but has the wrong version. */ cpp_error (pfile, CPP_DL_WARNING, "%s: not compatible with this GCC version", name); else if (memcmp (ident, pch_ident, 4) == 0) /* It's a PCH for the wrong language. */ cpp_error (pfile, CPP_DL_WARNING, "%s: not for %s", name, lang_hooks.name); else /* Not any kind of PCH. */ cpp_error (pfile, CPP_DL_WARNING, "%s: not a PCH file", name); } return 2; } if (memcmp (ident + IDENT_LENGTH, executable_checksum, 16) != 0) { if (cpp_get_options (pfile)->warn_invalid_pch) cpp_error (pfile, CPP_DL_WARNING, "%s: created by a different GCC executable", name); return 2; } /* At this point, we know it's a PCH file created by this executable, so it ought to be long enough that we can read a c_pch_validity structure. */ if (read (fd, &v, sizeof (v)) != sizeof (v)) fatal_error ("can%'t read %s: %m", name); /* The allowable debug info combinations are that either the PCH file was built with the same as is being used now, or the PCH file was built for some kind of debug info but now none is in use. */ if (v.debug_info_type != write_symbols && write_symbols != NO_DEBUG) { if (cpp_get_options (pfile)->warn_invalid_pch) cpp_error (pfile, CPP_DL_WARNING, "%s: created with -g%s, but used with -g%s", name, debug_type_names[v.debug_info_type], debug_type_names[write_symbols]); return 2; } /* Check flags that must match exactly. */ { size_t i; for (i = 0; i < MATCH_SIZE; i++) if (*pch_matching[i].flag_var != v.match[i]) { if (cpp_get_options (pfile)->warn_invalid_pch) cpp_error (pfile, CPP_DL_WARNING, "%s: settings for %s do not match", name, pch_matching[i].flag_name); return 2; } } /* If the text segment was not loaded at the same address as it was when the PCH file was created, function pointers loaded from the PCH will not be valid. We could in theory remap all the function pointers, but no support for that exists at present. Since we have the same executable, it should only be necessary to check one function. */ if (v.pch_init != &pch_init) { if (cpp_get_options (pfile)->warn_invalid_pch) cpp_error (pfile, CPP_DL_WARNING, "%s: had text segment at different address", name); return 2; } /* Check the target-specific validity data. */ { void *this_file_data = xmalloc (v.target_data_length); const char *msg; if ((size_t) read (fd, this_file_data, v.target_data_length) != v.target_data_length) fatal_error ("can%'t read %s: %m", name); msg = targetm.pch_valid_p (this_file_data, v.target_data_length); free (this_file_data); if (msg != NULL) { if (cpp_get_options (pfile)->warn_invalid_pch) cpp_error (pfile, CPP_DL_WARNING, "%s: %s", name, msg); return 2; } } /* Check the preprocessor macros are the same as when the PCH was generated. */ result = cpp_valid_state (pfile, name, fd); if (result == -1) return 2; else return result == 0; }