Newer
Older
Copyright (C) 1986-2025 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"
/* 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. */
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
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
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
const location_t *location_ptr;
/* 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;
static const char *vaopt_paste_error =
N_("'##' cannot appear at either end of __VA_OPT__");
Jakub Jelinek
committed
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:
Jakub Jelinek
committed
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. */
Jakub Jelinek
committed
vaopt_state (cpp_reader *pfile, bool is_variadic, macro_arg *arg)
Jakub Jelinek
committed
m_arg (arg),
m_variadic (is_variadic),
m_last_was_paste (false),
Jakub Jelinek
committed
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;
}
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;
Jakub Jelinek
committed
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;
}
}
}
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
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;
}
Jakub Jelinek
committed
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 true for # __VA_OPT__. */
bool stringify () const
{
return m_stringify;
}
private:
/* The cpp_reader. */
cpp_reader *m_pfile;
Jakub Jelinek
committed
/* 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;
Jakub Jelinek
committed
/* If __VA_ARGS__ substitutes to no preprocessing tokens,
INCLUDE, otherwise DROP. ERROR when unknown yet. */
update_type m_update;
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);
Richard Henderson
committed
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 *,
static _cpp_buff *collect_args (cpp_reader *, const cpp_hashnode *,
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 **,
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 *,
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,
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 **,
const cpp_token *,
location_t,
location_t,
unsigned int);
static const cpp_token **tokens_buff_add_token (_cpp_buff *,
location_t,
location_t,
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 *,
static cpp_macro *create_iso_definition (cpp_reader *);
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);
}
&& _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;
}
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
/* 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;
}
/* Do not do the lookup if we're skipping, that's unnecessary
IO. */
if (ok && !pfile->state.skip_eval)
result = _cpp_stack_embed (pfile, fname, bracket, ¶ms);
_cpp_free_embed_params_tokens (¶ms.base64);
XDELETEVEC (fname);
}
else if (paren)
_cpp_get_token_no_padding (pfile);
return result;
}
/* Emits a warning if NODE is a macro defined in the main file that
has not been used. */
int
_cpp_warn_if_unused_macro (cpp_reader *pfile, cpp_hashnode *node,
void *v ATTRIBUTE_UNUSED)
{
cpp_macro *macro = node->value.macro;
if (!macro->used
&& MAIN_FILE_P (linemap_check_ordinary
(linemap_lookup (pfile->line_table,
macro->line))))
Simon Baldwin
committed
cpp_warning_with_line (pfile, CPP_W_UNUSED_MACROS, macro->line, 0,
"macro %qs is not used", NODE_NAME (node));
/* Allocates and returns a CPP_STRING token, containing TEXT of length
LEN, after null-terminating it. TEXT must be in permanent storage. */
static const cpp_token *
new_string_token (cpp_reader *pfile, unsigned char *text, unsigned int len)
cpp_token *token = _cpp_temp_token (pfile);
token->val.str.len = len;
token->val.str.text = text;
}
static const char * const monthnames[] =
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
/* Helper function for builtin_macro. Returns the text generated by
a builtin macro. */
Richard Henderson
committed
_cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node,
const uchar *result = NULL;
cpp_error (pfile, CPP_DL_ICE, "invalid built-in macro %qs",
NODE_NAME (node));
cpp_warning (pfile, CPP_W_DATE_TIME, "macro %qs might prevent "
"reproducible builds", NODE_NAME (node));
cpp_buffer *pbuffer = cpp_get_buffer (pfile);
if (pbuffer->timestamp == NULL)
{
/* Initialize timestamp value of the assotiated file. */
struct _cpp_file *file = cpp_get_file (pbuffer);
if (file)
{
/* Generate __TIMESTAMP__ string, that represents
the date and time of the last modification
of the current source file. The string constant
looks like "Sun Sep 16 01:03:52 1973". */
struct tm *tb = NULL;
struct stat *st = _cpp_get_file_stat (file);
if (st)
tb = localtime (&st->st_mtime);
if (tb)
{
char *str = asctime (tb);
size_t len = strlen (str);
unsigned char *buf = _cpp_unaligned_alloc (pfile, len + 2);
buf[0] = '"';
strcpy ((char *) buf + 1, str);
buf[len] = '"';
pbuffer->timestamp = buf;
}
else
{
cpp_errno (pfile, CPP_DL_WARNING,
"could not determine file timestamp");
pbuffer->timestamp = UC"\"??? ??? ?? ??:??:?? ????\"";
}
}
}
result = pbuffer->timestamp;
}
break;
case BT_FILE_NAME:
if (node->value.builtin == BT_FILE
|| node->value.builtin == BT_FILE_NAME)
{
name = linemap_get_expansion_filename (pfile->line_table,
pfile->line_table->highest_line);
if ((node->value.builtin == BT_FILE_NAME) && name)
name = lbasename (name);
}
name = _cpp_get_file_name (pfile->main_file);
if (!name)
abort ();
if (pfile->cb.remap_filename && !pfile->state.in_directive)
name = pfile->cb.remap_filename (name);
buf = _cpp_unaligned_alloc (pfile, len * 2 + 3);
result = buf;
*buf = '"';
buf = cpp_quote_string (buf + 1, (const unsigned char *) name, len);
*buf++ = '"';
*buf = '\0';
/* The line map depth counts the primary source as level 1, but
historically __INCLUDE_DEPTH__ has called the primary source
level 0. */
number = pfile->line_table->depth - 1;
case BT_SPECLINE:
/* If __LINE__ is embedded in a macro, it must expand to the
line of the macro's invocation, not its definition.
Richard Henderson
committed
Otherwise things like assert() will not work properly.
See WG14 N1911, WG21 N4220 sec 6.5, and PR 61861. */
if (CPP_OPTION (pfile, traditional))
loc = pfile->line_table->highest_line;
else
loc = linemap_resolve_location (pfile->line_table, loc,
LRK_MACRO_EXPANSION_POINT, NULL);
number = linemap_get_expansion_line (pfile->line_table, loc);
/* __STDC__ has the value 1 under normal circumstances.
However, if (a) we are in a system header, (b) the option
Zack Weinberg
committed
stdc_0_in_system_headers is true (set by target config), and
(c) we are not in strictly conforming mode, then it has the
Jakub Jelinek
committed
value 0. (b) and (c) are already checked in cpp_init_builtins. */
Jakub Jelinek
committed
number = 0;
else
number = 1;
cpp_warning (pfile, CPP_W_DATE_TIME, "macro %qs might prevent "
"reproducible builds", NODE_NAME (node));
if (pfile->date == NULL)
/* Allocate __DATE__ and __TIME__ strings from permanent
storage. We only do this once, and don't generate them
at init time, because time() and localtime() are very
slow on some systems. */
time_t tt;
cpp_errno (pfile, CPP_DL_WARNING,
"could not determine date and time");
pfile->date = UC"\"??? ?? ????\"";
pfile->time = UC"\"??:??:??\"";
struct tm *tb = (kind == CPP_time_kind::FIXED
? gmtime : localtime) (&tt);
pfile->date = _cpp_unaligned_alloc (pfile,
sizeof ("\"Oct 11 1347\""));
sprintf ((char *) pfile->date, "\"%s %2d %4d\"",
monthnames[tb->tm_mon], tb->tm_mday,
tb->tm_year + 1900);
pfile->time = _cpp_unaligned_alloc (pfile,
sizeof ("\"12:34:56\""));
sprintf ((char *) pfile->time, "\"%02d:%02d:%02d\"",
tb->tm_hour, tb->tm_min, tb->tm_sec);
}
result = pfile->date;
result = pfile->time;
if (CPP_OPTION (pfile, directives_only) && pfile->state.in_directive)
cpp_error (pfile, CPP_DL_ERROR,
"%<__COUNTER__%> expanded inside directive with "
"%<-fdirectives-only%>");
number = pfile->counter++;
break;
case BT_HAS_ATTRIBUTE:
number = pfile->cb.has_attribute (pfile, false);
break;
case BT_HAS_STD_ATTRIBUTE:
number = pfile->cb.has_attribute (pfile, true);
case BT_HAS_BUILTIN:
number = pfile->cb.has_builtin (pfile);
break;
case BT_HAS_INCLUDE:
case BT_HAS_INCLUDE_NEXT:
number = builtin_has_include (pfile, node,
node->value.builtin == BT_HAS_INCLUDE_NEXT);
break;
case BT_HAS_EMBED:
if (CPP_OPTION (pfile, traditional))
{
cpp_error (pfile, CPP_DL_ERROR, /* FIXME should be DL_SORRY */
"%<__has_embed%> not supported in traditional C");
break;
}
number = builtin_has_embed (pfile);
break;
case BT_HAS_FEATURE:
case BT_HAS_EXTENSION:
number = pfile->cb.has_feature (pfile,
node->value.builtin == BT_HAS_FEATURE);
break;
}
if (result == NULL)
{
/* 21 bytes holds all NUL-terminated unsigned 64-bit numbers. */
result = _cpp_unaligned_alloc (pfile, 21);
sprintf ((char *) result, "%u", number);
}
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
/* Get an idempotent date. Either the cached value, the value from
source epoch, or failing that, the value from time(2). Use this
during compilation so that every time stamp is the same. */
CPP_time_kind
cpp_get_date (cpp_reader *pfile, time_t *result)
{
if (!pfile->time_stamp_kind)
{
int kind = 0;
if (pfile->cb.get_source_date_epoch)
{
/* Try reading the fixed epoch. */
pfile->time_stamp = pfile->cb.get_source_date_epoch (pfile);
if (pfile->time_stamp != time_t (-1))
kind = int (CPP_time_kind::FIXED);
}
if (!kind)
{
/* Pedantically time_t (-1) is a legitimate value for
"number of seconds since the Epoch". It is a silly
time. */
errno = 0;
pfile->time_stamp = time (nullptr);
/* Annoyingly a library could legally set errno and return a
valid time! Bad library! */
if (pfile->time_stamp == time_t (-1) && errno)
kind = errno;
else
kind = int (CPP_time_kind::DYNAMIC);
}
pfile->time_stamp_kind = kind;
}
*result = pfile->time_stamp;
if (pfile->time_stamp_kind >= 0)
{
errno = pfile->time_stamp_kind;
return CPP_time_kind::UNKNOWN;
}
return CPP_time_kind (pfile->time_stamp_kind);
}
/* Convert builtin macros like __FILE__ to a token and push it on the
context stack. Also handles _Pragma, for which a new token may not
be created. Returns 1 if it generates a new token context, 0 to
return the token to the caller. LOC is the location of the expansion
point of the macro. */
Richard Henderson
committed
builtin_macro (cpp_reader *pfile, cpp_hashnode *node,
location_t loc, location_t expand_loc)
{
const uchar *buf;
size_t len;
char *nbuf;
if (node->value.builtin == BT_PRAGMA)
{
/* Don't interpret _Pragma within directives. The standard is
not clear on this, but to me this makes most sense.
Similarly, don't interpret _Pragma inside expand_args, we might
need to stringize it later on. */
if (pfile->state.in_directive || pfile->state.ignore__Pragma)
return _cpp_do__Pragma (pfile, loc);
Richard Henderson
committed
buf = _cpp_builtin_macro_text (pfile, node, expand_loc);
nbuf = (char *) alloca (len + 1);
memcpy (nbuf, buf, len);
nbuf[len]='\n';
Per Bothner
committed
cpp_push_buffer (pfile, (uchar *) nbuf, len, /* from_stage3 */ true);
_cpp_clean_line (pfile);
/* Set pfile->cur_token as required by _cpp_lex_direct. */
pfile->cur_token = _cpp_temp_token (pfile);
cpp_token *token = _cpp_lex_direct (pfile);
/* We should point to the expansion point of the builtin macro. */
token->src_loc = loc;
if (pfile->context->tokens_kind == TOKENS_KIND_EXTENDED)
{
/* We are tracking tokens resulting from macro expansion.
Create a macro line map and generate a virtual location for
the token resulting from the expansion of the built-in
macro. */
location_t *virt_locs = NULL;
_cpp_buff *token_buf = tokens_buff_new (pfile, 1, &virt_locs);
const line_map_macro * map =
Richard Henderson
committed
linemap_enter_macro (pfile->line_table, node, loc, 1);
tokens_buff_add_token (token_buf, virt_locs, token,
pfile->line_table->builtin_location,
pfile->line_table->builtin_location,
map, /*macro_token_index=*/0);
push_extended_tokens_context (pfile, node, token_buf, virt_locs,
(const cpp_token **)token_buf->base,
1);
}
else
_cpp_push_token_context (pfile, NULL, token, 1);
if (pfile->buffer->cur != pfile->buffer->rlimit)
cpp_error (pfile, CPP_DL_ICE, "invalid built-in macro %qs",
NODE_NAME (node));
_cpp_pop_buffer (pfile);
/* Copies SRC, of length LEN, to DEST, adding backslashes before all
backslashes and double quotes. DEST must be of sufficient size.
Returns a pointer to the end of the string. */
cpp_quote_string (uchar *dest, const uchar *src, unsigned int len)
case '\n':
/* Naked LF can appear in raw string literals */
c = 'n';
/* FALLTHROUGH */
case '\\':
case '"':
/* FALLTHROUGH */
default:
/* Convert a token sequence FIRST to FIRST+COUNT-1 to a single string token
according to the rules of the ISO C #-operator. */
stringify_arg (cpp_reader *pfile, const cpp_token **first, unsigned int count)
unsigned int i, escape_it, backslash_count = 0;
if (BUFF_ROOM (pfile->u_buff) < 3)
_cpp_extend_buff (pfile, &pfile->u_buff, 3);
dest = BUFF_FRONT (pfile->u_buff);
*dest++ = '"';
const cpp_token *token = first[i];
if (source == NULL
|| (!(source->flags & PREV_WHITE)
&& token->val.source == NULL))
source = token->val.source;
continue;
}
escape_it = (token->type == CPP_STRING || token->type == CPP_CHAR
|| token->type == CPP_WSTRING || token->type == CPP_WCHAR
|| token->type == CPP_STRING32 || token->type == CPP_CHAR32
|| token->type == CPP_STRING16 || token->type == CPP_CHAR16
|| token->type == CPP_UTF8STRING || token->type == CPP_UTF8CHAR
|| cpp_userdef_string_p (token->type)
|| cpp_userdef_char_p (token->type));
/* Room for each char being written in octal, initial space and
if ((size_t) (BUFF_LIMIT (pfile->u_buff) - dest) < len)
size_t len_so_far = dest - BUFF_FRONT (pfile->u_buff);
_cpp_extend_buff (pfile, &pfile->u_buff, len);
dest = BUFF_FRONT (pfile->u_buff) + len_so_far;
if (dest - 1 != BUFF_FRONT (pfile->u_buff))
{
if (source == NULL)
source = token;
if (source->flags & PREV_WHITE)
*dest++ = ' ';
}
source = NULL;
_cpp_buff *buff = _cpp_get_buff (pfile, len);
unsigned char *buf = BUFF_FRONT (buff);
len = cpp_spell_token (pfile, token, buf, true) - buf;
dest = cpp_quote_string (dest, buf, len);
_cpp_release_buff (pfile, buff);
dest = cpp_spell_token (pfile, token, dest, true);
if (token->type == CPP_OTHER && token->val.str.text[0] == '\\')