/* Part of CPP library. (Macro and #define handling.) Copyright (C) 1986-2026 Free Software Foundation, Inc. Written by Per Bothner, 1994. Based on CCCP program by Paul Rubin, June 1986 Adapted to ANSI C, Richard Stallman, Jan 1987 This program is free software; you can redistribute it and/or modify itunder the terms of the GNU General Public License as published by theFree Software Foundation; either version 3, or (at your option) anylater version. This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details. You should have received a copy of the GNU General Public Licensealong with this program; see the file COPYING3. If not see<http://www.gnu.org/licenses/>. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ #include "config.h"#include "system.h"#include "cpplib.h"#include "internal.h" typedef struct macro_arg macro_arg;/* This structure represents the tokens of a macro argument. These tokens can be macro themselves, in which case they can be either expanded or unexpanded. When they are expanded, this data structure keeps both the expanded and unexpanded forms. */struct macro_arg{ const cpp_token **first; /* First token in unexpanded argument. */ const cpp_token **expanded; /* Macro-expanded argument. */ const cpp_token *stringified; /* Stringified argument. */ unsigned int count; /* # of tokens in argument. */ unsigned int expanded_count; /* # of tokens in expanded argument. */ location_t *virt_locs; /* Where virtual locations for unexpanded tokens are stored. */ location_t *expanded_virt_locs; /* Where virtual locations for expanded tokens are stored. */}; /* The kind of macro tokens which the instance of macro_arg_token_iter is supposed to iterate over. */enum macro_arg_token_kind { MACRO_ARG_TOKEN_NORMAL, /* This is a macro argument token that got transformed into a string literal, e.g. #foo. */ MACRO_ARG_TOKEN_STRINGIFIED, /* This is a token resulting from the expansion of a macro argument that was itself a macro. */ MACRO_ARG_TOKEN_EXPANDED}; /* An iterator over tokens coming from a function-like macro argument. */typedef struct macro_arg_token_iter macro_arg_token_iter;struct macro_arg_token_iter{ /* Whether or not -ftrack-macro-expansion is used. */ bool track_macro_exp_p; /* The kind of token over which we are supposed to iterate. */ enum macro_arg_token_kind kind; /* A pointer to the current token pointed to by the iterator. */ const cpp_token **token_ptr; /* A pointer to the "full" location of the current token. If -ftrack-macro-expansion is used this location tracks loci across macro expansion. */ const location_t *location_ptr;#if CHECKING_P /* The number of times the iterator went forward. This useful only when checking is enabled. */ size_t num_forwards;#endif}; /* Saved data about an identifier being used as a macro argument name. */struct macro_arg_saved_data { /* The canonical (UTF-8) spelling of this identifier. */ cpp_hashnode *canonical_node; /* The previous value & type of this identifier. */ union _cpp_hashnode_value value; node_type type;}; static const char *vaopt_paste_error = N_("'##' cannot appear at either end of __VA_OPT__"); static void expand_arg (cpp_reader *, macro_arg *); /* A class for tracking __VA_OPT__ state while iterating over a sequence of tokens. This is used during both macro definition and expansion. */class vaopt_state { public: enum update_type { ERROR, DROP, INCLUDE, BEGIN, END }; /* Initialize the state tracker. ANY_ARGS is true if variable arguments were provided to the macro invocation. */ vaopt_state (cpp_reader *pfile, bool is_variadic, macro_arg *arg) : m_pfile (pfile), m_arg (arg), m_variadic (is_variadic), m_last_was_paste (false), m_stringify (false), m_state (0), m_paste_location (0), m_location (0), m_update (ERROR) { } /* Given a token, update the state of this tracker and return a boolean indicating whether the token should be be included in the expansion. */ update_type update (const cpp_token *token) { /* If the macro isn't variadic, just don't bother. */ if (!m_variadic) return INCLUDE; if (token->type == CPP_NAME && token->val.node.node == m_pfile->spec_nodes.n__VA_OPT__) { if (m_state > 0) { cpp_error_at (m_pfile, CPP_DL_ERROR, token->src_loc, "%<__VA_OPT__%> may not appear in a %<__VA_OPT__%>"); return ERROR; } ++m_state; m_location = token->src_loc; m_stringify = (token->flags & STRINGIFY_ARG) != 0; return BEGIN; } else if (m_state == 1) { if (token->type != CPP_OPEN_PAREN) { cpp_error_at (m_pfile, CPP_DL_ERROR, m_location, "%<__VA_OPT__%> must be followed by an " "open parenthesis"); return ERROR; } ++m_state; if (m_update == ERROR) { if (m_arg == NULL) m_update = INCLUDE; else { m_update = DROP; if (!m_arg->expanded) expand_arg (m_pfile, m_arg); for (unsigned idx = 0; idx < m_arg->expanded_count; ++idx) if (m_arg->expanded[idx]->type != CPP_PADDING) { m_update = INCLUDE; break; } } } return DROP; } else if (m_state >= 2) { if (m_state == 2 && token->type == CPP_PASTE) { cpp_error_at (m_pfile, CPP_DL_ERROR, token->src_loc, vaopt_paste_error); return ERROR; } /* Advance states before further considering this token, in case we see a close paren immediately after the open paren. */ if (m_state == 2) ++m_state; bool was_paste = m_last_was_paste; m_last_was_paste = false; if (token->type == CPP_PASTE) { m_last_was_paste = true; m_paste_location = token->src_loc; } else if (token->type == CPP_OPEN_PAREN) ++m_state; else if (token->type == CPP_CLOSE_PAREN) { --m_state; if (m_state == 2) { /* Saw the final paren. */ m_state = 0; if (was_paste) { cpp_error_at (m_pfile, CPP_DL_ERROR, token->src_loc, vaopt_paste_error); return ERROR; } return END; } } return m_update; } /* Nothing to do with __VA_OPT__. */ return INCLUDE; } /* Ensure that any __VA_OPT__ was completed. If ok, return true. Otherwise, issue an error and return false. */ bool completed () { if (m_variadic && m_state != 0) cpp_error_at (m_pfile, CPP_DL_ERROR, m_location, "unterminated %<__VA_OPT__%>"); return m_state == 0; } /* Return true for # __VA_OPT__. */ bool stringify () const { return m_stringify; } private: /* The cpp_reader. */ cpp_reader *m_pfile; /* The __VA_ARGS__ argument. */ macro_arg *m_arg; /* True if the macro is variadic. */ bool m_variadic; /* If true, the previous token was ##. This is used to detect when a paste occurs at the end of the sequence. */ bool m_last_was_paste; /* True for #__VA_OPT__. */ bool m_stringify; /* The state variable: 0 means not parsing 1 means __VA_OPT__ seen, looking for "(" 2 means "(" seen (so the next token can't be "##") >= 3 means looking for ")", the number encodes the paren depth. */ int m_state; /* The location of the paste token. */ location_t m_paste_location; /* Location of the __VA_OPT__ token. */ location_t m_location; /* If __VA_ARGS__ substitutes to no preprocessing tokens, INCLUDE, otherwise DROP. ERROR when unknown yet. */ update_type m_update;}; /* Macro expansion. */ static cpp_macro *get_deferred_or_lazy_macro (cpp_reader *, cpp_hashnode *, location_t);static int enter_macro_context (cpp_reader *, cpp_hashnode *, const cpp_token *, location_t);static int builtin_macro (cpp_reader *, cpp_hashnode *, location_t, location_t);static void push_ptoken_context (cpp_reader *, cpp_hashnode *, _cpp_buff *, const cpp_token **, unsigned int);static void push_extended_tokens_context (cpp_reader *, cpp_hashnode *, _cpp_buff *, location_t *, const cpp_token **, unsigned int);static _cpp_buff *collect_args (cpp_reader *, const cpp_hashnode *, _cpp_buff **, unsigned *);static cpp_context *next_context (cpp_reader *);static const cpp_token *padding_token (cpp_reader *, const cpp_token *);static const cpp_token *new_string_token (cpp_reader *, uchar *, unsigned int);static const cpp_token *stringify_arg (cpp_reader *, const cpp_token **, unsigned int);static void paste_all_tokens (cpp_reader *, const cpp_token *);static bool paste_tokens (cpp_reader *, location_t, const cpp_token **, const cpp_token *);static void alloc_expanded_arg_mem (cpp_reader *, macro_arg *, size_t);static void ensure_expanded_arg_room (cpp_reader *, macro_arg *, size_t, size_t *);static void delete_macro_args (_cpp_buff*, unsigned num_args);static void set_arg_token (macro_arg *, const cpp_token *, location_t, size_t, enum macro_arg_token_kind, bool);static const location_t *get_arg_token_location (const macro_arg *, enum macro_arg_token_kind);static const cpp_token **arg_token_ptr_at (const macro_arg *, size_t, enum macro_arg_token_kind, location_t **virt_location); static void macro_arg_token_iter_init (macro_arg_token_iter *, bool, enum macro_arg_token_kind, const macro_arg *, const cpp_token **);static const cpp_token *macro_arg_token_iter_get_token(const macro_arg_token_iter *it);static location_t macro_arg_token_iter_get_location(const macro_arg_token_iter *);static void macro_arg_token_iter_forward (macro_arg_token_iter *);static _cpp_buff *tokens_buff_new (cpp_reader *, size_t, location_t **);static size_t tokens_buff_count (_cpp_buff *);static const cpp_token **tokens_buff_last_token_ptr (_cpp_buff *);static inline const cpp_token **tokens_buff_put_token_to (const cpp_token **, location_t *, const cpp_token *, location_t, location_t, const line_map_macro *, unsigned int); static const cpp_token **tokens_buff_add_token (_cpp_buff *, location_t *, const cpp_token *, location_t, location_t, const line_map_macro *, unsigned int);static inline void tokens_buff_remove_last_token (_cpp_buff *);static void replace_args (cpp_reader *, cpp_hashnode *, cpp_macro *, macro_arg *, location_t);static _cpp_buff *funlike_invocation_p (cpp_reader *, cpp_hashnode *, _cpp_buff **, unsigned *);static cpp_macro *create_iso_definition (cpp_reader *); /* #define directive parsing and handling. */ static cpp_macro *lex_expansion_token (cpp_reader *, cpp_macro *);static bool parse_params (cpp_reader *, unsigned *, bool *);static void check_trad_stringification (cpp_reader *, const cpp_macro *, const cpp_string *);static bool reached_end_of_context (cpp_context *);static void consume_next_token_from_context (cpp_reader *pfile, const cpp_token **, location_t *);static const cpp_token* cpp_get_token_1 (cpp_reader *, location_t *); static cpp_hashnode* macro_of_context (cpp_context *context); /* Statistical counter tracking the number of macros that got expanded. */line_map_uint_t num_expanded_macros_counter = 0;/* Statistical counter tracking the total number tokens resulting from macro expansion. */line_map_uint_t num_macro_tokens_counter = 0; /* Wrapper around cpp_get_token to skip CPP_PADDING tokens and not consume CPP_EOF. */const cpp_token *_cpp_get_token_no_padding (cpp_reader *pfile){ for (;;) { const cpp_token *ret = cpp_peek_token (pfile, 0); if (ret->type == CPP_EOF) return ret; ret = cpp_get_token (pfile); if (ret->type != CPP_PADDING) return ret; }} /* Helper function for builtin_has_include and builtin_has_embed. */ static char *builtin_has_include_1 (cpp_reader *pfile, const char *name, bool *paren, bool *bracket, location_t *loc){ if (!pfile->state.in_directive) cpp_error (pfile, CPP_DL_ERROR, "%qs used outside of preprocessing directive", name); pfile->state.angled_headers = true; const auto sav_padding = pfile->state.directive_wants_padding; pfile->state.directive_wants_padding = true; const cpp_token *token = _cpp_get_token_no_padding (pfile); *paren = token->type == CPP_OPEN_PAREN; if (*paren) token = _cpp_get_token_no_padding (pfile); else cpp_error (pfile, CPP_DL_ERROR, "missing %<(%> before %qs operand", name); pfile->state.angled_headers = false; pfile->state.directive_wants_padding = sav_padding; if (loc) *loc = token->src_loc; *bracket = token->type != CPP_STRING; char *fname = NULL; if (token->type == CPP_STRING || token->type == CPP_HEADER_NAME) { fname = XNEWVEC (char, token->val.str.len - 1); memcpy (fname, token->val.str.text + 1, token->val.str.len - 2); fname[token->val.str.len - 2] = '\0'; } else if (token->type == CPP_LESS) fname = _cpp_bracket_include (pfile); else cpp_error (pfile, CPP_DL_ERROR, "operator %qs requires a header-name", name); return fname;} /* Handle meeting "__has_include" builtin macro. */ static intbuiltin_has_include (cpp_reader *pfile, cpp_hashnode *op, bool has_next){ int result = 0; bool paren, bracket; char *fname = builtin_has_include_1 (pfile, (const char *) NODE_NAME (op), &paren, &bracket, NULL); if (fname) { /* Do not do the lookup if we're skipping, that's unnecessary IO. */ if (!pfile->state.skip_eval && _cpp_has_header (pfile, fname, bracket, has_next ? IT_INCLUDE_NEXT : IT_INCLUDE)) result = 1; XDELETEVEC (fname); } if (paren && _cpp_get_token_no_padding (pfile)->type != CPP_CLOSE_PAREN) cpp_error (pfile, CPP_DL_ERROR, "missing %<)%> after %qs operand", NODE_NAME (op)); return result;} /* Handle the "__has_embed" expression. */ static intbuiltin_has_embed (cpp_reader *pfile){ int result = 0; bool paren, bracket; struct cpp_embed_params params = {}; char *fname = builtin_has_include_1 (pfile, "__has_embed", &paren, &bracket, ¶ms.loc); if (fname) { params.has_embed = true; auto save_in_directive = pfile->state.in_directive; auto save_angled_headers = pfile->state.angled_headers; auto save_directive_wants_padding = pfile->state.directive_wants_padding; auto save_op_stack = pfile->op_stack; auto save_op_limit = pfile->op_limit; auto save_skip_eval = pfile->state.skip_eval; auto save_mi_ind_cmacro = pfile->mi_ind_cmacro; /* Tell the lexer this is an embed directive. */ pfile->state.in_directive = 3; pfile->state.angled_headers = false; pfile->state.directive_wants_padding = false; pfile->op_stack = NULL; pfile->op_limit = NULL; bool ok = _cpp_parse_embed_params (pfile, ¶ms); free (pfile->op_stack); pfile->state.in_directive = save_in_directive; pfile->state.angled_headers = save_angled_headers; pfile->state.directive_wants_padding = save_directive_wants_padding; pfile->op_stack = save_op_stack; pfile->op_limit = save_op_limit; pfile->state.skip_eval = save_skip_eval; pfile->mi_ind_cmacro = save_mi_ind_cmacro; if (!*fname) { cpp_error_with_line (pfile, CPP_DL_ERROR, params.loc, 0, "empty filename in %qs", "__has_embed"); ok = false;Lines 1–500 of 4284. Load more
/* Part of CPP library. (Macro and #define handling.) Copyright (C) 1986-2026 Free Software Foundation, Inc. Written by Per Bothner, 1994. Based on CCCP program by Paul Rubin, June 1986 Adapted to ANSI C, Richard Stallman, Jan 1987 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ #include "config.h" #include "system.h" #include "cpplib.h" #include "internal.h" typedef struct macro_arg macro_arg; /* This structure represents the tokens of a macro argument. These tokens can be macro themselves, in which case they can be either expanded or unexpanded. When they are expanded, this data structure keeps both the expanded and unexpanded forms. */ struct macro_arg { const cpp_token **first; /* First token in unexpanded argument. */ const cpp_token **expanded; /* Macro-expanded argument. */ const cpp_token *stringified; /* Stringified argument. */ unsigned int count; /* # of tokens in argument. */ unsigned int expanded_count; /* # of tokens in expanded argument. */ location_t *virt_locs; /* Where virtual locations for unexpanded tokens are stored. */ location_t *expanded_virt_locs; /* Where virtual locations for expanded tokens are stored. */ }; /* The kind of macro tokens which the instance of macro_arg_token_iter is supposed to iterate over. */ enum macro_arg_token_kind { MACRO_ARG_TOKEN_NORMAL, /* This is a macro argument token that got transformed into a string literal, e.g. #foo. */ MACRO_ARG_TOKEN_STRINGIFIED, /* This is a token resulting from the expansion of a macro argument that was itself a macro. */ MACRO_ARG_TOKEN_EXPANDED }; /* An iterator over tokens coming from a function-like macro argument. */ typedef struct macro_arg_token_iter macro_arg_token_iter; struct macro_arg_token_iter { /* Whether or not -ftrack-macro-expansion is used. */ bool track_macro_exp_p; /* The kind of token over which we are supposed to iterate. */ enum macro_arg_token_kind kind; /* A pointer to the current token pointed to by the iterator. */ const cpp_token **token_ptr; /* A pointer to the "full" location of the current token. If -ftrack-macro-expansion is used this location tracks loci across macro expansion. */ const location_t *location_ptr; #if CHECKING_P /* The number of times the iterator went forward. This useful only when checking is enabled. */ size_t num_forwards; #endif }; /* Saved data about an identifier being used as a macro argument name. */ struct macro_arg_saved_data { /* The canonical (UTF-8) spelling of this identifier. */ cpp_hashnode *canonical_node; /* The previous value & type of this identifier. */ union _cpp_hashnode_value value; node_type type; }; static const char *vaopt_paste_error = N_("'##' cannot appear at either end of __VA_OPT__"); static void expand_arg (cpp_reader *, macro_arg *); /* A class for tracking __VA_OPT__ state while iterating over a sequence of tokens. This is used during both macro definition and expansion. */ class vaopt_state { public: enum update_type { ERROR, DROP, INCLUDE, BEGIN, END }; /* Initialize the state tracker. ANY_ARGS is true if variable arguments were provided to the macro invocation. */ vaopt_state (cpp_reader *pfile, bool is_variadic, macro_arg *arg) : m_pfile (pfile), m_arg (arg), m_variadic (is_variadic), m_last_was_paste (false), m_stringify (false), m_state (0), m_paste_location (0), m_location (0), m_update (ERROR) { } /* Given a token, update the state of this tracker and return a boolean indicating whether the token should be be included in the expansion. */ update_type update (const cpp_token *token) { /* If the macro isn't variadic, just don't bother. */ if (!m_variadic) return INCLUDE; if (token->type == CPP_NAME && token->val.node.node == m_pfile->spec_nodes.n__VA_OPT__) { if (m_state > 0) { cpp_error_at (m_pfile, CPP_DL_ERROR, token->src_loc, "%<__VA_OPT__%> may not appear in a %<__VA_OPT__%>"); return ERROR; } ++m_state; m_location = token->src_loc; m_stringify = (token->flags & STRINGIFY_ARG) != 0; return BEGIN; } else if (m_state == 1) { if (token->type != CPP_OPEN_PAREN) { cpp_error_at (m_pfile, CPP_DL_ERROR, m_location, "%<__VA_OPT__%> must be followed by an " "open parenthesis"); return ERROR; } ++m_state; if (m_update == ERROR) { if (m_arg == NULL) m_update = INCLUDE; else { m_update = DROP; if (!m_arg->expanded) expand_arg (m_pfile, m_arg); for (unsigned idx = 0; idx < m_arg->expanded_count; ++idx) if (m_arg->expanded[idx]->type != CPP_PADDING) { m_update = INCLUDE; break; } } } return DROP; } else if (m_state >= 2) { if (m_state == 2 && token->type == CPP_PASTE) { cpp_error_at (m_pfile, CPP_DL_ERROR, token->src_loc, vaopt_paste_error); return ERROR; } /* Advance states before further considering this token, in case we see a close paren immediately after the open paren. */ if (m_state == 2) ++m_state; bool was_paste = m_last_was_paste; m_last_was_paste = false; if (token->type == CPP_PASTE) { m_last_was_paste = true; m_paste_location = token->src_loc; } else if (token->type == CPP_OPEN_PAREN) ++m_state; else if (token->type == CPP_CLOSE_PAREN) { --m_state; if (m_state == 2) { /* Saw the final paren. */ m_state = 0; if (was_paste) { cpp_error_at (m_pfile, CPP_DL_ERROR, token->src_loc, vaopt_paste_error); return ERROR; } return END; } } return m_update; } /* Nothing to do with __VA_OPT__. */ return INCLUDE; } /* Ensure that any __VA_OPT__ was completed. If ok, return true. Otherwise, issue an error and return false. */ bool completed () { if (m_variadic && m_state != 0) cpp_error_at (m_pfile, CPP_DL_ERROR, m_location, "unterminated %<__VA_OPT__%>"); return m_state == 0; } /* Return true for # __VA_OPT__. */ bool stringify () const { return m_stringify; } private: /* The cpp_reader. */ cpp_reader *m_pfile; /* The __VA_ARGS__ argument. */ macro_arg *m_arg; /* True if the macro is variadic. */ bool m_variadic; /* If true, the previous token was ##. This is used to detect when a paste occurs at the end of the sequence. */ bool m_last_was_paste; /* True for #__VA_OPT__. */ bool m_stringify; /* The state variable: 0 means not parsing 1 means __VA_OPT__ seen, looking for "(" 2 means "(" seen (so the next token can't be "##") >= 3 means looking for ")", the number encodes the paren depth. */ int m_state; /* The location of the paste token. */ location_t m_paste_location; /* Location of the __VA_OPT__ token. */ location_t m_location; /* If __VA_ARGS__ substitutes to no preprocessing tokens, INCLUDE, otherwise DROP. ERROR when unknown yet. */ update_type m_update; }; /* Macro expansion. */ static cpp_macro *get_deferred_or_lazy_macro (cpp_reader *, cpp_hashnode *, location_t); static int enter_macro_context (cpp_reader *, cpp_hashnode *, const cpp_token *, location_t); static int builtin_macro (cpp_reader *, cpp_hashnode *, location_t, location_t); static void push_ptoken_context (cpp_reader *, cpp_hashnode *, _cpp_buff *, const cpp_token **, unsigned int); static void push_extended_tokens_context (cpp_reader *, cpp_hashnode *, _cpp_buff *, location_t *, const cpp_token **, unsigned int); static _cpp_buff *collect_args (cpp_reader *, const cpp_hashnode *, _cpp_buff **, unsigned *); static cpp_context *next_context (cpp_reader *); static const cpp_token *padding_token (cpp_reader *, const cpp_token *); static const cpp_token *new_string_token (cpp_reader *, uchar *, unsigned int); static const cpp_token *stringify_arg (cpp_reader *, const cpp_token **, unsigned int); static void paste_all_tokens (cpp_reader *, const cpp_token *); static bool paste_tokens (cpp_reader *, location_t, const cpp_token **, const cpp_token *); static void alloc_expanded_arg_mem (cpp_reader *, macro_arg *, size_t); static void ensure_expanded_arg_room (cpp_reader *, macro_arg *, size_t, size_t *); static void delete_macro_args (_cpp_buff*, unsigned num_args); static void set_arg_token (macro_arg *, const cpp_token *, location_t, size_t, enum macro_arg_token_kind, bool); static const location_t *get_arg_token_location (const macro_arg *, enum macro_arg_token_kind); static const cpp_token **arg_token_ptr_at (const macro_arg *, size_t, enum macro_arg_token_kind, location_t **virt_location); static void macro_arg_token_iter_init (macro_arg_token_iter *, bool, enum macro_arg_token_kind, const macro_arg *, const cpp_token **); static const cpp_token *macro_arg_token_iter_get_token (const macro_arg_token_iter *it); static location_t macro_arg_token_iter_get_location (const macro_arg_token_iter *); static void macro_arg_token_iter_forward (macro_arg_token_iter *); static _cpp_buff *tokens_buff_new (cpp_reader *, size_t, location_t **); static size_t tokens_buff_count (_cpp_buff *); static const cpp_token **tokens_buff_last_token_ptr (_cpp_buff *); static inline const cpp_token **tokens_buff_put_token_to (const cpp_token **, location_t *, const cpp_token *, location_t, location_t, const line_map_macro *, unsigned int); static const cpp_token **tokens_buff_add_token (_cpp_buff *, location_t *, const cpp_token *, location_t, location_t, const line_map_macro *, unsigned int); static inline void tokens_buff_remove_last_token (_cpp_buff *); static void replace_args (cpp_reader *, cpp_hashnode *, cpp_macro *, macro_arg *, location_t); static _cpp_buff *funlike_invocation_p (cpp_reader *, cpp_hashnode *, _cpp_buff **, unsigned *); static cpp_macro *create_iso_definition (cpp_reader *); /* #define directive parsing and handling. */ static cpp_macro *lex_expansion_token (cpp_reader *, cpp_macro *); static bool parse_params (cpp_reader *, unsigned *, bool *); static void check_trad_stringification (cpp_reader *, const cpp_macro *, const cpp_string *); static bool reached_end_of_context (cpp_context *); static void consume_next_token_from_context (cpp_reader *pfile, const cpp_token **, location_t *); static const cpp_token* cpp_get_token_1 (cpp_reader *, location_t *); static cpp_hashnode* macro_of_context (cpp_context *context); /* Statistical counter tracking the number of macros that got expanded. */ line_map_uint_t num_expanded_macros_counter = 0; /* Statistical counter tracking the total number tokens resulting from macro expansion. */ line_map_uint_t num_macro_tokens_counter = 0; /* Wrapper around cpp_get_token to skip CPP_PADDING tokens and not consume CPP_EOF. */ const cpp_token * _cpp_get_token_no_padding (cpp_reader *pfile) { for (;;) { const cpp_token *ret = cpp_peek_token (pfile, 0); if (ret->type == CPP_EOF) return ret; ret = cpp_get_token (pfile); if (ret->type != CPP_PADDING) return ret; } } /* Helper function for builtin_has_include and builtin_has_embed. */ static char * builtin_has_include_1 (cpp_reader *pfile, const char *name, bool *paren, bool *bracket, location_t *loc) { if (!pfile->state.in_directive) cpp_error (pfile, CPP_DL_ERROR, "%qs used outside of preprocessing directive", name); pfile->state.angled_headers = true; const auto sav_padding = pfile->state.directive_wants_padding; pfile->state.directive_wants_padding = true; const cpp_token *token = _cpp_get_token_no_padding (pfile); *paren = token->type == CPP_OPEN_PAREN; if (*paren) token = _cpp_get_token_no_padding (pfile); else cpp_error (pfile, CPP_DL_ERROR, "missing %<(%> before %qs operand", name); pfile->state.angled_headers = false; pfile->state.directive_wants_padding = sav_padding; if (loc) *loc = token->src_loc; *bracket = token->type != CPP_STRING; char *fname = NULL; if (token->type == CPP_STRING || token->type == CPP_HEADER_NAME) { fname = XNEWVEC (char, token->val.str.len - 1); memcpy (fname, token->val.str.text + 1, token->val.str.len - 2); fname[token->val.str.len - 2] = '\0'; } else if (token->type == CPP_LESS) fname = _cpp_bracket_include (pfile); else cpp_error (pfile, CPP_DL_ERROR, "operator %qs requires a header-name", name); return fname; } /* Handle meeting "__has_include" builtin macro. */ static int builtin_has_include (cpp_reader *pfile, cpp_hashnode *op, bool has_next) { int result = 0; bool paren, bracket; char *fname = builtin_has_include_1 (pfile, (const char *) NODE_NAME (op), &paren, &bracket, NULL); if (fname) { /* Do not do the lookup if we're skipping, that's unnecessary IO. */ if (!pfile->state.skip_eval && _cpp_has_header (pfile, fname, bracket, has_next ? IT_INCLUDE_NEXT : IT_INCLUDE)) result = 1; XDELETEVEC (fname); } if (paren && _cpp_get_token_no_padding (pfile)->type != CPP_CLOSE_PAREN) cpp_error (pfile, CPP_DL_ERROR, "missing %<)%> after %qs operand", NODE_NAME (op)); return result; } /* Handle the "__has_embed" expression. */ static int builtin_has_embed (cpp_reader *pfile) { int result = 0; bool paren, bracket; struct cpp_embed_params params = {}; char *fname = builtin_has_include_1 (pfile, "__has_embed", &paren, &bracket, ¶ms.loc); if (fname) { params.has_embed = true; auto save_in_directive = pfile->state.in_directive; auto save_angled_headers = pfile->state.angled_headers; auto save_directive_wants_padding = pfile->state.directive_wants_padding; auto save_op_stack = pfile->op_stack; auto save_op_limit = pfile->op_limit; auto save_skip_eval = pfile->state.skip_eval; auto save_mi_ind_cmacro = pfile->mi_ind_cmacro; /* Tell the lexer this is an embed directive. */ pfile->state.in_directive = 3; pfile->state.angled_headers = false; pfile->state.directive_wants_padding = false; pfile->op_stack = NULL; pfile->op_limit = NULL; bool ok = _cpp_parse_embed_params (pfile, ¶ms); free (pfile->op_stack); pfile->state.in_directive = save_in_directive; pfile->state.angled_headers = save_angled_headers; pfile->state.directive_wants_padding = save_directive_wants_padding; pfile->op_stack = save_op_stack; pfile->op_limit = save_op_limit; pfile->state.skip_eval = save_skip_eval; pfile->mi_ind_cmacro = save_mi_ind_cmacro; if (!*fname) { cpp_error_with_line (pfile, CPP_DL_ERROR, params.loc, 0, "empty filename in %qs", "__has_embed"); ok = false;