@@ -621,6 +621,19 @@ c_common_handle_option (size_t scode, const char *arg, int value,
cpp_opts->preprocessed = value;
break;
+ case OPT_ftrack_macro_expansion:
+ if (value)
+ value = 2;
+ goto ftrack_macro_expansion_with_arg;
+
+ case OPT_ftrack_macro_expansion_:
+ ftrack_macro_expansion_with_arg:
+ if (arg && *arg != '\0')
+ cpp_opts->track_macro_expansion = value;
+ else
+ cpp_opts->track_macro_expansion = 2;
+ break;
+
case OPT_frepo:
flag_use_repository = value;
if (value)
@@ -909,6 +909,14 @@ fpreprocessed
C ObjC C++ ObjC++
Treat the input file as already preprocessed
+ftrack-macro-expansion
+C ObjC C++ ObjC++ JoinedOrMissing RejectNegative UInteger
+; converted into ftrack-macro-expansion=
+
+ftrack-macro-expansion=
+C ObjC C++ ObjC++ JoinedOrMissing RejectNegative UInteger
+-ftrack-macro-expansion=<0|1|2> Track locations of tokens coming from macro expansion and display them in error messages
+
fpretty-templates
C++ ObjC++ Var(flag_pretty_templates) Init(1)
-fno-pretty-templates Do not pretty-print template specializations as the template signature followed by the arguments
@@ -583,6 +583,23 @@ correct column numbers in warnings or errors, even if tabs appear on the
line. If the value is less than 1 or greater than 100, the option is
ignored. The default is 8.
+@item -ftrack-macro-expansion@r{[}=@var{level}@r{]}
+@opindex ftrack-macro-expansion
+Track locations of tokens across macro expansions. This allows the
+compiler to emit diagnostic about the current macro expansion stack
+when a compilation error occurs in a macro expansion. Using this
+option makes the preprocessor and the compiler consume more
+memory. The @var{level} parameter can be used to choose the level of
+precision of token location tracking thus decreasing the memory
+consumption if necessary. Value @samp{0} of @var{level} de-activates
+this option just as if no @option{-ftrack-macro-expansion} was present
+on the command line. Value @samp{1} tracks tokens locations in a
+degraded mode for the sake of minimal memory overhead. In this mode
+all tokens resulting from the expansion of an argument of a
+function-like macro have the same location. Value @samp{2} tracks
+tokens locations completely. This value is the most memory hungry. It
+is the default value.
+
@item -fexec-charset=@var{charset}
@opindex fexec-charset
@cindex character set, execution
@@ -415,9 +415,9 @@ Objective-C and Objective-C++ Dialects}.
-iwithprefixbefore @var{dir} -isystem @var{dir} @gol
-imultilib @var{dir} -isysroot @var{dir} @gol
-M -MM -MF -MG -MP -MQ -MT -nostdinc @gol
--P -fworking-directory -remap @gol
--trigraphs -undef -U@var{macro} -Wp,@var{option} @gol
--Xpreprocessor @var{option}}
+-P -ftrack-macro-expansion -fworking-directory @gol
+-remap -trigraphs -undef -U@var{macro} @gol
+-Wp,@var{option} -Xpreprocessor @var{option}}
@item Assembler Option
@xref{Assembler Options,,Passing Options to the Assembler}.
@@ -389,6 +389,14 @@ struct cpp_options
bother trying to do macro expansion and whatnot. */
unsigned char preprocessed;
+ /* Nonzero means we are tracking locations of tokens involved in
+ macro expansion. 1 Means we track the location in degraded mode
+ where we do not track locations of tokens resulting from the
+ expansion of arguments of function-like macro. all macro
+ expansion. 2 Means we do track all macro expansions. This last
+ option is the one that consumes the highest amount of memory. */
+ unsigned char track_macro_expansion;
+
/* Nonzero means handle C++ alternate operator names. */
unsigned char operator_names;
@@ -151,6 +151,7 @@ cpp_create_reader (enum c_lang lang, hash_table *table,
init_library ();
pfile = XCNEW (cpp_reader);
+ memset (&pfile->base_context, 0, sizeof (pfile->base_context));
cpp_set_lang (pfile, lang);
CPP_OPTION (pfile, warn_multichar) = 1;
@@ -139,6 +139,44 @@ struct tokenrun
#define CUR(c) ((c)->u.trad.cur)
#define RLIMIT(c) ((c)->u.trad.rlimit)
+
+/* This is a "special" token representation that reuses a "normal"
+ token and adds a location. The location is useful when the tokens
+ results from macro expansion. In that case LOCATION encodes the
+ locus of the token in the macro definition as well as the locus of
+ the token at the macro expansion point. This representation is
+ used when -ftrack-macro-expansion is on, and for tokens resulting
+ from macro expansion only. */
+struct cpp_extended_token
+{
+ const cpp_token *token;
+ /* The location of the token in the context of the macro expansion.
+ This is different from the location of the token member above
+ which would be the location of the token in the context of the
+ definition of the macro. */
+ source_location location;
+};
+typedef struct cpp_extended_token cpp_ext_token;
+
+/* The kind of tokens carried by a cpp_context. */
+enum context_tokens_kind {
+ /* This is the value of cpp_context::tokens_kind if u.iso.first
+ contains an instance of cpp_token **. */
+ TOKENS_KIND_INDIRECT,
+ /* This is the value of cpp_context::tokens_kind if u.iso.first
+ contains an instance of cpp_token *. */
+ TOKENS_KIND_DIRECT,
+ /* This is the value of cpp_context::tokens_kind if u.iso.first
+ contains an instance of cpp_extended_token. This is used only
+ when the -ftrack-macro-expansion flag is on. Note that in this
+ case the static type of u.iso.first is still considered to be
+ cpp_token ** even though each element of the array pointed to by
+ u.iso.first are effectively instances of cpp_exted_token. This is
+ a hack done so that the size of u.iso.first remains "small" when
+ the flag -ftrack-macro-expansion is not used. */
+ TOKENS_KIND_EXTENDED
+};
+
typedef struct cpp_context cpp_context;
struct cpp_context
{
@@ -171,8 +209,8 @@ struct cpp_context
/* For a macro context, the macro node, otherwise NULL. */
cpp_hashnode *macro;
- /* True if utoken element is token, else ptoken. */
- bool direct_p;
+ /* This determines the type of tokens hold by this context. */
+ enum context_tokens_kind tokens_kind;
};
struct lexer_state
@@ -601,6 +639,7 @@ extern cpp_token *_cpp_lex_direct (cpp_reader *);
extern int _cpp_equiv_tokens (const cpp_token *, const cpp_token *);
extern void _cpp_init_tokenrun (tokenrun *, unsigned int);
extern cpp_hashnode *_cpp_lex_identifier (cpp_reader *, const char *);
+extern int _cpp_remaining_tokens_num_in_context (cpp_reader *);
/* In init.c. */
extern void _cpp_maybe_push_include_file (cpp_reader *);
@@ -1719,6 +1719,41 @@ next_tokenrun (tokenrun *run)
return run->next;
}
+/* Return the number of not yet processed token in the the current
+ context. */
+int
+_cpp_remaining_tokens_num_in_context (cpp_reader *pfile)
+{
+ cpp_context *context = pfile->context;
+ if (context->tokens_kind == TOKENS_KIND_DIRECT)
+ return (LAST (context).token - FIRST (context).token) / sizeof (cpp_token);
+ else if (context->tokens_kind == TOKENS_KIND_INDIRECT)
+ return (LAST (context).ptoken - FIRST (context).ptoken) / sizeof (cpp_token *);
+ else if (context->tokens_kind == TOKENS_KIND_EXTENDED)
+ return (LAST (context).ptoken - FIRST (context).ptoken) / sizeof (cpp_ext_token);
+ else
+ abort ();
+}
+
+/* Returns the token present at index INDEX in the current context.
+ If INDEX is zero, the next token to be processed is returned. */
+static const cpp_token*
+_cpp_token_from_context_at (cpp_reader *pfile, int index)
+{
+ cpp_context *context = pfile->context;
+ if (context->tokens_kind == TOKENS_KIND_DIRECT)
+ return &(FIRST (context).token[index]);
+ else if (context->tokens_kind == TOKENS_KIND_INDIRECT)
+ return FIRST (context).ptoken[index];
+ else if (context->tokens_kind == TOKENS_KIND_EXTENDED)
+ {
+ cpp_ext_token *ptr = (cpp_ext_token *) FIRST (context).ptoken;
+ return ptr[index].token;
+ }
+ else
+ abort ();
+}
+
/* Look ahead in the input stream. */
const cpp_token *
cpp_peek_token (cpp_reader *pfile, int index)
@@ -1730,15 +1765,10 @@ cpp_peek_token (cpp_reader *pfile, int index)
/* First, scan through any pending cpp_context objects. */
while (context->prev)
{
- ptrdiff_t sz = (context->direct_p
- ? LAST (context).token - FIRST (context).token
- : LAST (context).ptoken - FIRST (context).ptoken);
+ ptrdiff_t sz = _cpp_remaining_tokens_num_in_context (pfile);
if (index < (int) sz)
- return (context->direct_p
- ? FIRST (context).token + index
- : *(FIRST (context).ptoken + index));
-
+ return _cpp_token_from_context_at (pfile, index);
index -= (int) sz;
context = context->prev;
}
@@ -37,15 +37,55 @@ struct macro_arg
const cpp_token *stringified; /* Stringified argument. */
unsigned int count; /* # of tokens in argument. */
unsigned int expanded_count; /* # of tokens in expanded argument. */
+ size_t expanded_capacity; /* total size of expanded array. */
+};
+
+/* 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
+ litteral, 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 token coming from a function line macro
+ argument. */
+typedef struct macro_arg_token_iter macro_arg_token_iter;
+struct macro_arg_token_iter
+{
+ /* The cpp_reader the macro comes from. */
+ cpp_reader *pfile;
+ /* The kind of token which we are supposed to iterator over. */
+ enum macro_arg_token_kind kind;
+ /* The function-like macro the tokens come from. */
+ const macro_arg *arg;
+ /* 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 locuses
+ accross macro expansion. */
+ const source_location *location_ptr;
+#ifdef ENABLE_CHECKING
+ /* The number of times the iterator went forward. This useful only
+ when checking is enabled. */
+ size_t num_forwards;
+#endif
};
/* Macro expansion. */
static int enter_macro_context (cpp_reader *, cpp_hashnode *,
- const cpp_token *);
+ const cpp_token *, source_location);
static int builtin_macro (cpp_reader *, cpp_hashnode *);
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 *, const cpp_token **,
+ unsigned int);
static _cpp_buff *collect_args (cpp_reader *, const cpp_hashnode *,
_cpp_buff **);
static cpp_context *next_context (cpp_reader *);
@@ -55,8 +95,50 @@ static const cpp_token *new_string_token (cpp_reader *, uchar *, unsigned int);
static const cpp_token *stringify_arg (cpp_reader *, macro_arg *);
static void paste_all_tokens (cpp_reader *, const cpp_token *);
static bool paste_tokens (cpp_reader *, const cpp_token **, const cpp_token *);
+static void alloc_expanded_args_mem (cpp_reader *, macro_arg *, size_t);
+static void ensure_expanded_args_room (cpp_reader *, macro_arg *, size_t);
+static _cpp_buff *alloc_args_buff (cpp_reader *, size_t);
+static _cpp_buff *extend_arg_tokens_room (cpp_reader *, _cpp_buff *, size_t);
+static void set_arg_token (cpp_reader *, macro_arg *, const cpp_token *,
+ source_location, size_t, enum macro_arg_token_kind);
+static const source_location *get_arg_token_location (cpp_reader *,
+ const macro_arg *,
+ enum macro_arg_token_kind);
+static const cpp_token **arg_token_ptr_at (cpp_reader *, const macro_arg *,
+ size_t, enum macro_arg_token_kind);
+static const cpp_token *arg_token_at (cpp_reader *, macro_arg *, size_t,
+ enum macro_arg_token_kind);
+static const cpp_token **next_macro_token_ptr (cpp_reader *, const cpp_token **);
+static const cpp_token **prev_macro_token_ptr (cpp_reader *, const cpp_token **);
+static const cpp_token **macro_token_ptr_at (cpp_reader *, const cpp_token **, int);
+static source_location *next_arg_location_ptr (cpp_reader *,
+ const source_location *);
+static void macro_arg_token_iter_init (macro_arg_token_iter *, cpp_reader*,
+ 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 source_location 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_reader *, _cpp_buff *);
+static const cpp_token **tokens_buff_last_token_ptr (cpp_reader *,
+ _cpp_buff *);
+static const cpp_token **tokens_buff_put_token_to
+(cpp_reader *, const cpp_token **, const cpp_token *, source_location,
+ source_location, const struct line_map *, unsigned int *);
+
+static const cpp_token **tokens_buff_append_token (cpp_reader *,
+ _cpp_buff *,
+ const cpp_token *,
+ source_location,
+ source_location,
+ const struct line_map *,
+ unsigned int *);
+static void tokens_buff_remove_last_token (cpp_reader *, _cpp_buff *);
static void replace_args (cpp_reader *, cpp_hashnode *, cpp_macro *,
- macro_arg *);
+ macro_arg *, source_location);
static _cpp_buff *funlike_invocation_p (cpp_reader *, cpp_hashnode *,
_cpp_buff **);
static bool create_iso_definition (cpp_reader *, cpp_macro *);
@@ -70,6 +152,11 @@ static bool warn_of_redefinition (cpp_reader *, cpp_hashnode *,
static bool parse_params (cpp_reader *, cpp_macro *);
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 **,
+ source_location *);
+static const cpp_token* cpp_get_token_1 (cpp_reader *, source_location *);
/* Emits a warning if NODE is a macro defined in the main file that
has not been used. */
@@ -369,7 +456,8 @@ stringify_arg (cpp_reader *pfile, macro_arg *arg)
/* Loop, reading in the argument's tokens. */
for (i = 0; i < arg->count; i++)
{
- const cpp_token *token = arg->first[i];
+ const cpp_token *token = arg_token_at (pfile, arg, i,
+ MACRO_ARG_TOKEN_NORMAL);
if (token->type == CPP_PADDING)
{
@@ -511,7 +599,7 @@ paste_tokens (cpp_reader *pfile, const cpp_token **plhs, const cpp_token *rhs)
static void
paste_all_tokens (cpp_reader *pfile, const cpp_token *lhs)
{
- const cpp_token *rhs;
+ const cpp_token *rhs = NULL;
cpp_context *context = pfile->context;
do
@@ -521,10 +609,16 @@ paste_all_tokens (cpp_reader *pfile, const cpp_token *lhs)
object-like macro, or a function-like macro with arguments
inserted. In either case, the constraints to #define
guarantee we have at least one more token. */
- if (context->direct_p)
+ if (context->tokens_kind == TOKENS_KIND_DIRECT)
rhs = FIRST (context).token++;
- else
+ else if (context->tokens_kind == TOKENS_KIND_INDIRECT)
rhs = *FIRST (context).ptoken++;
+ else if (context->tokens_kind == TOKENS_KIND_EXTENDED)
+ {
+ rhs = ((cpp_ext_token *) FIRST (context).ptoken)->token;
+ FIRST (context).ptoken =
+ next_macro_token_ptr (pfile, FIRST (context).ptoken);
+ }
if (rhs->type == CPP_PADDING)
{
@@ -598,14 +692,16 @@ collect_args (cpp_reader *pfile, const cpp_hashnode *node,
macro_arg *args, *arg;
const cpp_token *token;
unsigned int argc;
+ source_location virt_loc;
macro = node->value.macro;
if (macro->paramc)
argc = macro->paramc;
else
argc = 1;
- buff = _cpp_get_buff (pfile, argc * (50 * sizeof (cpp_token *)
- + sizeof (macro_arg)));
+
+ buff = alloc_args_buff (pfile, argc);
+
base_buff = buff;
args = (macro_arg *) buff->base;
memset (args, 0, argc * sizeof (macro_arg));
@@ -626,15 +722,16 @@ collect_args (cpp_reader *pfile, const cpp_hashnode *node,
for (;;)
{
/* Require space for 2 new tokens (including a CPP_EOF). */
- if ((unsigned char *) &arg->first[ntokens + 2] > buff->limit)
+ if ((unsigned char *) arg_token_ptr_at (pfile, arg, ntokens + 2,
+ MACRO_ARG_TOKEN_NORMAL)
+ > buff->limit)
{
- buff = _cpp_append_extend_buff (pfile, buff,
- 1000 * sizeof (cpp_token *));
+ buff = extend_arg_tokens_room (pfile, buff, 1000);
arg->first = (const cpp_token **) buff->cur;
}
- token = cpp_get_token (pfile);
-
+ token = cpp_get_token_1 (pfile, &virt_loc);
+
if (token->type == CPP_PADDING)
{
/* Drop leading padding. */
@@ -690,7 +787,7 @@ collect_args (cpp_reader *pfile, const cpp_hashnode *node,
BUFF_FRONT (*pragma_buff) += sizeof (cpp_token *);
if (token->type == CPP_PRAGMA_EOL)
break;
- token = cpp_get_token (pfile);
+ token = cpp_get_token_1 (pfile, &virt_loc);
}
while (token->type != CPP_EOF);
@@ -704,22 +801,28 @@ collect_args (cpp_reader *pfile, const cpp_hashnode *node,
else
continue;
}
-
- arg->first[ntokens++] = token;
+ set_arg_token (pfile, arg, token, virt_loc,
+ ntokens, MACRO_ARG_TOKEN_NORMAL);
+ ntokens++;
}
/* Drop trailing padding. */
- while (ntokens > 0 && arg->first[ntokens - 1]->type == CPP_PADDING)
+ while (ntokens > 0
+ && arg_token_at (pfile, arg, ntokens - 1,
+ MACRO_ARG_TOKEN_NORMAL)->type == CPP_PADDING)
ntokens--;
arg->count = ntokens;
- arg->first[ntokens] = &pfile->eof;
+ set_arg_token (pfile, arg, &pfile->eof, pfile->eof.src_loc,
+ ntokens, MACRO_ARG_TOKEN_NORMAL);
/* Terminate the argument. Excess arguments loop back and
overwrite the final legitimate argument, before failing. */
if (argc <= macro->paramc)
{
- buff->cur = (unsigned char *) &arg->first[ntokens + 1];
+ buff->cur =
+ (unsigned char *) arg_token_ptr_at (pfile, arg, ntokens + 1,
+ MACRO_ARG_TOKEN_NORMAL);
if (argc != macro->paramc)
arg++;
}
@@ -823,13 +926,15 @@ macro_real_token_count (const cpp_macro *macro)
/* Push the context of a macro with hash entry NODE onto the context
stack. If we can successfully expand the macro, we push a context
containing its yet-to-be-rescanned replacement list and return one.
- If there were additionally any unexpanded deferred #pragma directives
- among macro arguments, push another context containing the
- pragma tokens before the yet-to-be-rescanned replacement list
- and return two. Otherwise, we don't push a context and return zero. */
+ If there were additionally any unexpanded deferred #pragma
+ directives among macro arguments, push another context containing
+ the pragma tokens before the yet-to-be-rescanned replacement list
+ and return two. Otherwise, we don't push a context and return
+ zero. LOCATION is the location of the expansion point of the
+ macro. */
static int
enter_macro_context (cpp_reader *pfile, cpp_hashnode *node,
- const cpp_token *result)
+ const cpp_token *token, source_location location)
{
/* The presence of a macro invalidates a file's controlling macro. */
pfile->mi_valid = false;
@@ -877,8 +982,13 @@ enter_macro_context (cpp_reader *pfile, cpp_hashnode *node,
}
if (macro->paramc > 0)
- replace_args (pfile, node, macro, (macro_arg *) buff->base);
- _cpp_release_buff (pfile, buff);
+ replace_args (pfile, node, macro,
+ (macro_arg *) buff->base,
+ location);
+ /* Unlike _cpp_release_buff, calling _cpp_free_buff
+ actually frees the memory for real. This reduces peak
+ memory usage on source code with a lot of macros. */
+ _cpp_free_buff (buff);
}
/* Disable the macro within its expansion. */
@@ -892,19 +1002,47 @@ enter_macro_context (cpp_reader *pfile, cpp_hashnode *node,
}
if (pfile->cb.used)
- pfile->cb.used (pfile, result->src_loc, node);
+ pfile->cb.used (pfile, location, node);
macro->used = 1;
if (macro->paramc == 0)
- _cpp_push_token_context (pfile, node, macro->exp.tokens,
- macro_real_token_count (macro));
+ {
+ if (CPP_OPTION (pfile, track_macro_expansion))
+ {
+ unsigned int i, count = macro->count;
+ const cpp_token *src = macro->exp.tokens;
+ const struct line_map *map;
+ _cpp_buff *macro_tokens =
+ tokens_buff_new (pfile, count);
+
+ /* Create a macro map to record the locations of the
+ tokens that are involved in the expansion. LOCATION
+ is the location of the macro expansion point. */
+ map = linemap_enter_macro (pfile->line_table,
+ macro, location, count);
+ for (i = 0; i < count; ++i)
+ {
+ tokens_buff_append_token (pfile, macro_tokens, src,
+ src->src_loc, src->src_loc,
+ map, &i);
+ ++src;
+ }
+ push_extended_tokens_context (pfile, node, macro_tokens,
+ (const cpp_token **)
+ macro_tokens->base,
+ count);
+ }
+ else
+ _cpp_push_token_context (pfile, node, macro->exp.tokens,
+ macro_real_token_count (macro));
+ }
if (pragma_buff)
{
if (!pfile->state.in_directive)
_cpp_push_token_context (pfile, NULL,
- padding_token (pfile, result), 1);
+ padding_token (pfile, token), 1);
do
{
_cpp_buff *tail = pragma_buff->next;
@@ -926,33 +1064,336 @@ enter_macro_context (cpp_reader *pfile, cpp_hashnode *node,
return builtin_macro (pfile, node);
}
+/* Allocates a buffer to hold tokens coming from macro arguments. If
+ -ftrack-macro-expansion is used the buffer holds instances of
+ cpp_ext_token, otherwise it holds instance of cpp_token *. The
+ buffer is big enough to contain NUM_ARGS instances of macro_arg
+ data, and for each instance of macro_arg can contain 50 tokens that
+ can be accessed from the macro_arg::first pointer. */
+static _cpp_buff*
+alloc_args_buff (cpp_reader *pfile, size_t num_args)
+{
+ bool track_macro_exp_p = CPP_OPTION (pfile, track_macro_expansion);
+ size_t arg_size;
+
+ if (track_macro_exp_p)
+ arg_size = 50 * sizeof (cpp_ext_token) + sizeof (macro_arg);
+ else
+ arg_size = 50 * sizeof (cpp_token *) + sizeof (macro_arg);
+
+ return _cpp_get_buff (pfile, num_args * arg_size);
+}
+
+/* Enlarges the memory room pointed to by the macro_arg::first pointer
+ to make it capable of containing NUM_ELEMS more worth of tokens.
+
+ Creates a new buffer big enough to hold NUM_ELEMS tokens as well as
+ a the uncommitted tokens remaining in BUFF, chain that new buffer
+ to the end of BUFF, and return it. BUFF->CUR must be the memory room to
+ store tokens belonging to a function-like macro argument (the
+ macro_arg::first pointer). */
+static _cpp_buff *
+extend_arg_tokens_room (cpp_reader *pfile, _cpp_buff *buff, size_t num_elems)
+{
+ bool track_macro_exp_p = CPP_OPTION (pfile, track_macro_expansion);
+ size_t token_size =
+ (track_macro_exp_p) ? sizeof (cpp_ext_token) : sizeof (cpp_token *);
+
+ return _cpp_append_extend_buff (pfile, buff, num_elems * token_size);
+}
+
+/* Set the INDEXth token of the macro argument ARG. TOKEN is the
+ token to set, LOCATION is its location. If TOKEN comes from a
+ macro expansion and if -ftrack-macro-location is in effect,
+ LOCATION must be the location that encodes locuses accross macro
+ expansion. Otherwise it has to be TOKEN->SRC_LOC. KIND is the kind
+ of tokens the argument ARG is supposed to contain. */
+static void
+set_arg_token (cpp_reader *pfile, macro_arg *arg, const cpp_token *token,
+ source_location location, size_t index,
+ enum macro_arg_token_kind kind)
+{
+ bool track_macro_exp_p = CPP_OPTION (pfile, track_macro_expansion);
+ const cpp_token **token_ptr;
+
+ token_ptr = arg_token_ptr_at (pfile, arg, index, kind);
+ if (track_macro_exp_p)
+ {
+ ((cpp_ext_token *) token_ptr)->token = (cpp_token *) token;
+ ((cpp_ext_token *) token_ptr)->location = location;
+ }
+ else
+ *token_ptr = token;
+}
+
+/* Get the pointer to the location of the argument token of the
+ function-like macro argument ARG. */
+static const source_location *
+get_arg_token_location (cpp_reader *pfile,
+ const macro_arg *arg,
+ enum macro_arg_token_kind kind)
+{
+ bool track_macro_exp_p = CPP_OPTION (pfile, track_macro_expansion);
+ const cpp_token **token_ptr = arg_token_ptr_at (pfile, arg, 0, kind);
+
+ if (token_ptr == NULL)
+ return NULL;
+
+ if (track_macro_exp_p)
+ return &((cpp_ext_token *) token_ptr)->location;
+ return (source_location *) &((*token_ptr)->src_loc);
+
+}
+
+/* Return the pointer to the INDEXth token of the macro argument ARG.
+ KIND specifies the kind of token the macro argument ARG
+ contains. */
+static const cpp_token **
+arg_token_ptr_at (cpp_reader *pfile, const macro_arg *arg,
+ size_t index, enum macro_arg_token_kind kind)
+{
+ bool track_macro_exp_p = CPP_OPTION (pfile, track_macro_expansion);
+ const cpp_token **ptr = NULL;
+
+ switch (kind)
+ {
+ case MACRO_ARG_TOKEN_NORMAL:
+ ptr = arg->first;
+ break;
+ case MACRO_ARG_TOKEN_STRINGIFIED:
+ ptr = (const cpp_token **) &arg->stringified;
+ break;
+ case MACRO_ARG_TOKEN_EXPANDED:
+ ptr = arg->expanded;
+ break;
+ }
+
+ if (track_macro_exp_p)
+ return (const cpp_token **) &((cpp_ext_token *) ptr)[index].token;
+ else
+ return &ptr[index];
+}
+
+/* Return the INDEXth token of the macro argument ARG. KIND specifies
+ the kind of token the macro argument ARG contains. */
+static const cpp_token *
+arg_token_at (cpp_reader *pfile, macro_arg *arg, size_t index,
+ enum macro_arg_token_kind kind)
+{
+ return *arg_token_ptr_at (pfile, arg, index, kind);
+}
+
+/* Return the address of the token coming right after *TOKEN_PTR. The
+ function handles the different types of tokens. If
+ -ftrack-macro-expansion is used, the token pointed to by TOKEN_PTR
+ is considered to be an instance of cpp_ext_token otherwise it's a
+ cpp_token*. */
+static const cpp_token **
+next_macro_token_ptr (cpp_reader *pfile, const cpp_token **token_ptr)
+{
+ return macro_token_ptr_at (pfile, token_ptr, 1);
+}
+
+/* Return the address of the token coming right before *TOKEN_PTR. The
+ function handles the different types of tokens. If
+ -ftrack-macro-expansion is used, the token pointed to by TOKEN_PTR
+ is considered to be an instance of cpp_ext_token otherwise it's a
+ cpp_token*. */
+static const cpp_token **
+prev_macro_token_ptr (cpp_reader *pfile, const cpp_token **token_ptr)
+{
+ return macro_token_ptr_at (pfile, token_ptr, -1);
+}
+
+/* Return the address of the token at index INDEX, starting from
+ TOKEN_PTR. The function handles the different types of tokens. If
+ -ftrack-macro-expansion is used, the token pointed to by TOKEN_PTR
+ is considered to be an instance of cpp_ext_token otherwise it's a
+ cpp_token *. */
+static const cpp_token **
+macro_token_ptr_at (cpp_reader *pfile,
+ const cpp_token **token_ptr,
+ int index)
+{
+ bool track_macro_exp_p = CPP_OPTION (pfile, track_macro_expansion);
+
+ if (track_macro_exp_p)
+ return &((cpp_ext_token *) (token_ptr))[index].token;
+ return &token_ptr[index];
+}
+
+/* Return the address of the location of the token coming right after
+ the token which location is pointed to by LOCATION. If
+ -ftrack-macro-expansion is used, the token is considered to be an
+ instance of cpp_ext_token otherwise it's a cpp_token *. */
+static source_location *
+next_arg_location_ptr (cpp_reader *pfile,
+ const source_location *location)
+{
+ bool track_macro_exp_p = CPP_OPTION (pfile, track_macro_expansion);
+
+ if (track_macro_exp_p)
+ {
+ cpp_ext_token *base;
+ base = (cpp_ext_token *)
+ ((unsigned char*) location - offsetof (cpp_ext_token, location));
+ return &base[1].location;
+ }
+ else
+ abort ();
+}
+
+/* Initialize an iterator so that it iterates over the tokens of a
+ function-like macro argument. KIND is the kind of tokens we want
+ ITER to iterate over. TOKEN_PTR points the first token ITER will
+ iterate over. */
+static void
+macro_arg_token_iter_init (macro_arg_token_iter *iter,
+ cpp_reader *pfile,
+ enum macro_arg_token_kind kind,
+ const macro_arg *arg,
+ const cpp_token **token_ptr)
+{
+ iter->pfile = pfile;
+ iter->kind = kind;
+ iter->arg = arg;
+ iter->token_ptr = token_ptr;
+ iter->location_ptr = get_arg_token_location (pfile, arg, kind);
+#ifdef ENABLE_CHECKING
+ iter->num_forwards = 0;
+#endif
+}
+
+/* Move the iterator one token forward. Note that if IT was
+ initialized on an argument that has a stringified token, moving it
+ foward doesn't make sense as a stringified token is essentially one
+ string. */
+static void
+macro_arg_token_iter_forward (macro_arg_token_iter *it)
+{
+ bool track_macro_exp_p = CPP_OPTION (it->pfile,
+ track_macro_expansion);
+
+ switch (it->kind)
+ {
+ case MACRO_ARG_TOKEN_NORMAL:
+ case MACRO_ARG_TOKEN_EXPANDED:
+ it->token_ptr = next_macro_token_ptr (it->pfile,
+ it->token_ptr);
+ if (track_macro_exp_p)
+ it->location_ptr =
+ next_arg_location_ptr (it->pfile,
+ it->location_ptr);
+ break;
+ case MACRO_ARG_TOKEN_STRINGIFIED:
+#ifdef ENABLE_CHECKING
+ if (it->num_forwards > 0)
+ abort ();
+ it->num_forwards++;
+#endif
+ break;
+ }
+}
+
+/* Return the token pointed to by the iterator. */
+static const cpp_token *
+macro_arg_token_iter_get_token (const macro_arg_token_iter *it)
+{
+#ifdef ENABLE_CHECKING
+ if (it->kind == MACRO_ARG_TOKEN_STRINGIFIED
+ && it->num_forwards > 0)
+ abort ();
+#endif
+ if (it->token_ptr == NULL)
+ return NULL;
+ return *it->token_ptr;
+}
+
+/* Return the location of the token pointed to by the iterator.*/
+static source_location
+macro_arg_token_iter_get_location (const macro_arg_token_iter *it)
+{
+#ifdef ENABLE_CHECKING
+ if (it->kind == MACRO_ARG_TOKEN_STRINGIFIED
+ && it->num_forwards > 0)
+ abort ();
+#endif
+ return *it->location_ptr;
+}
+
+/* Return the index of a token [resulting from macro expansion] inside
+ the total list of tokens resulting from a given macro
+ expansion. The index can be different depending on whether if we
+ want each tokens resulting from function-like macro arguments
+ expansion to have a different location or not.
+
+ E.g, consider this function like macro:
+
+ #define M(x) x - 3
+
+ Then consider us "calling" it (and thus expanding it) like:
+
+ M(1+2)
+
+ It will be expanded into:
+
+ 1+2-3
+
+ Let's consider the case of the token '2'.
+
+ Its index can be 1 (it's the third token of the set of tokens
+ resulting from the expansion) or it can be 0 if we consider that
+ all tokens resulting from the expansion of the argument "1+2" have
+ the same index, which is 0. In this later case, the index of token
+ '-' would then be 1 and the index of token '3' would be 2.
+
+ The later case is useful to use less memory e.g, for the case of
+ the user using the option -ftrack-macro-expansion=1.
+
+ This is a subroutine of replace_args. */
+inline static unsigned
+expanded_token_index (cpp_reader *pfile, cpp_macro *macro,
+ const cpp_token *cur_replacement_token,
+ unsigned absolute_token_index)
+{
+ if (CPP_OPTION (pfile, track_macro_expansion) > 1)
+ return absolute_token_index;
+ return cur_replacement_token - macro->exp.tokens;
+}
+
/* Replace the parameters in a function-like macro of NODE with the
actual ARGS, and place the result in a newly pushed token context.
Expand each argument before replacing, unless it is operated upon
- by the # or ## operators. */
+ by the # or ## operators. EXPANSION_POINT_LOC is the location of
+ the expansion point of the macro. E.g, the location of the
+ function-like macro invocation. */
static void
-replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro, macro_arg *args)
+replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro,
+ macro_arg *args, source_location expansion_point_loc)
{
unsigned int i, total;
const cpp_token *src, *limit;
- const cpp_token **dest, **first;
+ const cpp_token **first = NULL;
macro_arg *arg;
- _cpp_buff *buff;
- unsigned int count;
+ _cpp_buff *buff = NULL;
+ unsigned int exp_count;
+ const struct line_map *map = NULL;
+ bool track_macro_exp_p;
/* First, fully macro-expand arguments, calculating the number of
tokens in the final expansion as we go. The ordering of the if
statements below is subtle; we must handle stringification before
pasting. */
- count = macro_real_token_count (macro);
- total = count;
- limit = macro->exp.tokens + count;
+ exp_count = macro_real_token_count (macro);
+ total = exp_count;
+ limit = macro->exp.tokens + exp_count;
for (src = macro->exp.tokens; src < limit; src++)
if (src->type == CPP_MACRO_ARG)
{
/* Leading and trailing padding tokens. */
total += 2;
+ exp_count += 2;
/* We have an argument. If it is not being stringified or
pasted it is macro-replaced before insertion. */
@@ -974,67 +1415,189 @@ replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro, macro_arg
}
}
+ /* When the compiler is called with the -ftrack-macro-expansion
+ flag, we need to keep track of the location of each token that
+ results from macro expansion.
+
+ A token resulting from macro expansion is not a new token. It is
+ simply the same token as the token coming from the macro
+ definition. The new things that are allocated are the buffer that
+ holds the tokens resulting from macro expansion and a new
+ location that records many things like the locus of the expansion
+ point as well as the original locus inside the definition of the
+ macro. This is basically what the buffer buff holds: a set of
+ cpp_token* and a location.
+
+ The memory allocated to store the tokens and their locations is
+ going to be freed once the context of macro expansion is popped.
+
+ As far as tokens are concerned, the memory overhead of
+ -ftrack-macro-expansion is proportional to the number of
+ macros that get expanded multiplied by sizeof (source_location).
+ The good news is that extra memory gets freed when the macro
+ context is freed, i.e shortly after the macro got expanded. */
+
+ /* Is the -ftrack-macro-expansion flag in effect? */
+ track_macro_exp_p = CPP_OPTION (pfile, track_macro_expansion);
+
/* Now allocate space for the expansion, copy the tokens and replace
- the arguments. */
- buff = _cpp_get_buff (pfile, total * sizeof (cpp_token *));
+ the arguments. This memory must be freed when the context of
+ the macro MACRO is popped. */
+ buff = tokens_buff_new (pfile, total);
+
first = (const cpp_token **) buff->base;
- dest = first;
+ /* Create a macro map to record the locations of the tokens that are
+ involved in the expansion. Note that the expansion point is set
+ to the location of the closing parenthesis. Otherwise, the
+ subsequent map created for the first token that comes after the
+ macro map might have a wrong line number. What would lead to
+ tokens with wrong line numbers after the macro expansion. This
+ adds up to the memory overhead of the -ftrack-macro-expansion
+ flag; for every macro that is expanded, a "macro map" is
+ created. */
+ if (track_macro_exp_p)
+ {
+ int num_macro_tokens = total;
+ if (track_macro_exp_p < 2)
+ /* Then the number of macro tokens won't take in account the
+ fact that function-like macro arguments can expand to
+ multiple tokens. This is to save memory at the expense of
+ accuracy.
+
+ Suppose we have #define SQARE(A) A * A
+
+ And then we do SQARE(2+3)
+
+ Then the tokens 2, +, 3, will have the same location, saying they come
+ from the expansion of the argument A. */
+ num_macro_tokens = exp_count;
+ map = linemap_enter_macro (pfile->line_table, macro,
+ expansion_point_loc,
+ num_macro_tokens);
+ }
+ i = 0;
for (src = macro->exp.tokens; src < limit; src++)
{
- unsigned int count;
- const cpp_token **from, **paste_flag;
+ unsigned int arg_tokens_count;
+ macro_arg_token_iter from;
+ const cpp_token **paste_flag = NULL;
+ const cpp_token **tmp_token_ptr;
if (src->type != CPP_MACRO_ARG)
{
- *dest++ = src;
+ unsigned index = expanded_token_index (pfile, macro, src, i);
+ tokens_buff_append_token (pfile, buff, src,
+ src->src_loc, src->src_loc,
+ map, &index);
+ i += 1;
continue;
}
paste_flag = 0;
arg = &args[src->val.macro_arg.arg_no - 1];
if (src->flags & STRINGIFY_ARG)
- count = 1, from = &arg->stringified;
+ {
+ arg_tokens_count = 1;
+ macro_arg_token_iter_init (&from, pfile,
+ MACRO_ARG_TOKEN_STRINGIFIED,
+ arg, &arg->stringified);
+ }
else if (src->flags & PASTE_LEFT)
- count = arg->count, from = arg->first;
+ {
+ arg_tokens_count = arg->count;
+ macro_arg_token_iter_init (&from, pfile,
+ MACRO_ARG_TOKEN_NORMAL,
+ arg, arg->first);
+ }
else if (src != macro->exp.tokens && (src[-1].flags & PASTE_LEFT))
{
- count = arg->count, from = arg->first;
- if (dest != first)
+ int num_toks;
+ arg_tokens_count = arg->count;
+ macro_arg_token_iter_init (&from, pfile,
+ MACRO_ARG_TOKEN_NORMAL,
+ arg, arg->first);
+
+ num_toks = tokens_buff_count (pfile, buff);
+
+ if (num_toks != 0)
{
- if (dest[-1]->type == CPP_COMMA
+ tmp_token_ptr = tokens_buff_last_token_ptr (pfile, buff);
+
+ if ((*tmp_token_ptr)->type == CPP_COMMA
&& macro->variadic
&& src->val.macro_arg.arg_no == macro->paramc)
{
/* Swallow a pasted comma if from == NULL, otherwise
drop the paste flag. */
- if (from == NULL)
- dest--;
+ if (macro_arg_token_iter_get_token (&from) == NULL)
+ tokens_buff_remove_last_token (pfile, buff);
else
- paste_flag = dest - 1;
+ paste_flag = tmp_token_ptr;
}
- /* Remove the paste flag if the RHS is a placemarker. */
- else if (count == 0)
- paste_flag = dest - 1;
+ else if (arg_tokens_count == 0)
+ paste_flag = tmp_token_ptr;
}
}
else
- count = arg->expanded_count, from = arg->expanded;
+ {
+ arg_tokens_count = arg->expanded_count;
+ macro_arg_token_iter_init (&from, pfile,
+ MACRO_ARG_TOKEN_EXPANDED,
+ arg, arg->expanded);
+ }
/* Padding on the left of an argument (unless RHS of ##). */
if ((!pfile->state.in_directive || pfile->state.directive_wants_padding)
&& src != macro->exp.tokens && !(src[-1].flags & PASTE_LEFT))
- *dest++ = padding_token (pfile, src);
+ {
+ const cpp_token *t = padding_token (pfile, src);
+ unsigned index = expanded_token_index (pfile, macro, src, i);
+ tokens_buff_append_token (pfile, buff, t,
+ t->src_loc, t->src_loc,
+ map, &index);
+ }
- if (count)
+ if (arg_tokens_count)
{
- memcpy (dest, from, count * sizeof (cpp_token *));
- dest += count;
+ unsigned int j;
+ for (j = 0; j < arg_tokens_count; ++j)
+ {
+ /* So if track_macro_exp_p is < 2, the user wants to
+ save extra memory while tracking macro expansion locations.
+ So in that case here is what we do:
+
+ Suppose we have #define SQARE(A) A * A
+
+ And then we do SQARE(2+3)
+
+ Then the tokens 2, +, 3, will have the same location, saying they come
+ from the expansion of the argument A.
+
+ So that means we are going to ignore the COUNT tokens
+ resulting from the expansion of the current macro
+ arugment. In other words all the COUNT tokens resulting
+ from the expansion of the macro argument will have the
+ index I. Normally, each of those token should have
+ index I+J. */
+ unsigned token_index = i;
+ unsigned index;
+ if (track_macro_exp_p > 1)
+ token_index += j;
+
+ index = expanded_token_index (pfile, macro, src, token_index);
+ tokens_buff_append_token (pfile, buff,
+ macro_arg_token_iter_get_token (&from),
+ macro_arg_token_iter_get_location (&from),
+ src->src_loc, map, &index);
+ macro_arg_token_iter_forward (&from);
+ }
/* With a non-empty argument on the LHS of ##, the last
token should be flagged PASTE_LEFT. */
if (src->flags & PASTE_LEFT)
- paste_flag = dest - 1;
+ paste_flag =
+ (const cpp_token **) tokens_buff_last_token_ptr (pfile, buff);
}
else if (CPP_PEDANTIC (pfile) && ! macro->syshdr
&& ! CPP_OPTION (pfile, c99)
@@ -1050,7 +1613,11 @@ replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro, macro_arg
/* Avoid paste on RHS (even case count == 0). */
if (!pfile->state.in_directive && !(src->flags & PASTE_LEFT))
- *dest++ = &pfile->avoid_paste;
+ {
+ const cpp_token *t = &pfile->avoid_paste;
+ tokens_buff_append_token (pfile, buff, t, t->src_loc,
+ t->src_loc, NULL, NULL);
+ }
/* Add a new paste flag, or remove an unwanted one. */
if (paste_flag)
@@ -1064,6 +1631,8 @@ replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro, macro_arg
token->flags = (*paste_flag)->flags & ~PASTE_LEFT;
*paste_flag = token;
}
+
+ i += arg_tokens_count;
}
/* Free the expanded arguments. */
@@ -1071,7 +1640,12 @@ replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro, macro_arg
if (args[i].expanded)
free (args[i].expanded);
- push_ptoken_context (pfile, node, buff, first, dest - first);
+ if (track_macro_exp_p)
+ push_extended_tokens_context (pfile, node, buff, first,
+ tokens_buff_count (pfile, buff));
+ else
+ push_ptoken_context (pfile, node, buff, first,
+ tokens_buff_count (pfile, buff));
}
/* Return a special padding token, with padding inherited from SOURCE. */
@@ -1099,6 +1673,7 @@ next_context (cpp_reader *pfile)
if (result == 0)
{
result = XNEW (cpp_context);
+ memset (result, 0, sizeof (cpp_context));
result->prev = pfile->context;
result->next = 0;
pfile->context->next = result;
@@ -1115,7 +1690,7 @@ push_ptoken_context (cpp_reader *pfile, cpp_hashnode *macro, _cpp_buff *buff,
{
cpp_context *context = next_context (pfile);
- context->direct_p = false;
+ context->tokens_kind = TOKENS_KIND_INDIRECT;
context->macro = macro;
context->buff = buff;
FIRST (context).ptoken = first;
@@ -1127,13 +1702,30 @@ void
_cpp_push_token_context (cpp_reader *pfile, cpp_hashnode *macro,
const cpp_token *first, unsigned int count)
{
+ cpp_context *context = next_context (pfile);
+
+ context->tokens_kind = TOKENS_KIND_DIRECT;
+ context->macro = macro;
+ context->buff = NULL;
+ FIRST (context).token = first;
+ LAST (context).token = first + count;
+}
+
+/* Push a list of tokens. */
+static void
+push_extended_tokens_context (cpp_reader *pfile, cpp_hashnode *macro,
+ _cpp_buff *token_buff,
+ const cpp_token **first,
+ unsigned int count)
+{
cpp_context *context = next_context (pfile);
- context->direct_p = true;
+ context->tokens_kind = TOKENS_KIND_EXTENDED;
+ context->buff = token_buff;
context->macro = macro;
- context->buff = NULL;
- FIRST (context).token = first;
- LAST (context).token = first + count;
+ FIRST (context).ptoken = first;
+ LAST (context).ptoken =
+ macro_token_ptr_at (pfile, first, count);
}
/* Push a traditional macro's replacement text. */
@@ -1143,7 +1735,7 @@ _cpp_push_text_context (cpp_reader *pfile, cpp_hashnode *macro,
{
cpp_context *context = next_context (pfile);
- context->direct_p = true;
+ context->tokens_kind = TOKENS_KIND_DIRECT;
context->macro = macro;
context->buff = NULL;
CUR (context) = start;
@@ -1151,6 +1743,196 @@ _cpp_push_text_context (cpp_reader *pfile, cpp_hashnode *macro,
macro->flags |= NODE_DISABLED;
}
+/* Creates a buffer that holds tokens a.k.a "token buffer", usually
+ for the purpose of storing them on a cpp_context. If the
+ -ftrack-macro-expansion flag is in effect the buffer holds a set of
+ cpp_ext_token. Otherwise it holds a set of cpp_token*. */
+static _cpp_buff*
+tokens_buff_new (cpp_reader *pfile, size_t len)
+{
+ bool track_macro_exp_p = CPP_OPTION (pfile, track_macro_expansion);
+ size_t size =
+ track_macro_exp_p
+ ? len * sizeof (cpp_ext_token)
+ : len * sizeof (cpp_token *);
+
+ return _cpp_get_buff (pfile, size);
+}
+
+/* Returns the number of tokens contained in a token buffer. If the
+ -ftrack-macro-expansion flag is in effect the buffer holds a set of
+ cpp_ext_token. Otherwise it holds a set of cpp_token*. */
+static size_t
+tokens_buff_count (cpp_reader *pfile, _cpp_buff *buff)
+{
+ bool track_macro_exp_p = CPP_OPTION (pfile, track_macro_expansion);
+ size_t size =
+ track_macro_exp_p
+ ? sizeof (cpp_ext_token)
+ : sizeof (cpp_token *);
+
+ return (BUFF_FRONT (buff) - buff->base) / size;
+}
+
+/* Return a pointer to the last token contained in the token buffer
+ BUFF. If the -ftrack-macro-expansion flag is in effect the buffer
+ holds a set of cpp_ext_token. Otherwise it holds a set of
+ cpp_token*.*/
+static const cpp_token **
+tokens_buff_last_token_ptr (cpp_reader *pfile, _cpp_buff *buff)
+{
+ bool track_macro_exp_p = CPP_OPTION (pfile, track_macro_expansion);
+
+ if (track_macro_exp_p)
+ return &((cpp_ext_token *) BUFF_FRONT (buff))[-1].token;
+ return &((const cpp_token **) BUFF_FRONT (buff))[-1];
+}
+
+/* Remove the last token contained in the token buffer BUFF. If the
+ -ftrack-macro-expansion flag is in effect the buffer holds a set of
+ cpp_ext_token. Otherwise it holds a set of cpp_token*.*/
+static void
+tokens_buff_remove_last_token (cpp_reader *pfile, _cpp_buff *buff)
+{
+ bool track_macro_exp_p = CPP_OPTION (pfile, track_macro_expansion);
+
+ if (BUFF_FRONT (buff) > buff->base)
+ {
+ if (track_macro_exp_p)
+ BUFF_FRONT (buff) =
+ (unsigned char *) &((cpp_ext_token *) BUFF_FRONT (buff))[-1];
+ else
+ BUFF_FRONT (buff) =
+ (unsigned char *) &((const cpp_token **) BUFF_FRONT (buff))[-1];
+ }
+}
+
+/* Insert a token into the token buffer at the position pointed to by
+ DEST. Note that the buffer is not enlarged so the previous token
+ that was at *DEST is overwritten. TOKEN is the token to
+ insert. DEF_LOC is the full location of the token, i.e, the
+ location possibly encoding its locus accross macro expansion. If
+ TOKEN is an argument of a function like macro (inside a macro
+ replacement list), PARM_DEF_LOC is the location of the macro
+ parameter that TOKEN is replacing. If TOKEN doesn't come from a
+ macro expansion, then PARM_DEF_LOC can just be set to the same
+ value as DEF_LOC. If MAP is non null, it means TOKEN comes from a
+ macro expansion and MAP is the macro map associated to the
+ macro. MACRO_TOKEN_INDEX points to the index of the token in the
+ macro map; It is not considered if MAP is NULL. Upon successful
+ completion this function returns the a pointer to the position of
+ the token coming right after the insertion point.
+
+ If the -ftrack-macro-expansion flag is in effect the buffer holds a
+ set of cpp_ext_token. Otherwise it holds a set of cpp_token*. */
+static inline const cpp_token **
+tokens_buff_put_token_to (cpp_reader *pfile,
+ const cpp_token **dest,
+ const cpp_token *token,
+ source_location def_loc,
+ source_location parm_def_loc,
+ const struct line_map *map,
+ unsigned int *macro_token_index)
+{
+ bool track_macro_exp_p = CPP_OPTION (pfile, track_macro_expansion);
+ source_location macro_loc = def_loc;
+ const cpp_token **result;
+
+ if (track_macro_exp_p)
+ {
+ cpp_ext_token *token_dest = (cpp_ext_token *) dest;
+ if (map)
+ macro_loc = linemap_add_macro_token (map, *macro_token_index,
+ def_loc, parm_def_loc);
+ token_dest->token = token;
+ token_dest->location = macro_loc;
+ result = &token_dest[1].token;
+ }
+ else
+ {
+ *dest = token;
+ result = &dest[1];
+ }
+ return result;
+}
+
+/* Appends a token to the end of the token buffer BUFFER. TOKEN is
+ the token to append. DEF_LOC is the full location of the token,
+ i.e, the location possibly encoding its locus accross macro
+ expansion. If TOKEN is an argument of a function like macro (inside
+ a macro replacement list), PARM_DEF_LOC is the location of the
+ macro parameter that TOKEN is replacing. If TOKEN doesn't come
+ from a macro expansion, then PARM_DEF_LOC can just be set to the
+ same value as DEF_LOC. If MAP is non null, it means TOKEN comes
+ from a macro expansion and MAP is the macro map associated to the
+ macro. MACRO_TOKEN_INDEX points to the index of the token in the
+ macro map; It is not considered if MAP is NULL. Upon successful
+ completion this function returns the a pointer to the position of
+ the token coming right after the insertion point.
+
+ If the -ftrack-macro-expansion flag is in effect the buffer holds a
+ set of cpp_ext_token. Otherwise it holds a set of cpp_token*.
+ */
+static const cpp_token **
+tokens_buff_append_token (cpp_reader *pfile,
+ _cpp_buff *buffer,
+ const cpp_token *token,
+ source_location def_loc,
+ source_location parm_def_loc,
+ const struct line_map *map,
+ unsigned int *macro_token_index)
+{
+ const cpp_token **result;
+
+ result =
+ tokens_buff_put_token_to (pfile,
+ (const cpp_token **) BUFF_FRONT (buffer),
+ token, def_loc, parm_def_loc,
+ map, macro_token_index);
+
+ BUFF_FRONT (buffer) = (unsigned char *) result;
+ return result;
+}
+
+/* Allocate space for the function-like macro argument ARG to store
+ the tokens resulting from the macro-expansion of the tokens that
+ make up ARG itself. That space is allocated in ARG->expanded and
+ needs to be freed using free. */
+static void
+alloc_expanded_args_mem (cpp_reader *pfile, macro_arg *arg, size_t capacity)
+{
+ bool track_macro_exp_p = CPP_OPTION (pfile, track_macro_expansion);
+
+ if (track_macro_exp_p)
+ arg->expanded = (const cpp_token **) XNEWVEC (cpp_ext_token, capacity);
+ else
+ arg->expanded = XNEWVEC (const cpp_token *, capacity);
+
+ arg->expanded_capacity = capacity;
+}
+
+/* If necessary, enlarge ARG->expanded to so that it can contain SIZE
+ more tokens. */
+static void
+ensure_expanded_args_room (cpp_reader *pfile, macro_arg *arg, size_t size)
+{
+ bool track_macro_exp_p;
+
+ if (size <= arg->expanded_capacity)
+ return;
+
+ size *= 2;
+ track_macro_exp_p = CPP_OPTION (pfile, track_macro_expansion);
+
+ if (track_macro_exp_p)
+ arg->expanded = (const cpp_token **)
+ XRESIZEVEC (cpp_ext_token, arg->expanded, size);
+ else
+ arg->expanded =
+ XRESIZEVEC (const cpp_token *, arg->expanded, size);
+ arg->expanded_capacity = size;
+}
+
/* Expand an argument ARG before replacing parameters in a
function-like macro. This works by pushing a context with the
argument's tokens, and then expanding that into a temporary buffer
@@ -1162,6 +1944,7 @@ expand_arg (cpp_reader *pfile, macro_arg *arg)
{
unsigned int capacity;
bool saved_warn_trad;
+ bool track_macro_exp_p = CPP_OPTION (pfile, track_macro_expansion);
if (arg->count == 0)
return;
@@ -1172,26 +1955,30 @@ expand_arg (cpp_reader *pfile, macro_arg *arg)
/* Loop, reading in the arguments. */
capacity = 256;
- arg->expanded = XNEWVEC (const cpp_token *, capacity);
+ alloc_expanded_args_mem (pfile, arg, capacity);
+
+ if (track_macro_exp_p)
+ push_extended_tokens_context (pfile, NULL, NULL,
+ arg->first, arg->count + 1);
+ else
+ push_ptoken_context (pfile, NULL, NULL,
+ arg->first, arg->count + 1);
- push_ptoken_context (pfile, NULL, NULL, arg->first, arg->count + 1);
for (;;)
{
const cpp_token *token;
+ source_location location;
- if (arg->expanded_count + 1 >= capacity)
- {
- capacity *= 2;
- arg->expanded = XRESIZEVEC (const cpp_token *, arg->expanded,
- capacity);
- }
+ ensure_expanded_args_room (pfile, arg, arg->expanded_count + 1);
- token = cpp_get_token (pfile);
+ token = cpp_get_token_1 (pfile, &location);
if (token->type == CPP_EOF)
break;
- arg->expanded[arg->expanded_count++] = token;
+ set_arg_token (pfile, arg, token, location,
+ arg->expanded_count, MACRO_ARG_TOKEN_EXPANDED);
+ arg->expanded_count++;
}
_cpp_pop_context (pfile);
@@ -1200,8 +1987,9 @@ expand_arg (cpp_reader *pfile, macro_arg *arg)
}
/* Pop the current context off the stack, re-enabling the macro if the
- context represented a macro's replacement list. The context
- structure is not freed so that we can re-use it later. */
+ context represented a macro's replacement list. Initially the
+ context structure was not freed so that we can re-use it later, but
+ now we do free it to reduce peak memory consumption. */
void
_cpp_pop_context (cpp_reader *pfile)
{
@@ -1211,14 +1999,85 @@ _cpp_pop_context (cpp_reader *pfile)
context->macro->flags &= ~NODE_DISABLED;
if (context->buff)
- _cpp_release_buff (pfile, context->buff);
+ {
+ /* Decrease memory peak consumption by freeing the memory used
+ by the context. */
+ _cpp_free_buff (context->buff);
+ }
pfile->context = context->prev;
+ /* decrease peak memory consumption by feeing the context. */
+ pfile->context->next = NULL;
+ free (context);
}
-/* External routine to get a token. Also used nearly everywhere
- internally, except for places where we know we can safely call
- _cpp_lex_token directly, such as lexing a directive name.
+/* Return TRUE if we reached the end of the set of tokens stored in
+ CONTEXT, FALSE otherwise. */
+static bool
+reached_end_of_context (cpp_context *context)
+{
+ if (context->tokens_kind == TOKENS_KIND_DIRECT)
+ return FIRST (context).token == LAST (context).token;
+ else if (context->tokens_kind == TOKENS_KIND_INDIRECT
+ || context->tokens_kind == TOKENS_KIND_EXTENDED)
+ return FIRST (context).ptoken == LAST (context).ptoken;
+ else
+ abort ();
+}
+
+/* Consume the next token contained in the current context of PFILE,
+ and return it in *TOKEN. It's "full location" is returned in
+ *LOCATION. If -ftrack-macro-location is in effeect, fFull location"
+ means the location encoding the locus of the token accross macro
+ expansion; otherwise it's just is the "normal" location of the
+ token which (*TOKEN)->src_loc. */
+static void
+consume_next_token_from_context (cpp_reader *pfile,
+ const cpp_token ** token,
+ source_location *location)
+{
+ cpp_context *c = pfile->context;
+
+ if ((c)->tokens_kind == TOKENS_KIND_DIRECT)
+ {
+ *token = FIRST (c).token;
+ *location = (*token)->src_loc;
+ FIRST (c).token++;
+ }
+ else if ((c)->tokens_kind == TOKENS_KIND_INDIRECT)
+ {
+ *token = *FIRST (c).ptoken;
+ *location = (*token)->src_loc;
+ FIRST (c).ptoken++;
+ }
+ else if ((c)->tokens_kind == TOKENS_KIND_EXTENDED)
+ {
+ *token = ((cpp_ext_token *) FIRST (c).ptoken)->token;
+ *location = ((cpp_ext_token *) FIRST (c).ptoken)->location;
+ FIRST (c).ptoken = next_macro_token_ptr (pfile, FIRST (c).ptoken);
+ }
+ else
+ abort ();
+}
+
+/* In the traditionnal mode of the preprocessor, if we are currently
+ in a directive, the location of a token must be the location of the
+ start of the directive line. This function returns the proper
+ location if we are in the traditionnal mode, and just returns
+ LOCATION otherwise. */
+
+static inline source_location
+maybe_adjust_loc_for_trad_cpp (cpp_reader *pfile, source_location location)
+{
+ if (CPP_OPTION (pfile, traditional))
+ {
+ if (pfile->state.in_directive)
+ return pfile->directive_line;
+ }
+ return location;
+}
+
+/* Routine to get a token as well as its location.
Macro expansions and directives are transparently handled,
including entering included files. Thus tokens are post-macro
@@ -1226,12 +2085,40 @@ _cpp_pop_context (cpp_reader *pfile)
see CPP_EOF only at EOF. Internal callers also see it when meeting
a directive inside a macro call, when at the end of a directive and
state.in_directive is still 1, and at the end of argument
- pre-expansion. */
-const cpp_token *
-cpp_get_token (cpp_reader *pfile)
+ pre-expansion.
+
+ LOC is an out parameter; *LOC is set to the location "as expected
+ by the user". This matters when a token results from macro
+ expansion -- the token's location will indicate where the macro is
+ defined (the spelling location of the token) but *LOC will be a
+ virtual location of the token. Virtual location means a location
+ that possibly encodes many types of locus at once. A virtual
+ location can encode the location of a token resulting from macro
+ expansion or not. If the token results from macro expansion its
+ virtual location encodes (at the same time):
+ - the spelling location of the token
+ - the locus of the macro expansion point
+ - the locus the point where the token got instantiated as part of
+ the macro expansion process.
+ (YES, IT ENCODES ALL THESE THREE AT THE SAME TIME! and maybe more.)
+
+ You can learn more about the different locuses encoded in a map by
+ reading the extensive comments of the line_map_macro and line_map
+ structs in line-map.h. A virtual location, indeed.
+
+ The linemap API can then be used to retrieve the particular locus
+ we are interested in.
+
+ Otherwise *LOC is set to the same location as the location carried
+ by the returned token. */
+static const cpp_token*
+cpp_get_token_1 (cpp_reader *pfile, source_location *location)
{
const cpp_token *result;
bool can_set = pfile->set_invocation_location;
+ /* This token is a virtual token that either encodes a location
+ related to macro expansion or a spelling location. */
+ source_location virt_loc = 0;
pfile->set_invocation_location = false;
for (;;)
@@ -1241,20 +2128,23 @@ cpp_get_token (cpp_reader *pfile)
/* Context->prev == 0 <=> base context. */
if (!context->prev)
- result = _cpp_lex_token (pfile);
- else if (FIRST (context).token != LAST (context).token)
{
- if (context->direct_p)
- result = FIRST (context).token++;
- else
- result = *FIRST (context).ptoken++;
-
+ result = _cpp_lex_token (pfile);
+ virt_loc = result->src_loc;
+ }
+ else if (!reached_end_of_context (context))
+ {
+ consume_next_token_from_context (pfile, &result,
+ &virt_loc);
if (result->flags & PASTE_LEFT)
{
paste_all_tokens (pfile, result);
if (pfile->state.in_directive)
continue;
- return padding_token (pfile, result);
+ result = padding_token (pfile, result);
+ if (location)
+ *location = result->src_loc;
+ return result;
}
}
else
@@ -1262,6 +2152,8 @@ cpp_get_token (cpp_reader *pfile)
_cpp_pop_context (pfile);
if (pfile->state.in_directive)
continue;
+ if (location)
+ *location = pfile->avoid_paste.src_loc;
return &pfile->avoid_paste;
}
@@ -1299,7 +2191,8 @@ cpp_get_token (cpp_reader *pfile)
|| (peek_tok->flags & PREV_WHITE));
node = pfile->cb.macro_to_expand (pfile, result);
if (node)
- ret = enter_macro_context (pfile, node, result);
+ ret = enter_macro_context (pfile, node, result,
+ virt_loc);
else if (whitespace_after)
{
/* If macro_to_expand hook returned NULL and it
@@ -1316,12 +2209,16 @@ cpp_get_token (cpp_reader *pfile)
}
}
else
- ret = enter_macro_context (pfile, node, result);
+ ret = enter_macro_context (pfile, node, result,
+ virt_loc);
if (ret)
{
if (pfile->state.in_directive || ret == 2)
continue;
- return padding_token (pfile, result);
+ result = padding_token (pfile, result);
+ if (location)
+ *location = result->src_loc;
+ return result;
}
}
else
@@ -1338,27 +2235,74 @@ cpp_get_token (cpp_reader *pfile)
break;
}
- return result;
+ if (location)
+ *location = virt_loc;
+ return result;
}
-/* Like cpp_get_token, but also returns a location separate from the
- one provided by the returned token. LOC is an out parameter; *LOC
- is set to the location "as expected by the user". This matters
- when a token results from macro expansion -- the token's location
- will indicate where the macro is defined, but *LOC will be the
- location of the start of the expansion. */
+/* External routine to get a token. Also used nearly everywhere
+ internally, except for places where we know we can safely call
+ _cpp_lex_token directly, such as lexing a directive name.
+
+ Macro expansions and directives are transparently handled,
+ including entering included files. Thus tokens are post-macro
+ expansion, and after any intervening directives. External callers
+ see CPP_EOF only at EOF. Internal callers also see it when meeting
+ a directive inside a macro call, when at the end of a directive and
+ state.in_directive is still 1, and at the end of argument
+ pre-expansion. */
+const cpp_token *
+cpp_get_token (cpp_reader *pfile)
+{
+ return cpp_get_token_1 (pfile, NULL);
+}
+
+/* Like cpp_get_token, but also returns a virtual token location
+ separate from the spelling location carried by the returned token.
+
+ LOC is an out parameter; *LOC is set to the location "as expected
+ by the user". This matters when a token results from macro
+ expansion; in that case the token's spelling location indicates the
+ locus of the token in the definition of the macro but *LOC
+ virtually encodes all the other meaningful locuses associated to
+ the token.
+
+ What? virtual location? Yes, virtual location.
+
+ If the token results from macro expansion and if macro expansion
+ location tracking is enbled its virtual location encodes (at the
+ same time):
+
+ - the spelling location of the token the locus of the macro
+ - expansion point the locus the point where the token got
+ - instantiated as part of the macro expansion process.
+
+ You have to use the linemap API to get the locus you are interested
+ in from a given virtual location.
+
+ If macro expansion tracking is off and if the token results from
+ macro expansion the virtual location is the expansion point of the
+ macro that got expanded.
+
+ When the token doesn't result from macro expansion, the virtual
+ location is just the same thing as its spelling location. */
+
const cpp_token *
cpp_get_token_with_location (cpp_reader *pfile, source_location *loc)
{
const cpp_token *result;
pfile->set_invocation_location = true;
- result = cpp_get_token (pfile);
+ result = cpp_get_token_1 (pfile, loc);
if (pfile->context->macro)
- *loc = pfile->invocation_location;
+ {
+ if (!CPP_OPTION (pfile, track_macro_expansion))
+ *loc = pfile->invocation_location;
+ }
else
*loc = result->src_loc;
+ *loc = maybe_adjust_loc_for_trad_cpp (pfile, *loc);
return result;
}
@@ -1425,10 +2369,15 @@ _cpp_backup_tokens (cpp_reader *pfile, unsigned int count)
{
if (count != 1)
abort ();
- if (pfile->context->direct_p)
+ if (pfile->context->tokens_kind == TOKENS_KIND_DIRECT)
FIRST (pfile->context).token--;
- else
+ else if (pfile->context->tokens_kind == TOKENS_KIND_INDIRECT)
FIRST (pfile->context).ptoken--;
+ else if (pfile->context->tokens_kind == TOKENS_KIND_EXTENDED)
+ FIRST (pfile->context).ptoken =
+ prev_macro_token_ptr (pfile, FIRST (pfile->context).ptoken);
+ else
+ abort ();
}
}