aboutsummaryrefslogtreecommitdiff
path: root/libcpp
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2018-09-25 01:02:42 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2018-09-25 01:02:42 +0000
commit5055f108385c076346b3b279788dc0129549b11f (patch)
tree91456c9f0ec368308f734e6d649b046d57a19114 /libcpp
parent414925ab0cb8d0aea39cb3383b18f72f3ce887a0 (diff)
parent44eb8fa73bb53afa17e4d72b1c073d0e08a76866 (diff)
downloadgcc-5055f108385c076346b3b279788dc0129549b11f.zip
gcc-5055f108385c076346b3b279788dc0129549b11f.tar.gz
gcc-5055f108385c076346b3b279788dc0129549b11f.tar.bz2
Merge from trunk revision 264547.
From-SVN: r264554
Diffstat (limited to 'libcpp')
-rw-r--r--libcpp/ChangeLog221
-rw-r--r--libcpp/Makefile.in5
-rw-r--r--libcpp/directives.c236
-rw-r--r--libcpp/expr.c22
-rw-r--r--libcpp/files.c2
-rw-r--r--libcpp/identifiers.c4
-rw-r--r--libcpp/include/cpp-id-data.h82
-rw-r--r--libcpp/include/cpplib.h174
-rw-r--r--libcpp/include/line-map.h218
-rw-r--r--libcpp/init.c3
-rw-r--r--libcpp/internal.h33
-rw-r--r--libcpp/lex.c21
-rw-r--r--libcpp/line-map.c180
-rw-r--r--libcpp/macro.c648
-rw-r--r--libcpp/pch.c121
-rw-r--r--libcpp/traditional.c87
16 files changed, 1146 insertions, 911 deletions
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index c72804f..ef96824 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,216 @@
+2018-09-17 David Malcolm <dmalcolm@redhat.com>
+
+ * include/line-map.h (range_label::get_text): Add param
+ "range_idx".
+
+2018-08-30 Nathan Sidwell <nathan@acm.org>
+
+ * include/line-map.h (enum lc_reason): Comment each member
+ separately.
+ (struct line_maps): Fix reallocator comment.
+
+2018-08-27 David Malcolm <dmalcolm@redhat.com>
+
+ PR 87091
+ * include/line-map.h (enum range_display_kind): New enum.
+ (struct location_range): Replace field "m_show_caret_p" with
+ "m_range_display_kind", converting from bool to the new enum.
+ (class rich_location): Add example of line insertion fix-it hint.
+ (rich_location::add_range): Convert param "show_caret_p" from bool
+ to enum range_display_kind and rename to "range_display_kind",
+ giving it a default of SHOW_RANGE_WITHOUT_CARET.
+ (rich_location::set_range): Likewise, albeit without a default.
+ * line-map.c (rich_location::rich_location): Update for conversion
+ of show_caret_p to tri-state enum.
+ (rich_location::add_range): Likewise.
+ (rich_location::set_range): Likewise.
+
+2018-08-24 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR bootstrap/86872
+ * line-map.c (pure_location_p): Return true if linemap_lookup
+ returns NULL.
+ (linemap_add): Set start_location to 0 if we run out of line map
+ space.
+
+2018-08-20 Nathan Sidwell <nathan@acm.org>
+
+ * include/cpplib.h: Fixup some whitespace.
+ (cpp_hashnode): Reduce type to 2 bit & flags to 8.
+
+ * include/cpplib.h (NODE_BUILTIN, NODE_MACRO_ARG): Delete.
+ Renumber others.
+ (enum node_type): Replace NT_MACRO with NT_USER_MACRO,
+ NT_BUILTIN_MACRO, NT_MACRO_ARG. Delete NT_ASSERTION.
+ (NTV_MACRO, NTV_ANSWER, NTV_BUILTIN, NTV_ARGUMENT, NTV_NONE):
+ Delete.
+ (CPP_HASHNODE_VALUE_IDX): Delete.
+ (union _cpp_hashnode_value): GTY tag from enum node_type directly.
+ (struct cpp_hashnode): Adjust GTY desc for value field.
+ (cpp_user_macro_p, cpp_builtin_macro_p, cpp_macro_p): Adjust.
+ * directives.c (undefine_macros): Clear value.anwers, adjust flag
+ clearing.
+ (_cpp_test_assertion): No need to check NT_ASSERTION.
+ (do_assert, do_unassert): Likewise.
+ * init.c (cpp_init_special_builtins): Set type not flags.
+ * macro.c (struct macro_arg_saved_data): Add type field.
+ (cpp_get_token_1): Check type not NT_VOID.
+ (_cpp_free_definition): Adjust flag clearing. Nullify
+ value.answers.
+ (_cpp_save_parameter, _cpp_unsave_parameters): Save and restore
+ type.
+ (lex_expansion_token): Check type not flags.
+ (_cpp_create_definition): Set type to NT_USER_MACRO.
+ (_cpp_notify_macro_use): Adjust type checking.
+ * pch.c (write_macdef, count_defs, write_defs, cpp_valid_state)
+ (save_macros): Adjust node type/flag handling.
+ * traditional.c (_cpp_scan_out_logical_line): Check type not flags.
+
+ * directives.c (do_undef): Use cpp_macro_p & cpp_builtin_macro_p.
+ * include/cpplib.h (enum cpp_macro_kind): Remove trailing comma.
+ (cpp_fun_like_macro_p): Make inline, define.
+ * macro.c (cpp_define_lazily): Use UCHAR_MAX.
+ (cpp_fun_like_macro_p): Delete.
+
+ * Makefile.in (TAGS_SOURCES): Remove cpp-id-data.h.
+ * include/cpp-id-data.h: Delete.
+ * internal.h: Include cpplib.h not cpp-id-data.h.
+
+ * include/cpp-id-data.h (struct answer): Delete.
+ * include/cpplib.h (struct answer): Don't forward-declare.
+ (enum cpp_macro_kind): Add cmk_assert.
+ (struct cpp_macro): Union parms and next assert chain.
+ (union _cpp_hashnode_value): 'answer' field is cpp_macro.
+ * directives.c (parse_answer): Convert to use cpp_macro. Return
+ true on success.
+ (parse_assertion, find_answer, _cpp_test_assertion, cpp_do_assert)
+ (cpp_do_unassert): Convert to use cpp_macro.
+ * macro.c (warn_of_redefinition, _cpp_new_macro)
+ (check_trad_stringification, cpp_macro_definition): Adjust macro
+ parm access.
+ * traditional.c (_cpp_replacement_text_len)
+ (_cpp_copy_replacement_text, _cpp_create_trad_definition): Likewise.
+
+2018-08-17 Nathan Sidwell <nathan@acm.org>
+
+ * include/cpplib.h (struct cpp_callbacks): Replace
+ user_builtin_macro with user_lazy_macro.
+ (struct cpp_macro): add lazy field.
+ (enum cpp_builtin_type): Remove BT_FIRST_USER, BT_LAST_USER.
+ (cpp_define_lazily): Declare.
+ * macro.c (enter_macro_context) Use _cpp_maybe_notify_macro_use.
+ (warn_of_redefinition): Use cpp_builtin_macro_p, directly call
+ user_lazy_macro hook.
+ (_cpp_new_macro): Clear lazy field.
+ (cpp_define_lazily): Define.
+ (_cpp_notify_macro_use): Adjust lazy definition code.
+ (cpp_macro_definition): No need to do lazy definition here.
+ * pch.c (write_macdef, save_macros): Likewise.
+
+ * include/cpplib.h (enum cpp_macro_kind): New.
+ (struct cpp_macro): Make body trailing array. Add kind field,
+ delete traditional flag.
+ * internal.h (_cpp_new_macro): Declare.
+ (_cpp_reserve_room): New inline.
+ (_cpp_commit_buf): Declare.
+ (_cpp_create_trad_definition): Return new macro.
+ * lex.c (_cpp_commit_buff): New.
+ * macro.c (macro_real_token_count): Count backwards.
+ (replace_args): Pointer equality not orderedness.
+ (_cpp_save_parameter): Use _cpp_reserve_room.
+ (alloc_expansion_token): Delete.
+ (lex_expansion_token): Return macro pointer. Use _cpp_reserve_room.
+ (create_iso_definition): Allocate macro itself. Adjust for
+ different allocation ordering.
+ (_cpp_new_macro): New.
+ (_cpp_create_definition): Adjust for API changes.
+ * traditional.c (push_replacement_text): Don't set traditional
+ flag.
+ (save_replacement_text): Likewise.
+ (_cpp_create_trad_definition): Allocate macro itself, Adjust for
+ different allocation ordering.
+
+ * cpp-id-data.h (uchar, UC): Move to internal.h
+ (struct cpp_macro): Move to cpplib.h.
+ * internal.h (uchar, UC): From cpp-id-data.h.
+ * include/cpplib.h (struct cpp_macro): From cpp-id-data.h.
+
+2018-08-16 Nathan Sidwell <nathan@acm.org>
+
+ * internal.h (_cpp_save_parameter): Take parmno, not macro.
+ (_cpp_unsave_parameters): Declare.
+ * macro.c (_cpp_save_parameter): Take parm number, not macro.
+ Return true on success.
+ (_cpp_unsave_parameters): New.
+ (parse_params): Take parm_no and variadic pointers, not macro.
+ Reimplement parsing logic.
+ (create_iso_definition): Adjust parse_params changes. Call
+ _cpp_unsave_parameters here.
+ (_cpp_create_definition): Don't unsave params here.
+ * traditional.c (scan_parameters): Take n_param pointer, adjust.
+ (_cpp_create_trad_definition): Ajust scan_parameters change. Call
+ _cpp_unsave_parameters.
+
+ * include/cpplib.h (cpp_user_macro_p, cpp_builtin_macro_p)
+ (cpp_macro_p): New inlines.
+ * directives.c (do_pragma_poison): Use cpp_macro_p.
+ (do_ifdef, do_ifndef): Likewise. Use _cpp_maybe_notify_macro_use.
+ (cpp_pop_definition): Use cpp_macro_p. Move _cpp_free_definition
+ earlier. Don't zap node directly.
+ * expr.c (parse_defined): Use _cpp_maybe_notify_macro_use &
+ cpp_macro_p.
+ * files.c (should_stack_file): Use cpp_macro_p.
+ * identifiers.c (cpp_defined): Likewise.
+ * internal.h (_cpp_mark_macro): Use cpp_user_macro_p.
+ (_cpp_notify_macro_use): Declare.
+ (_cpp_maybe_notify_macro_use): New inline.
+ * lex.c (is_macro): Use cpp_macro_p.
+ * macro.c (_cpp_warn_if_unused_macro): Use cpp_user_macro_p.
+ (enter_macro_context): Likewise.
+ (_cpp_create_definition): Use cpp_builtin_macro_p,
+ cpp_user_macro_p. Move _cpp_free_definition earlier.
+ (_cpp_notify_macro_use): New, broken out of multiple call sites.
+ * traditional.c (fun_like_macro_p): Use cpp_builtin_macro_p.
+ (maybe_start_funlike, _cpp_scan_out_logical_line)
+ (push_replacement_text): Likewise.
+
+2018-08-15 David Malcolm <dmalcolm@redhat.com>
+
+ * include/line-map.h (struct location_range): Add "m_label" field.
+ (class rich_location): Add description of labels to leading
+ comment.
+ (rich_location::rich_location): Add "label" param, defaulting to
+ NULL.
+ (rich_location::add_range): Likewise.
+ (struct label_text): New struct.
+ (class range_label): New abstract base class.
+ * line-map.c (rich_location::rich_location): Add "label" param;
+ use it.
+ (rich_location::add_range): Likewise.
+
+2018-08-08 Nathan Sidwell <nathan@acm.org>
+
+ Make linemap::included_from a location
+ libcpp/
+ * include/line-map.h (struct line_map_ordinary): Replace
+ included_from map index with included_at source_location.
+ (ORDINARY_MAP_INCLUDER_FILE_INDEX): Delete.
+ (LAST_SOURCE_LINE_LOCATION): Delete.
+ (LAST_SOURCE_LINE, LAST_SOURCE_COLUMN): Delete.
+ (linemap_included_from): New.
+ (linemap_included_from_linemap): Declare.
+ (MAIN_FILE_P): Adjust.
+ * line-map.c (linemap_included_from_linemap): New.
+ (lonemap_check_files_exited): Use linemap_included_at.
+ (linemap_add): Adjust inclusion setting.
+ (linemap_dump, linemap_dump_location): Adjust.
+ * directives.c (do_linemarker): Use linemap_included_at.
+
+2018-08-07 Nathan Sidwell <nathan@acm.org>
+
+ * line-map.c: (linemap_init): Set default allocator here.
+ (new_linemap): Rather than here. Refactor allocation logic.
+
2018-07-20 David Malcolm <dmalcolm@redhat.com>
* include/line-map.h (rich_location::set_range): Remove redundant
@@ -94,10 +307,10 @@
2018-01-18 Boris Kolpackov <boris@codesynthesis.com>
- PR other/70268
- * include/cpplib.h (cpp_callbacks::remap_filename): New callback.
- * macro.c (_cpp_builtin_macro_text): Call remap_filename for
- __FILE__ and __BASE_FILE__.
+ PR other/70268
+ * include/cpplib.h (cpp_callbacks::remap_filename): New callback.
+ * macro.c (_cpp_builtin_macro_text): Call remap_filename for
+ __FILE__ and __BASE_FILE__.
2018-01-10 Kelvin Nilsen <kelvin@gcc.gnu.org>
diff --git a/libcpp/Makefile.in b/libcpp/Makefile.in
index bfd6069..835c835 100644
--- a/libcpp/Makefile.in
+++ b/libcpp/Makefile.in
@@ -261,9 +261,8 @@ po/$(PACKAGE).pot: $(libcpp_a_SOURCES)
sed 's:$(srcdir)/::g' <po/$(PACKAGE).pot.tmp >po/$(PACKAGE).pot
rm po/$(PACKAGE).pot.tmp
-TAGS_SOURCES = $(libcpp_a_SOURCES) internal.h ucnid.h \
- include/line-map.h include/symtab.h include/cpp-id-data.h \
- include/cpplib.h include/mkdeps.h system.h
+TAGS_SOURCES = $(libcpp_a_SOURCES) internal.h system.h ucnid.h \
+ include/cpplib.h include/line-map.h include/mkdeps.h include/symtab.h
TAGS: $(TAGS_SOURCES)
cd $(srcdir) && etags $(TAGS_SOURCES)
diff --git a/libcpp/directives.c b/libcpp/directives.c
index bf13ada..f7c460d 100644
--- a/libcpp/directives.c
+++ b/libcpp/directives.c
@@ -124,9 +124,9 @@ static const cpp_token *get_token_no_padding (cpp_reader *);
static const cpp_token *get__Pragma_string (cpp_reader *);
static void destringize_and_run (cpp_reader *, const cpp_string *,
source_location);
-static int parse_answer (cpp_reader *, struct answer **, int, source_location);
-static cpp_hashnode *parse_assertion (cpp_reader *, struct answer **, int);
-static struct answer ** find_answer (cpp_hashnode *, const struct answer *);
+static bool parse_answer (cpp_reader *, int, source_location, cpp_macro **);
+static cpp_hashnode *parse_assertion (cpp_reader *, int, cpp_macro **);
+static cpp_macro **find_answer (cpp_hashnode *, const cpp_macro *);
static void handle_assertion (cpp_reader *, const char *, int);
static void do_pragma_push_macro (cpp_reader *);
static void do_pragma_pop_macro (cpp_reader *);
@@ -665,12 +665,12 @@ do_undef (cpp_reader *pfile)
/* 6.10.3.5 paragraph 2: [#undef] is ignored if the specified
identifier is not currently defined as a macro name. */
- if (node->type == NT_MACRO)
+ if (cpp_macro_p (node))
{
if (node->flags & NODE_WARN)
cpp_error (pfile, CPP_DL_WARNING,
"undefining \"%s\"", NODE_NAME (node));
- else if ((node->flags & NODE_BUILTIN)
+ else if (cpp_builtin_macro_p (node)
&& CPP_OPTION (pfile, warn_builtin_macro_redefined))
cpp_warning_with_line (pfile, CPP_W_BUILTIN_MACRO_REDEFINED,
pfile->directive_line, 0,
@@ -695,7 +695,8 @@ undefine_macros (cpp_reader *pfile ATTRIBUTE_UNUSED, cpp_hashnode *h,
/* Body of _cpp_free_definition inlined here for speed.
Macros and assertions no longer have anything to free. */
h->type = NT_VOID;
- h->flags &= ~(NODE_POISONED|NODE_BUILTIN|NODE_DISABLED|NODE_USED);
+ h->value.answers = NULL;
+ h->flags &= ~(NODE_POISONED|NODE_DISABLED|NODE_USED);
return 1;
}
@@ -1088,10 +1089,10 @@ do_linemarker (cpp_reader *pfile)
/* Reread map since cpp_get_token can invalidate it with a
reallocation. */
map = LINEMAPS_LAST_ORDINARY_MAP (line_table);
- const line_map_ordinary *from;
+ const line_map_ordinary *from
+ = linemap_included_from_linemap (line_table, map);
if (MAIN_FILE_P (map)
- || (new_file
- && (from = INCLUDED_FROM (pfile->line_table, map)) != NULL
+ || (from
&& filename_cmp (ORDINARY_MAP_FILE_NAME (from), new_file) != 0))
{
cpp_warning (pfile, CPP_W_NONE,
@@ -1666,7 +1667,7 @@ do_pragma_poison (cpp_reader *pfile)
if (hp->flags & NODE_POISONED)
continue;
- if (hp->type == NT_MACRO)
+ if (cpp_macro_p (hp))
cpp_error (pfile, CPP_DL_WARNING, "poisoning existing macro \"%s\"",
NODE_NAME (hp));
_cpp_free_definition (hp);
@@ -1960,26 +1961,9 @@ do_ifdef (cpp_reader *pfile)
the powerpc and spu ports using conditional macros for 'vector',
'bool', and 'pixel' to act as conditional keywords. This messes
up tests like #ifndef bool. */
- skip = (node->type != NT_MACRO
- || ((node->flags & NODE_CONDITIONAL) != 0));
+ skip = !cpp_macro_p (node) || (node->flags & NODE_CONDITIONAL);
_cpp_mark_macro_used (node);
- if (!(node->flags & NODE_USED))
- {
- node->flags |= NODE_USED;
- if (node->type == NT_MACRO)
- {
- if ((node->flags & NODE_BUILTIN)
- && pfile->cb.user_builtin_macro)
- pfile->cb.user_builtin_macro (pfile, node);
- if (pfile->cb.used_define)
- pfile->cb.used_define (pfile, pfile->directive_line, node);
- }
- else
- {
- if (pfile->cb.used_undef)
- pfile->cb.used_undef (pfile, pfile->directive_line, node);
- }
- }
+ _cpp_maybe_notify_macro_use (pfile, node);
if (pfile->cb.used)
pfile->cb.used (pfile, pfile->directive_line, node);
check_eol (pfile, false);
@@ -2006,26 +1990,10 @@ do_ifndef (cpp_reader *pfile)
the powerpc and spu ports using conditional macros for 'vector',
'bool', and 'pixel' to act as conditional keywords. This messes
up tests like #ifndef bool. */
- skip = (node->type == NT_MACRO
- && ((node->flags & NODE_CONDITIONAL) == 0));
+ skip = (cpp_macro_p (node)
+ && !(node->flags & NODE_CONDITIONAL));
_cpp_mark_macro_used (node);
- if (!(node->flags & NODE_USED))
- {
- node->flags |= NODE_USED;
- if (node->type == NT_MACRO)
- {
- if ((node->flags & NODE_BUILTIN)
- && pfile->cb.user_builtin_macro)
- pfile->cb.user_builtin_macro (pfile, node);
- if (pfile->cb.used_define)
- pfile->cb.used_define (pfile, pfile->directive_line, node);
- }
- else
- {
- if (pfile->cb.used_undef)
- pfile->cb.used_undef (pfile, pfile->directive_line, node);
- }
- }
+ _cpp_maybe_notify_macro_use (pfile, node);
if (pfile->cb.used)
pfile->cb.used (pfile, pfile->directive_line, node);
check_eol (pfile, false);
@@ -2182,17 +2150,13 @@ push_conditional (cpp_reader *pfile, int skip, int type,
storage, i.e. the #assert case. Returns 0 on success, and sets
ANSWERP to point to the answer. PRED_LOC is the location of the
predicate. */
-static int
-parse_answer (cpp_reader *pfile, struct answer **answerp, int type,
- source_location pred_loc)
+static bool
+parse_answer (cpp_reader *pfile, int type, source_location pred_loc,
+ cpp_macro **answer_ptr)
{
- const cpp_token *paren;
- struct answer *answer;
- unsigned int acount;
-
/* In a conditional, it is legal to not have an open paren. We
should save the following token in this case. */
- paren = cpp_get_token (pfile);
+ const cpp_token *paren = cpp_get_token (pfile);
/* If not a paren, see if we're OK. */
if (paren->type != CPP_OPEN_PAREN)
@@ -2202,23 +2166,26 @@ parse_answer (cpp_reader *pfile, struct answer **answerp, int type,
if (type == T_IF)
{
_cpp_backup_tokens (pfile, 1);
- return 0;
+ return true;
}
/* #unassert with no answer is valid - it removes all answers. */
if (type == T_UNASSERT && paren->type == CPP_EOF)
- return 0;
+ return true;
cpp_error_with_line (pfile, CPP_DL_ERROR, pred_loc, 0,
"missing '(' after predicate");
- return 1;
+ return false;
}
- for (acount = 0;; acount++)
+ cpp_macro *answer = _cpp_new_macro (pfile, cmk_assert,
+ _cpp_reserve_room (pfile, 0,
+ sizeof (cpp_macro)));
+ answer->parm.next = NULL;
+ unsigned count = 0;
+ for (;;)
{
- size_t room_needed;
const cpp_token *token = cpp_get_token (pfile);
- cpp_token *dest;
if (token->type == CPP_CLOSE_PAREN)
break;
@@ -2226,57 +2193,52 @@ parse_answer (cpp_reader *pfile, struct answer **answerp, int type,
if (token->type == CPP_EOF)
{
cpp_error (pfile, CPP_DL_ERROR, "missing ')' to complete answer");
- return 1;
+ return false;
}
- /* struct answer includes the space for one token. */
- room_needed = (sizeof (struct answer) + acount * sizeof (cpp_token));
-
- if (BUFF_ROOM (pfile->a_buff) < room_needed)
- _cpp_extend_buff (pfile, &pfile->a_buff, sizeof (struct answer));
-
- dest = &((struct answer *) BUFF_FRONT (pfile->a_buff))->first[acount];
- *dest = *token;
-
- /* Drop whitespace at start, for answer equivalence purposes. */
- if (acount == 0)
- dest->flags &= ~PREV_WHITE;
+ answer = (cpp_macro *)_cpp_reserve_room
+ (pfile, sizeof (cpp_macro) + count * sizeof (cpp_token),
+ sizeof (cpp_token));
+ answer->exp.tokens[count++] = *token;
}
- if (acount == 0)
+ if (!count)
{
cpp_error (pfile, CPP_DL_ERROR, "predicate's answer is empty");
- return 1;
+ return false;
}
- answer = (struct answer *) BUFF_FRONT (pfile->a_buff);
- answer->count = acount;
- answer->next = NULL;
- *answerp = answer;
+ /* Drop whitespace at start, for answer equivalence purposes. */
+ answer->exp.tokens[0].flags &= ~PREV_WHITE;
- return 0;
+ answer->count = count;
+ *answer_ptr = answer;
+
+ return true;
}
/* Parses an assertion directive of type TYPE, returning a pointer to
- the hash node of the predicate, or 0 on error. If an answer was
- supplied, it is placed in ANSWERP, otherwise it is set to 0. */
+ the hash node of the predicate, or 0 on error. The node is
+ guaranteed to be disjoint from the macro namespace, so can only
+ have type 'NT_VOID'. If an answer was supplied, it is placed in
+ *ANSWER_PTR, which is otherwise set to 0. */
static cpp_hashnode *
-parse_assertion (cpp_reader *pfile, struct answer **answerp, int type)
+parse_assertion (cpp_reader *pfile, int type, cpp_macro **answer_ptr)
{
cpp_hashnode *result = 0;
- const cpp_token *predicate;
/* We don't expand predicates or answers. */
pfile->state.prevent_expansion++;
- *answerp = 0;
- predicate = cpp_get_token (pfile);
+ *answer_ptr = NULL;
+
+ const cpp_token *predicate = cpp_get_token (pfile);
if (predicate->type == CPP_EOF)
cpp_error (pfile, CPP_DL_ERROR, "assertion without predicate");
else if (predicate->type != CPP_NAME)
cpp_error_with_line (pfile, CPP_DL_ERROR, predicate->src_loc, 0,
"predicate must be an identifier");
- else if (parse_answer (pfile, answerp, type, predicate->src_loc) == 0)
+ else if (parse_answer (pfile, type, predicate->src_loc, answer_ptr))
{
unsigned int len = NODE_LEN (predicate->val.node.node);
unsigned char *sym = (unsigned char *) alloca (len + 1);
@@ -2288,25 +2250,27 @@ parse_assertion (cpp_reader *pfile, struct answer **answerp, int type)
}
pfile->state.prevent_expansion--;
+
return result;
}
/* Returns a pointer to the pointer to CANDIDATE in the answer chain,
or a pointer to NULL if the answer is not in the chain. */
-static struct answer **
-find_answer (cpp_hashnode *node, const struct answer *candidate)
+static cpp_macro **
+find_answer (cpp_hashnode *node, const cpp_macro *candidate)
{
unsigned int i;
- struct answer **result;
+ cpp_macro **result = NULL;
- for (result = &node->value.answers; *result; result = &(*result)->next)
+ for (result = &node->value.answers; *result; result = &(*result)->parm.next)
{
- struct answer *answer = *result;
+ cpp_macro *answer = *result;
if (answer->count == candidate->count)
{
for (i = 0; i < answer->count; i++)
- if (! _cpp_equiv_tokens (&answer->first[i], &candidate->first[i]))
+ if (!_cpp_equiv_tokens (&answer->exp.tokens[i],
+ &candidate->exp.tokens[i]))
break;
if (i == answer->count)
@@ -2323,18 +2287,18 @@ find_answer (cpp_hashnode *node, const struct answer *candidate)
int
_cpp_test_assertion (cpp_reader *pfile, unsigned int *value)
{
- struct answer *answer;
- cpp_hashnode *node;
-
- node = parse_assertion (pfile, &answer, T_IF);
+ cpp_macro *answer;
+ cpp_hashnode *node = parse_assertion (pfile, T_IF, &answer);
/* For recovery, an erroneous assertion expression is handled as a
failing assertion. */
*value = 0;
if (node)
- *value = (node->type == NT_ASSERTION &&
- (answer == 0 || *find_answer (node, answer) != 0));
+ {
+ if (node->value.answers)
+ *value = !answer || *find_answer (node, answer);
+ }
else if (pfile->cur_token[-1].type == CPP_EOF)
_cpp_backup_tokens (pfile, 1);
@@ -2346,43 +2310,29 @@ _cpp_test_assertion (cpp_reader *pfile, unsigned int *value)
static void
do_assert (cpp_reader *pfile)
{
- struct answer *new_answer;
- cpp_hashnode *node;
+ cpp_macro *answer;
+ cpp_hashnode *node = parse_assertion (pfile, T_ASSERT, &answer);
- node = parse_assertion (pfile, &new_answer, T_ASSERT);
if (node)
{
- size_t answer_size;
-
/* Place the new answer in the answer list. First check there
is not a duplicate. */
- new_answer->next = 0;
- if (node->type == NT_ASSERTION)
+ if (*find_answer (node, answer))
{
- if (*find_answer (node, new_answer))
- {
- cpp_error (pfile, CPP_DL_WARNING, "\"%s\" re-asserted",
- NODE_NAME (node) + 1);
- return;
- }
- new_answer->next = node->value.answers;
+ cpp_error (pfile, CPP_DL_WARNING, "\"%s\" re-asserted",
+ NODE_NAME (node) + 1);
+ return;
}
- answer_size = sizeof (struct answer) + ((new_answer->count - 1)
- * sizeof (cpp_token));
- /* Commit or allocate storage for the object. */
- if (pfile->hash_table->alloc_subobject)
- {
- struct answer *temp_answer = new_answer;
- new_answer = (struct answer *) pfile->hash_table->alloc_subobject
- (answer_size);
- memcpy (new_answer, temp_answer, answer_size);
- }
- else
- BUFF_FRONT (pfile->a_buff) += answer_size;
+ /* Commit or allocate storage for the answer. */
+ answer = (cpp_macro *)_cpp_commit_buff
+ (pfile, sizeof (cpp_macro) - sizeof (cpp_token)
+ + sizeof (cpp_token) * answer->count);
+
+ /* Chain into the list. */
+ answer->parm.next = node->value.answers;
+ node->value.answers = answer;
- node->type = NT_ASSERTION;
- node->value.answers = new_answer;
check_eol (pfile, false);
}
}
@@ -2391,25 +2341,19 @@ do_assert (cpp_reader *pfile)
static void
do_unassert (cpp_reader *pfile)
{
- cpp_hashnode *node;
- struct answer *answer;
+ cpp_macro *answer;
+ cpp_hashnode *node = parse_assertion (pfile, T_UNASSERT, &answer);
- node = parse_assertion (pfile, &answer, T_UNASSERT);
/* It isn't an error to #unassert something that isn't asserted. */
- if (node && node->type == NT_ASSERTION)
+ if (node)
{
if (answer)
{
- struct answer **p = find_answer (node, answer), *temp;
+ cpp_macro **p = find_answer (node, answer);
- /* Remove the answer from the list. */
- temp = *p;
- if (temp)
- *p = temp->next;
-
- /* Did we free the last answer? */
- if (node->value.answers == 0)
- node->type = NT_VOID;
+ /* Remove the assert from the list. */
+ if (cpp_macro *temp = *p)
+ *p = temp->parm.next;
check_eol (pfile, false);
}
@@ -2508,18 +2452,18 @@ cpp_pop_definition (cpp_reader *pfile, struct def_pragma_macro *c)
if (pfile->cb.before_define)
pfile->cb.before_define (pfile);
- if (node->type == NT_MACRO)
+ if (cpp_macro_p (node))
{
if (pfile->cb.undef)
pfile->cb.undef (pfile, pfile->directive_line, node);
if (CPP_OPTION (pfile, warn_unused_macros))
_cpp_warn_if_unused_macro (pfile, node, NULL);
+ _cpp_free_definition (node);
}
- if (node->type != NT_VOID)
- _cpp_free_definition (node);
if (c->is_undef)
return;
+
{
size_t namelen;
const uchar *dn;
@@ -2530,8 +2474,6 @@ cpp_pop_definition (cpp_reader *pfile, struct def_pragma_macro *c)
h = cpp_lookup (pfile, c->definition, namelen);
dn = c->definition + namelen;
- h->type = NT_VOID;
- h->flags &= ~(NODE_POISONED|NODE_BUILTIN|NODE_DISABLED|NODE_USED);
nbuf = cpp_push_buffer (pfile, dn, ustrchr (dn, '\n') - dn, true);
if (nbuf != NULL)
{
diff --git a/libcpp/expr.c b/libcpp/expr.c
index 36c3fc4..201a619 100644
--- a/libcpp/expr.c
+++ b/libcpp/expr.c
@@ -1065,23 +1065,7 @@ parse_defined (cpp_reader *pfile)
"this use of \"defined\" may not be portable");
_cpp_mark_macro_used (node);
- if (!(node->flags & NODE_USED))
- {
- node->flags |= NODE_USED;
- if (node->type == NT_MACRO)
- {
- if ((node->flags & NODE_BUILTIN)
- && pfile->cb.user_builtin_macro)
- pfile->cb.user_builtin_macro (pfile, node);
- if (pfile->cb.used_define)
- pfile->cb.used_define (pfile, pfile->directive_line, node);
- }
- else
- {
- if (pfile->cb.used_undef)
- pfile->cb.used_undef (pfile, pfile->directive_line, node);
- }
- }
+ _cpp_maybe_notify_macro_use (pfile, node);
/* A possible controlling macro of the form #if !defined ().
_cpp_parse_expr checks there was no other junk on the line. */
@@ -1097,8 +1081,8 @@ parse_defined (cpp_reader *pfile)
result.unsignedp = false;
result.high = 0;
result.overflow = false;
- result.low = (node && node->type == NT_MACRO
- && (node->flags & NODE_CONDITIONAL) == 0);
+ result.low = (node && cpp_macro_p (node)
+ && !(node->flags & NODE_CONDITIONAL));
return result;
}
diff --git a/libcpp/files.c b/libcpp/files.c
index e8d21b2..08b7c64 100644
--- a/libcpp/files.c
+++ b/libcpp/files.c
@@ -805,7 +805,7 @@ should_stack_file (cpp_reader *pfile, _cpp_file *file, bool import,
/* Skip if the file had a header guard and the macro is defined.
PCH relies on this appearing before the PCH handler below. */
- if (file->cmacro && file->cmacro->type == NT_MACRO)
+ if (file->cmacro && cpp_macro_p (file->cmacro))
return false;
/* Handle PCH files immediately; don't stack them. */
diff --git a/libcpp/identifiers.c b/libcpp/identifiers.c
index 16584a6..3d42d1a 100644
--- a/libcpp/identifiers.c
+++ b/libcpp/identifiers.c
@@ -104,8 +104,8 @@ cpp_defined (cpp_reader *pfile, const unsigned char *str, int len)
node = CPP_HASHNODE (ht_lookup (pfile->hash_table, str, len, HT_NO_INSERT));
- /* If it's of type NT_MACRO, it cannot be poisoned. */
- return node && node->type == NT_MACRO;
+ /* If it's a macro, it cannot have been poisoned. */
+ return node && cpp_macro_p (node);
}
/* We don't need a proxy since the hash table's identifier comes first
diff --git a/libcpp/include/cpp-id-data.h b/libcpp/include/cpp-id-data.h
deleted file mode 100644
index 0299984..0000000
--- a/libcpp/include/cpp-id-data.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/* Structures that hang off cpp_identifier, for PCH.
- Copyright (C) 1986-2018 Free Software Foundation, Inc.
-
-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/>. */
-
-#include "cpplib.h"
-
-#if !defined (HAVE_UCHAR) && !defined (IN_GCC)
-typedef unsigned char uchar;
-#endif
-
-#define UC (const unsigned char *) /* Intended use: UC"string" */
-
-/* Chained list of answers to an assertion. */
-struct GTY(()) answer {
- struct answer *next;
- unsigned int count;
- cpp_token GTY ((length ("%h.count"))) first[1];
-};
-
-/* Each macro definition is recorded in a cpp_macro structure.
- Variadic macros cannot occur with traditional cpp. */
-struct GTY(()) cpp_macro {
- /* Parameters, if any. If parameter names use extended identifiers,
- the original spelling of those identifiers, not the canonical
- UTF-8 spelling, goes here. */
- cpp_hashnode ** GTY ((nested_ptr (union tree_node,
- "%h ? CPP_HASHNODE (GCC_IDENT_TO_HT_IDENT (%h)) : NULL",
- "%h ? HT_IDENT_TO_GCC_IDENT (HT_NODE (%h)) : NULL"),
- length ("%h.paramc")))
- params;
-
- /* Replacement tokens (ISO) or replacement text (traditional). See
- comment at top of cpptrad.c for how traditional function-like
- macros are encoded. */
- union cpp_macro_u
- {
- cpp_token * GTY ((tag ("0"), length ("%0.count"))) tokens;
- const unsigned char * GTY ((tag ("1"))) text;
- } GTY ((desc ("%1.traditional"))) exp;
-
- /* Definition line number. */
- source_location line;
-
- /* Number of tokens in expansion, or bytes for traditional macros. */
- unsigned int count;
-
- /* Number of parameters. */
- unsigned short paramc;
-
- /* If a function-like macro. */
- unsigned int fun_like : 1;
-
- /* If a variadic macro. */
- unsigned int variadic : 1;
-
- /* If macro defined in system header. */
- unsigned int syshdr : 1;
-
- /* Nonzero if it has been expanded or had its existence tested. */
- unsigned int used : 1;
-
- /* Indicate which field of 'exp' is in use. */
- unsigned int traditional : 1;
-
- /* Indicate whether the tokens include extra CPP_PASTE tokens at the
- end to track invalid redefinitions with consecutive CPP_PASTE
- tokens. */
- unsigned int extra_tokens : 1;
-};
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index 3ad52d5..85aa09f 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -36,7 +36,6 @@ typedef struct cpp_macro cpp_macro;
typedef struct cpp_callbacks cpp_callbacks;
typedef struct cpp_dir cpp_dir;
-struct answer;
struct _cpp_file;
/* The first three groups, apart from '=', can appear in preprocessor
@@ -605,8 +604,8 @@ struct cpp_callbacks
/* Callback to identify whether an attribute exists. */
int (*has_attribute) (cpp_reader *);
- /* Callback that can change a user builtin into normal macro. */
- bool (*user_builtin_macro) (cpp_reader *, cpp_hashnode *);
+ /* Callback that can change a user lazy into normal macro. */
+ void (*user_lazy_macro) (cpp_reader *, cpp_macro *, unsigned);
/* Callback to parse SOURCE_DATE_EPOCH from environment. */
time_t (*get_source_date_epoch) (cpp_reader *);
@@ -671,14 +670,81 @@ struct cpp_dir
dev_t dev;
};
-/* The structure of a node in the hash table. The hash table has
- entries for all identifiers: either macros defined by #define
- commands (type NT_MACRO), assertions created with #assert
- (NT_ASSERTION), or neither of the above (NT_VOID). Builtin macros
- like __LINE__ are flagged NODE_BUILTIN. Poisoned identifiers are
- flagged NODE_POISONED. NODE_OPERATOR (C++ only) indicates an
- identifier that behaves like an operator such as "xor".
- NODE_DIAGNOSTIC is for speed in lex_token: it indicates a
+/* The kind of the cpp_macro. */
+enum cpp_macro_kind {
+ cmk_macro, /* An ISO macro (token expansion). */
+ cmk_assert, /* An assertion. */
+ cmk_traditional /* A traditional macro (text expansion). */
+};
+
+/* Each macro definition is recorded in a cpp_macro structure.
+ Variadic macros cannot occur with traditional cpp. */
+struct GTY(()) cpp_macro {
+ union cpp_parm_u
+ {
+ /* Parameters, if any. If parameter names use extended identifiers,
+ the original spelling of those identifiers, not the canonical
+ UTF-8 spelling, goes here. */
+ cpp_hashnode ** GTY ((tag ("false"),
+ nested_ptr (union tree_node,
+ "%h ? CPP_HASHNODE (GCC_IDENT_TO_HT_IDENT (%h)) : NULL",
+ "%h ? HT_IDENT_TO_GCC_IDENT (HT_NODE (%h)) : NULL"),
+ length ("%1.paramc"))) params;
+
+ /* If this is an assertion, the next one in the chain. */
+ cpp_macro *GTY ((tag ("true"))) next;
+ } GTY ((desc ("%1.kind == cmk_assert"))) parm;
+
+ /* Definition line number. */
+ source_location line;
+
+ /* Number of tokens in body, or bytes for traditional macros. */
+ /* Do we really need 2^32-1 range here? */
+ unsigned int count;
+
+ /* Number of parameters. */
+ unsigned short paramc;
+
+ /* Non-zero if this is a user-lazy macro, value provided by user. */
+ unsigned char lazy;
+
+ /* The kind of this macro (ISO, trad or assert) */
+ unsigned kind : 2;
+
+ /* If a function-like macro. */
+ unsigned int fun_like : 1;
+
+ /* If a variadic macro. */
+ unsigned int variadic : 1;
+
+ /* If macro defined in system header. */
+ unsigned int syshdr : 1;
+
+ /* Nonzero if it has been expanded or had its existence tested. */
+ unsigned int used : 1;
+
+ /* Indicate whether the tokens include extra CPP_PASTE tokens at the
+ end to track invalid redefinitions with consecutive CPP_PASTE
+ tokens. */
+ unsigned int extra_tokens : 1;
+
+ /* 1 bits spare (32-bit). 33 on 64-bit target. */
+
+ union cpp_exp_u
+ {
+ /* Trailing array of replacement tokens (ISO), or assertion body value. */
+ cpp_token GTY ((tag ("false"), length ("%1.count"))) tokens[1];
+
+ /* Pointer to replacement text (traditional). See comment at top
+ of cpptrad.c for how traditional function-like macros are
+ encoded. */
+ const unsigned char *GTY ((tag ("true"))) text;
+ } GTY ((desc ("%1.kind == cmk_traditional"))) exp;
+};
+
+/* Poisoned identifiers are flagged NODE_POISONED. NODE_OPERATOR (C++
+ only) indicates an identifier that behaves like an operator such as
+ "xor". NODE_DIAGNOSTIC is for speed in lex_token: it indicates a
diagnostic may be required for this node. Currently this only
applies to __VA_ARGS__, poisoned identifiers, and -Wc++-compat
warnings about NODE_OPERATOR. */
@@ -686,21 +752,21 @@ struct cpp_dir
/* Hash node flags. */
#define NODE_OPERATOR (1 << 0) /* C++ named operator. */
#define NODE_POISONED (1 << 1) /* Poisoned identifier. */
-#define NODE_BUILTIN (1 << 2) /* Builtin macro. */
-#define NODE_DIAGNOSTIC (1 << 3) /* Possible diagnostic when lexed. */
-#define NODE_WARN (1 << 4) /* Warn if redefined or undefined. */
-#define NODE_DISABLED (1 << 5) /* A disabled macro. */
-#define NODE_MACRO_ARG (1 << 6) /* Used during #define processing. */
-#define NODE_USED (1 << 7) /* Dumped with -dU. */
-#define NODE_CONDITIONAL (1 << 8) /* Conditional macro */
-#define NODE_WARN_OPERATOR (1 << 9) /* Warn about C++ named operator. */
+#define NODE_DIAGNOSTIC (1 << 2) /* Possible diagnostic when lexed. */
+#define NODE_WARN (1 << 3) /* Warn if redefined or undefined. */
+#define NODE_DISABLED (1 << 4) /* A disabled macro. */
+#define NODE_USED (1 << 5) /* Dumped with -dU. */
+#define NODE_CONDITIONAL (1 << 6) /* Conditional macro */
+#define NODE_WARN_OPERATOR (1 << 7) /* Warn about C++ named operator. */
/* Different flavors of hash node. */
enum node_type
{
- NT_VOID = 0, /* No definition yet. */
- NT_MACRO, /* A macro of some form. */
- NT_ASSERTION /* Predicate for #assert. */
+ NT_VOID = 0, /* Maybe an assert? */
+ NT_MACRO_ARG, /* A macro arg. */
+ NT_USER_MACRO, /* A user macro. */
+ NT_BUILTIN_MACRO, /* A builtin macro. */
+ NT_MACRO_MASK = NT_USER_MACRO /* Mask for either macro kind. */
};
/* Different flavors of builtin macro. _Pragma is an operator, but we
@@ -717,9 +783,7 @@ enum cpp_builtin_type
BT_PRAGMA, /* `_Pragma' operator */
BT_TIMESTAMP, /* `__TIMESTAMP__' */
BT_COUNTER, /* `__COUNTER__' */
- BT_HAS_ATTRIBUTE, /* `__has_attribute__(x)' */
- BT_FIRST_USER, /* User defined builtin macros. */
- BT_LAST_USER = BT_FIRST_USER + 63
+ BT_HAS_ATTRIBUTE /* `__has_attribute__(x)' */
};
#define CPP_HASHNODE(HNODE) ((cpp_hashnode *) (HNODE))
@@ -727,36 +791,19 @@ enum cpp_builtin_type
#define NODE_LEN(NODE) HT_LEN (&(NODE)->ident)
#define NODE_NAME(NODE) HT_STR (&(NODE)->ident)
-/* Specify which field, if any, of the union is used. */
-
-enum {
- NTV_MACRO,
- NTV_ANSWER,
- NTV_BUILTIN,
- NTV_ARGUMENT,
- NTV_NONE
-};
-
-#define CPP_HASHNODE_VALUE_IDX(HNODE) \
- ((HNODE.flags & NODE_MACRO_ARG) ? NTV_ARGUMENT \
- : HNODE.type == NT_MACRO ? ((HNODE.flags & NODE_BUILTIN) \
- ? NTV_BUILTIN : NTV_MACRO) \
- : HNODE.type == NT_ASSERTION ? NTV_ANSWER \
- : NTV_NONE)
-
/* The common part of an identifier node shared amongst all 3 C front
ends. Also used to store CPP identifiers, which are a superset of
identifiers in the grammatical sense. */
union GTY(()) _cpp_hashnode_value {
- /* If a macro. */
- cpp_macro * GTY((tag ("NTV_MACRO"))) macro;
- /* Answers to an assertion. */
- struct answer * GTY ((tag ("NTV_ANSWER"))) answers;
+ /* Assert (maybe NULL) */
+ cpp_macro * GTY((tag ("NT_VOID"))) answers;
+ /* Macro (never NULL) */
+ cpp_macro * GTY((tag ("NT_USER_MACRO"))) macro;
/* Code for a builtin macro. */
- enum cpp_builtin_type GTY ((tag ("NTV_BUILTIN"))) builtin;
+ enum cpp_builtin_type GTY ((tag ("NT_BUILTIN_MACRO"))) builtin;
/* Macro argument index. */
- unsigned short GTY ((tag ("NTV_ARGUMENT"))) arg_index;
+ unsigned short GTY ((tag ("NT_MACRO_ARG"))) arg_index;
};
struct GTY(()) cpp_hashnode {
@@ -766,10 +813,12 @@ struct GTY(()) cpp_hashnode {
then index into directive table.
Otherwise, a NODE_OPERATOR. */
unsigned char rid_code; /* Rid code - for front ends. */
- ENUM_BITFIELD(node_type) type : 6; /* CPP node type. */
- unsigned int flags : 10; /* CPP flags. */
+ ENUM_BITFIELD(node_type) type : 2; /* CPP node type. */
+ unsigned int flags : 8; /* CPP flags. */
- union _cpp_hashnode_value GTY ((desc ("CPP_HASHNODE_VALUE_IDX (%1)"))) value;
+ /* 6 bits spare (plus another 32 on 64-bit hosts). */
+
+ union _cpp_hashnode_value GTY ((desc ("%1.type"))) value;
};
/* A class for iterating through the source locations within a
@@ -890,7 +939,25 @@ extern int cpp_avoid_paste (cpp_reader *, const cpp_token *,
extern const cpp_token *cpp_get_token (cpp_reader *);
extern const cpp_token *cpp_get_token_with_location (cpp_reader *,
source_location *);
-extern bool cpp_fun_like_macro_p (cpp_hashnode *);
+inline bool cpp_user_macro_p (const cpp_hashnode *node)
+{
+ return node->type == NT_USER_MACRO;
+}
+inline bool cpp_builtin_macro_p (const cpp_hashnode *node)
+{
+ return node->type == NT_BUILTIN_MACRO;
+}
+inline bool cpp_macro_p (const cpp_hashnode *node)
+{
+ return node->type & NT_MACRO_MASK;
+}
+
+/* Returns true if NODE is a function-like user macro. */
+inline bool cpp_fun_like_macro_p (cpp_hashnode *node)
+{
+ return cpp_user_macro_p (node) && node->value.macro->fun_like;
+}
+
extern const unsigned char *cpp_macro_definition (cpp_reader *,
cpp_hashnode *);
extern source_location cpp_macro_definition_location (cpp_hashnode *);
@@ -926,6 +993,9 @@ extern void cpp_assert (cpp_reader *, const char *);
extern void cpp_undef (cpp_reader *, const char *);
extern void cpp_unassert (cpp_reader *, const char *);
+/* Mark a node as a lazily defined macro. */
+extern void cpp_define_lazily (cpp_reader *, cpp_hashnode *node, unsigned N);
+
/* Undefine all macros and assertions. */
extern void cpp_undef_all (cpp_reader *);
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
index a4baa49..c479dfa 100644
--- a/libcpp/include/line-map.h
+++ b/libcpp/include/line-map.h
@@ -61,20 +61,14 @@ inline int compare (linenum_type lhs, linenum_type rhs)
return 0;
}
-/* Reason for creating a new line map with linemap_add. LC_ENTER is
- when including a new file, e.g. a #include directive in C.
- LC_LEAVE is when reaching a file's end. LC_RENAME is when a file
- name or line number changes for neither of the above reasons
- (e.g. a #line directive in C); LC_RENAME_VERBATIM is like LC_RENAME
- but a filename of "" is not specially interpreted as standard
- input. LC_ENTER_MACRO is when a macro expansion is about to start. */
+/* Reason for creating a new line map with linemap_add. */
enum lc_reason
{
- LC_ENTER = 0,
- LC_LEAVE,
- LC_RENAME,
- LC_RENAME_VERBATIM,
- LC_ENTER_MACRO,
+ LC_ENTER = 0, /* Begin #include. */
+ LC_LEAVE, /* Return to including file. */
+ LC_RENAME, /* Other reason for name change. */
+ LC_RENAME_VERBATIM, /* Likewise, but "" != stdin. */
+ LC_ENTER_MACRO, /* Begin macro expansion. */
/* FIXME: add support for stringize and paste. */
LC_HWM /* High Water Mark. */
};
@@ -440,10 +434,10 @@ struct GTY((tag ("1"))) line_map_ordinary : public line_map {
const char *to_file;
linenum_type to_line;
- /* An index into the set that gives the line mapping at whose end
- the current one was included. File(s) at the bottom of the
- include stack have this set to -1. */
- int included_from;
+ /* Location from whence this line map was included. For regular
+ #includes, this location will be the last location of a map. For
+ outermost file, this is 0. */
+ source_location included_from;
/* Size is 20 or 24 bytes, no padding */
};
@@ -634,17 +628,6 @@ ORDINARY_MAP_STARTING_LINE_NUMBER (const line_map_ordinary *ord_map)
return ord_map->to_line;
}
-/* Get the index of the ordinary map at whose end
- ordinary map MAP was included.
-
- File(s) at the bottom of the include stack have this set. */
-
-inline int
-ORDINARY_MAP_INCLUDER_FILE_INDEX (const line_map_ordinary *ord_map)
-{
- return ord_map->included_from;
-}
-
/* Return a positive value if map encodes locations from a system
header, 0 otherwise. Returns 1 if ordinary map MAP encodes locations
in a system header and 2 if it encodes locations in a C system header
@@ -788,8 +771,7 @@ struct GTY(()) line_maps {
may require allocating a new line_map. */
unsigned int max_column_hint;
- /* If non-null, the allocator to use when resizing 'maps'. If null,
- xrealloc is used. */
+ /* The allocator to use when resizing 'maps', defaults to xrealloc. */
line_map_realloc reallocator;
/* The allocators' function used to know the actual size it
@@ -1192,51 +1174,23 @@ SOURCE_COLUMN (const line_map_ordinary *ord_map, source_location loc)
& ((1 << ord_map->m_column_and_range_bits) - 1)) >> ord_map->m_range_bits;
}
-/* Return the location of the last source line within an ordinary
- map. */
-inline source_location
-LAST_SOURCE_LINE_LOCATION (const line_map_ordinary *map)
-{
- return (((map[1].start_location - 1
- - map->start_location)
- & ~((1 << map->m_column_and_range_bits) - 1))
- + map->start_location);
-}
-/* Returns the last source line number within an ordinary map. This
- is the (last) line of the #include, or other directive, that caused
- a map change. */
-inline linenum_type
-LAST_SOURCE_LINE (const line_map_ordinary *map)
-{
- return SOURCE_LINE (map, LAST_SOURCE_LINE_LOCATION (map));
-}
-
-/* Return the last column number within an ordinary map. */
-
-inline linenum_type
-LAST_SOURCE_COLUMN (const line_map_ordinary *map)
+inline source_location
+linemap_included_from (const line_map_ordinary *ord_map)
{
- return SOURCE_COLUMN (map, LAST_SOURCE_LINE_LOCATION (map));
+ return ord_map->included_from;
}
-/* Returns the map a given map was included from, or NULL if the map
- belongs to the main file, i.e, a file that wasn't included by
- another one. */
-inline line_map_ordinary *
-INCLUDED_FROM (struct line_maps *set, const line_map_ordinary *ord_map)
-{
- return ((ord_map->included_from == -1)
- ? NULL
- : LINEMAPS_ORDINARY_MAP_AT (set, ord_map->included_from));
-}
+/* The linemap containing the included-from location of MAP. */
+const line_map_ordinary *linemap_included_from_linemap
+ (line_maps *set, const line_map_ordinary *map);
/* True if the map is at the bottom of the include stack. */
inline bool
MAIN_FILE_P (const line_map_ordinary *ord_map)
{
- return ord_map->included_from < 0;
+ return ord_map->included_from == 0;
}
/* Encode and return a source_location from a column number. The
@@ -1320,23 +1274,50 @@ typedef struct
bool sysp;
} expanded_location;
-/* A location within a rich_location: a caret&range, with
- the caret potentially flagged for display. */
+class range_label;
-struct location_range
-{
- source_location m_loc;
+/* A hint to diagnostic_show_locus on how to print a source range within a
+ rich_location.
- /* Should a caret be drawn for this range? Typically this is
- true for the 0th range, and false for subsequent ranges,
- but the Fortran frontend overrides this for rendering things like:
+ Typically this is SHOW_RANGE_WITH_CARET for the 0th range, and
+ SHOW_RANGE_WITHOUT_CARET for subsequent ranges,
+ but the Fortran frontend uses SHOW_RANGE_WITH_CARET repeatedly for
+ printing things like:
x = x + y
1 2
Error: Shapes for operands at (1) and (2) are not conformable
- where "1" and "2" are notionally carets. */
- bool m_show_caret_p;
+ where "1" and "2" are notionally carets. */
+
+enum range_display_kind
+{
+ /* Show the pertinent source line(s), the caret, and underline(s). */
+ SHOW_RANGE_WITH_CARET,
+
+ /* Show the pertinent source line(s) and underline(s), but don't
+ show the caret (just an underline). */
+ SHOW_RANGE_WITHOUT_CARET,
+
+ /* Just show the source lines; don't show the range itself.
+ This is for use when displaying some line-insertion fix-it hints (for
+ showing the user context on the change, for when it doesn't make sense
+ to highlight the first column on the next line). */
+ SHOW_LINES_WITHOUT_RANGE
+};
+
+/* A location within a rich_location: a caret&range, with
+ the caret potentially flagged for display, and an optional
+ label. */
+
+struct location_range
+{
+ source_location m_loc;
+
+ enum range_display_kind m_range_display_kind;
+
+ /* If non-NULL, the label for this range. */
+ const range_label *m_label;
};
/* A partially-embedded vec for use within rich_location for storing
@@ -1478,6 +1459,8 @@ class fixit_hint;
Additional ranges may be added to help the user identify other
pertinent clauses in a diagnostic.
+ Ranges can (optionally) be given labels via class range_label.
+
rich_location instances are intended to be allocated on the stack
when generating diagnostics, and to be short-lived.
@@ -1523,18 +1506,22 @@ class fixit_hint;
equal to their caret point. The frontend overrides the diagnostic
context's default caret character for these ranges.
- Example E
- *********
+ Example E (range labels)
+ ************************
printf ("arg0: %i arg1: %s arg2: %i",
^~
+ |
+ const char *
100, 101, 102);
~~~
+ |
+ int
This rich location has two ranges:
- range 0 is at the "%s" with start = caret = "%" and finish at
- the "s".
+ the "s". It has a range_label ("const char *").
- range 1 has start/finish covering the "101" and is not flagged for
- caret printing; it is perhaps at the start of "101".
-
+ caret printing. The caret is at the start of "101", where its
+ range_label is printed ("int").
Fix-it hints
------------
@@ -1594,6 +1581,18 @@ class fixit_hint;
added via
richloc.add_fixit_replace ("color");
+ Example J: fix-it hint: line insertion
+ **************************************
+
+ 3 | #include <stddef.h>
+ + |+#include <stdio.h>
+ 4 | int the_next_line;
+
+ This rich location has a single range at line 4 column 1, marked
+ with SHOW_LINES_WITHOUT_RANGE (to avoid printing a meaningless caret
+ on the "i" of int). It has a insertion fix-it hint of the string
+ "#include <stdio.h>\n".
+
Adding a fix-it hint can fail: for example, attempts to insert content
at the transition between two line maps may fail due to there being no
source_location (aka location_t) value to express the new location.
@@ -1626,7 +1625,8 @@ class rich_location
/* Constructors. */
/* Constructing from a location. */
- rich_location (line_maps *set, source_location loc);
+ rich_location (line_maps *set, source_location loc,
+ const range_label *label = NULL);
/* Destructor. */
~rich_location ();
@@ -1636,10 +1636,14 @@ class rich_location
source_location get_loc (unsigned int idx) const;
void
- add_range (source_location loc, bool show_caret_p);
+ add_range (source_location loc,
+ enum range_display_kind range_display_kind
+ = SHOW_RANGE_WITHOUT_CARET,
+ const range_label *label = NULL);
void
- set_range (unsigned int idx, source_location loc, bool show_caret_p);
+ set_range (unsigned int idx, source_location loc,
+ enum range_display_kind range_display_kind);
unsigned int get_num_locations () const { return m_ranges.count (); }
@@ -1760,6 +1764,56 @@ protected:
bool m_fixits_cannot_be_auto_applied;
};
+/* A struct for the result of range_label::get_text: a NUL-terminated buffer
+ of localized text, and a flag to determine if the caller should "free" the
+ buffer. */
+
+struct label_text
+{
+ label_text ()
+ : m_buffer (NULL), m_caller_owned (false)
+ {}
+
+ label_text (char *buffer, bool caller_owned)
+ : m_buffer (buffer), m_caller_owned (caller_owned)
+ {}
+
+ void maybe_free ()
+ {
+ if (m_caller_owned)
+ free (m_buffer);
+ }
+
+ char *m_buffer;
+ bool m_caller_owned;
+};
+
+/* Abstract base class for labelling a range within a rich_location
+ (e.g. for labelling expressions with their type).
+
+ Generating the text could require non-trivial work, so this work
+ is delayed (via the "get_text" virtual function) until the diagnostic
+ printing code "knows" it needs it, thus avoiding doing it e.g. for
+ warnings that are filtered by command-line flags. This virtual
+ function also isolates libcpp and the diagnostics subsystem from
+ the front-end and middle-end-specific code for generating the text
+ for the labels.
+
+ Like the rich_location instances they annotate, range_label instances
+ are intended to be allocated on the stack when generating diagnostics,
+ and to be short-lived. */
+
+class range_label
+{
+ public:
+ virtual ~range_label () {}
+
+ /* Get localized text for the label.
+ The RANGE_IDX is provided, allowing for range_label instances to be
+ shared by multiple ranges if need be (the "flyweight" design pattern). */
+ virtual label_text get_text (unsigned range_idx) const = 0;
+};
+
/* A fix-it hint: a suggested insertion, replacement, or deletion of text.
We handle these three types of edit with one class, by representing
them as replacement of a half-open range:
diff --git a/libcpp/init.c b/libcpp/init.c
index d1697fd..32a5956 100644
--- a/libcpp/init.c
+++ b/libcpp/init.c
@@ -480,8 +480,7 @@ cpp_init_special_builtins (cpp_reader *pfile)
|| pfile->cb.has_attribute == NULL))
continue;
cpp_hashnode *hp = cpp_lookup (pfile, b->name, b->len);
- hp->type = NT_MACRO;
- hp->flags |= NODE_BUILTIN;
+ hp->type = NT_BUILTIN_MACRO;
if (b->always_warn_if_redefined)
hp->flags |= NODE_WARN;
hp->value.builtin = (enum cpp_builtin_type) b->value;
diff --git a/libcpp/internal.h b/libcpp/internal.h
index 782d8e6..59f830c 100644
--- a/libcpp/internal.h
+++ b/libcpp/internal.h
@@ -23,7 +23,7 @@ along with this program; see the file COPYING3. If not see
#define LIBCPP_INTERNAL_H
#include "symtab.h"
-#include "cpp-id-data.h"
+#include "cpplib.h"
#if HAVE_ICONV
#include <iconv.h>
@@ -93,9 +93,8 @@ struct dummy
#define CPP_ALIGN2(size, align) (((size) + ((align) - 1)) & ~((align) - 1))
#define CPP_ALIGN(size) CPP_ALIGN2 (size, DEFAULT_ALIGNMENT)
-#define _cpp_mark_macro_used(NODE) do { \
- if ((NODE)->type == NT_MACRO && !((NODE)->flags & NODE_BUILTIN)) \
- (NODE)->value.macro->used = 1; } while (0)
+#define _cpp_mark_macro_used(NODE) \
+ (cpp_user_macro_p (NODE) ? (NODE)->value.macro->used = 1 : 0)
/* A generic memory buffer, and operations on it. */
typedef struct _cpp_buff _cpp_buff;
@@ -603,6 +602,12 @@ extern const unsigned char _cpp_trigraph_map[UCHAR_MAX + 1];
extern unsigned char _cpp_trigraph_map[UCHAR_MAX + 1];
#endif
+#if !defined (HAVE_UCHAR) && !defined (IN_GCC)
+typedef unsigned char uchar;
+#endif
+
+#define UC (const uchar *) /* Intended use: UC"string" */
+
/* Macros. */
static inline int cpp_in_system_header (cpp_reader *);
@@ -622,13 +627,21 @@ cpp_in_primary_file (cpp_reader *pfile)
}
/* In macro.c */
+extern void _cpp_notify_macro_use (cpp_reader *pfile, cpp_hashnode *node);
+inline void _cpp_maybe_notify_macro_use (cpp_reader *pfile, cpp_hashnode *node)
+{
+ if (!(node->flags & NODE_USED))
+ _cpp_notify_macro_use (pfile, node);
+}
+extern cpp_macro *_cpp_new_macro (cpp_reader *, cpp_macro_kind, void *);
extern void _cpp_free_definition (cpp_hashnode *);
extern bool _cpp_create_definition (cpp_reader *, cpp_hashnode *);
extern void _cpp_pop_context (cpp_reader *);
extern void _cpp_push_text_context (cpp_reader *, cpp_hashnode *,
const unsigned char *, size_t);
-extern bool _cpp_save_parameter (cpp_reader *, cpp_macro *, cpp_hashnode *,
+extern bool _cpp_save_parameter (cpp_reader *, unsigned, cpp_hashnode *,
cpp_hashnode *);
+extern void _cpp_unsave_parameters (cpp_reader *, unsigned);
extern bool _cpp_arguments_ok (cpp_reader *, cpp_macro *, const cpp_hashnode *,
unsigned int);
extern const unsigned char *_cpp_builtin_macro_text (cpp_reader *,
@@ -685,6 +698,14 @@ 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_context *);
extern void _cpp_init_lexer (void);
+static inline void *_cpp_reserve_room (cpp_reader *pfile, size_t have,
+ size_t extra)
+{
+ if (BUFF_ROOM (pfile->a_buff) < (have + extra))
+ _cpp_extend_buff (pfile, &pfile->a_buff, extra);
+ return BUFF_FRONT (pfile->a_buff);
+}
+extern void *_cpp_commit_buff (cpp_reader *pfile, size_t size);
/* In init.c. */
extern void _cpp_maybe_push_include_file (cpp_reader *);
@@ -721,7 +742,7 @@ extern bool _cpp_read_logical_line_trad (cpp_reader *);
extern void _cpp_overlay_buffer (cpp_reader *pfile, const unsigned char *,
size_t);
extern void _cpp_remove_overlay (cpp_reader *);
-extern bool _cpp_create_trad_definition (cpp_reader *, cpp_macro *);
+extern cpp_macro *_cpp_create_trad_definition (cpp_reader *);
extern bool _cpp_expansions_different_trad (const cpp_macro *,
const cpp_macro *);
extern unsigned char *_cpp_copy_replacement_text (const cpp_macro *,
diff --git a/libcpp/lex.c b/libcpp/lex.c
index a2592e0..892cfc4 100644
--- a/libcpp/lex.c
+++ b/libcpp/lex.c
@@ -1627,7 +1627,7 @@ is_macro(cpp_reader *pfile, const uchar *base)
cpp_hashnode *result = CPP_HASHNODE (ht_lookup_with_hash (pfile->hash_table,
base, cur - base, hash, HT_NO_INSERT));
- return !result ? false : (result->type == NT_MACRO);
+ return result && cpp_macro_p (result);
}
/* Returns true if a literal suffix does not have the expected form
@@ -3725,6 +3725,25 @@ _cpp_aligned_alloc (cpp_reader *pfile, size_t len)
return result;
}
+/* Commit or allocate storage from a buffer. */
+
+void *
+_cpp_commit_buff (cpp_reader *pfile, size_t size)
+{
+ void *ptr = BUFF_FRONT (pfile->a_buff);
+
+ if (pfile->hash_table->alloc_subobject)
+ {
+ void *copy = pfile->hash_table->alloc_subobject (size);
+ memcpy (copy, ptr, size);
+ ptr = copy;
+ }
+ else
+ BUFF_FRONT (pfile->a_buff) += size;
+
+ return ptr;
+}
+
/* Say which field of TOK is in use. */
enum cpp_token_fld_kind
diff --git a/libcpp/line-map.c b/libcpp/line-map.c
index a1a765f..73d9444 100644
--- a/libcpp/line-map.c
+++ b/libcpp/line-map.c
@@ -304,6 +304,8 @@ pure_location_p (line_maps *set, source_location loc)
return false;
const line_map *map = linemap_lookup (set, loc);
+ if (map == NULL)
+ return true;
const line_map_ordinary *ordmap = linemap_check_ordinary (map);
if (loc & ((1U << ordmap->m_range_bits) - 1))
@@ -346,6 +348,8 @@ linemap_init (struct line_maps *set,
#else
new (set) line_maps();
#endif
+ /* Set default reallocator (used for initial alloc too). */
+ set->reallocator = xrealloc;
set->highest_location = RESERVED_LOCATION_COUNT - 1;
set->highest_line = RESERVED_LOCATION_COUNT - 1;
set->location_adhoc_data_map.htab =
@@ -353,17 +357,25 @@ linemap_init (struct line_maps *set,
set->builtin_location = builtin_location;
}
+/* Return the ordinary line map from whence MAP was included. Returns
+ NULL if MAP was not an include. */
+
+const line_map_ordinary *
+linemap_included_from_linemap (line_maps *set, const line_map_ordinary *map)
+{
+ return linemap_ordinary_map_lookup (set, linemap_included_from (map));
+}
+
/* Check for and warn about line_maps entered but not exited. */
void
linemap_check_files_exited (struct line_maps *set)
{
- const line_map_ordinary *map;
/* Depending upon whether we are handling preprocessed input or
not, this can be a user error or an ICE. */
- for (map = LINEMAPS_LAST_ORDINARY_MAP (set);
+ for (const line_map_ordinary *map = LINEMAPS_LAST_ORDINARY_MAP (set);
! MAIN_FILE_P (map);
- map = INCLUDED_FROM (set, map))
+ map = linemap_included_from_linemap (set, map))
fprintf (stderr, "line-map.c: file \"%s\" entered but not left\n",
ORDINARY_MAP_FILE_NAME (map));
}
@@ -376,81 +388,59 @@ linemap_check_files_exited (struct line_maps *set)
static struct line_map *
new_linemap (struct line_maps *set, source_location start_location)
{
- struct line_map *result;
- bool macro_map_p = start_location >= LINE_MAP_MAX_LOCATION;
+ bool macro_p = start_location >= LINE_MAP_MAX_LOCATION;
+ unsigned num_maps_allocated = LINEMAPS_ALLOCATED (set, macro_p);
+ unsigned num_maps_used = LINEMAPS_USED (set, macro_p);
- if (LINEMAPS_USED (set, macro_map_p) == LINEMAPS_ALLOCATED (set, macro_map_p))
+ if (num_maps_used == num_maps_allocated)
{
- /* We ran out of allocated line maps. Let's allocate more. */
- size_t alloc_size;
-
- /* Cast away extern "C" from the type of xrealloc. */
- line_map_realloc reallocator = (set->reallocator
- ? set->reallocator
- : (line_map_realloc) xrealloc);
- line_map_round_alloc_size_func round_alloc_size =
- set->round_alloc_size;
-
- size_t map_size = (macro_map_p
- ? sizeof (line_map_macro)
- : sizeof (line_map_ordinary));
+ /* We need more space! */
+ if (!num_maps_allocated)
+ num_maps_allocated = 128;
+ num_maps_allocated *= 2;
+
+ size_t size_of_a_map;
+ void *buffer;
+ if (macro_p)
+ {
+ size_of_a_map = sizeof (line_map_macro);
+ buffer = set->info_macro.maps;
+ }
+ else
+ {
+ size_of_a_map = sizeof (line_map_ordinary);
+ buffer = set->info_ordinary.maps;
+ }
/* We are going to execute some dance to try to reduce the
overhead of the memory allocator, in case we are using the
ggc-page.c one.
The actual size of memory we are going to get back from the
- allocator is the smallest power of 2 that is greater than the
- size we requested. So let's consider that size then. */
-
- alloc_size =
- (2 * LINEMAPS_ALLOCATED (set, macro_map_p) + 256)
- * map_size;
-
- /* Get the actual size of memory that is going to be allocated
- by the allocator. */
- alloc_size = round_alloc_size (alloc_size);
+ allocator may well be larger than what we ask for. Use this
+ hook to find what that size is. */
+ size_t alloc_size
+ = set->round_alloc_size (num_maps_allocated * size_of_a_map);
/* Now alloc_size contains the exact memory size we would get if
we have asked for the initial alloc_size amount of memory.
- Let's get back to the number of macro map that amounts
- to. */
- LINEMAPS_ALLOCATED (set, macro_map_p) =
- alloc_size / map_size;
-
- /* And now let's really do the re-allocation. */
- if (macro_map_p)
- {
- set->info_macro.maps
- = (line_map_macro *) (*reallocator) (set->info_macro.maps,
- (LINEMAPS_ALLOCATED (set, macro_map_p)
- * map_size));
- result = &set->info_macro.maps[LINEMAPS_USED (set, macro_map_p)];
- }
- else
- {
- set->info_ordinary.maps =
- (line_map_ordinary *) (*reallocator) (set->info_ordinary.maps,
- (LINEMAPS_ALLOCATED (set, macro_map_p)
- * map_size));
- result = &set->info_ordinary.maps[LINEMAPS_USED (set, macro_map_p)];
- }
- memset (result, 0,
- ((LINEMAPS_ALLOCATED (set, macro_map_p)
- - LINEMAPS_USED (set, macro_map_p))
- * map_size));
- }
- else
- {
- if (macro_map_p)
- result = &set->info_macro.maps[LINEMAPS_USED (set, macro_map_p)];
+ Let's get back to the number of map that amounts to. */
+ unsigned num_maps = alloc_size / size_of_a_map;
+ buffer = set->reallocator (buffer, num_maps * size_of_a_map);
+ memset ((char *)buffer + num_maps_used * size_of_a_map, 0,
+ (num_maps - num_maps_used) * size_of_a_map);
+ if (macro_p)
+ set->info_macro.maps = (line_map_macro *)buffer;
else
- result = &set->info_ordinary.maps[LINEMAPS_USED (set, macro_map_p)];
+ set->info_ordinary.maps = (line_map_ordinary *)buffer;
+ LINEMAPS_ALLOCATED (set, macro_p) = num_maps;
}
- result->start_location = start_location;
+ line_map *result = (macro_p ? (line_map *)&set->info_macro.maps[num_maps_used]
+ : (line_map *)&set->info_ordinary.maps[num_maps_used]);
+ LINEMAPS_USED (set, macro_p)++;
- LINEMAPS_USED (set, macro_map_p)++;
+ result->start_location = start_location;
return result;
}
@@ -504,6 +494,11 @@ linemap_add (struct line_maps *set, enum lc_reason reason,
}
linemap_assert (reason != LC_ENTER_MACRO);
+
+ if (start_location >= LINE_MAP_MAX_LOCATION)
+ /* We ran out of line map space. */
+ start_location = 0;
+
line_map_ordinary *map
= linemap_check_ordinary (new_linemap (set, start_location));
map->reason = reason;
@@ -514,19 +509,19 @@ linemap_add (struct line_maps *set, enum lc_reason reason,
if (reason == LC_RENAME_VERBATIM)
reason = LC_RENAME;
+ const line_map_ordinary *from = NULL;
if (reason == LC_LEAVE)
{
/* When we are just leaving an "included" file, and jump to the next
location inside the "includer" right after the #include
"included", this variable points the map in use right before the
#include "included", inside the same "includer" file. */
- line_map_ordinary *from;
linemap_assert (!MAIN_FILE_P (map - 1));
/* (MAP - 1) points to the map we are leaving. The
map from which (MAP - 1) got included should be the map
that comes right before MAP in the same file. */
- from = INCLUDED_FROM (set, map - 1);
+ from = linemap_included_from_linemap (set, map - 1);
/* A TO_FILE of NULL is special - we use the natural values. */
if (to_file == NULL)
@@ -558,19 +553,24 @@ linemap_add (struct line_maps *set, enum lc_reason reason,
if (reason == LC_ENTER)
{
- map->included_from =
- set->depth == 0 ? -1 : (int) (LINEMAPS_ORDINARY_USED (set) - 2);
+ if (set->depth == 0)
+ map->included_from = 0;
+ else
+ /* The location of the end of the just-closed map. */
+ map->included_from
+ = (((map[0].start_location - 1 - map[-1].start_location)
+ & ~((1 << map[-1].m_column_and_range_bits) - 1))
+ + map[-1].start_location);
set->depth++;
if (set->trace_includes)
trace_include (set, map);
}
else if (reason == LC_RENAME)
- map->included_from = ORDINARY_MAP_INCLUDER_FILE_INDEX (&map[-1]);
+ map->included_from = linemap_included_from (&map[-1]);
else if (reason == LC_LEAVE)
{
set->depth--;
- map->included_from =
- ORDINARY_MAP_INCLUDER_FILE_INDEX (INCLUDED_FROM (set, map - 1));
+ map->included_from = linemap_included_from (from);
}
return map;
@@ -1781,17 +1781,13 @@ linemap_dump (FILE *stream, struct line_maps *set, unsigned ix, bool is_macro)
if (!is_macro)
{
const line_map_ordinary *ord_map = linemap_check_ordinary (map);
- unsigned includer_ix;
- const line_map_ordinary *includer_map;
-
- includer_ix = ORDINARY_MAP_INCLUDER_FILE_INDEX (ord_map);
- includer_map = includer_ix < LINEMAPS_ORDINARY_USED (set)
- ? LINEMAPS_ORDINARY_MAP_AT (set, includer_ix)
- : NULL;
+ const line_map_ordinary *includer_map
+ = linemap_included_from_linemap (set, ord_map);
fprintf (stream, "File: %s:%d\n", ORDINARY_MAP_FILE_NAME (ord_map),
ORDINARY_MAP_STARTING_LINE_NUMBER (ord_map));
- fprintf (stream, "Included from: [%d] %s\n", includer_ix,
+ fprintf (stream, "Included from: [%d] %s\n",
+ includer_map ? int (includer_map - set->info_ordinary.maps) : -1,
includer_map ? ORDINARY_MAP_FILE_NAME (includer_map) : "None");
}
else
@@ -1841,9 +1837,11 @@ linemap_dump_location (struct line_maps *set,
if (e)
from = "N/A";
else
- from = (INCLUDED_FROM (set, map))
- ? LINEMAP_FILE (INCLUDED_FROM (set, map))
- : "<NULL>";
+ {
+ const line_map_ordinary *from_map
+ = linemap_included_from_linemap (set, map);
+ from = from_map ? LINEMAP_FILE (from_map) : "<NULL>";
+ }
}
/* P: path, L: line, C: column, S: in-system-header, M: map address,
@@ -1997,7 +1995,8 @@ line_table_dump (FILE *stream, struct line_maps *set, unsigned int num_ordinary,
/* Construct a rich_location with location LOC as its initial range. */
-rich_location::rich_location (line_maps *set, source_location loc) :
+rich_location::rich_location (line_maps *set, source_location loc,
+ const range_label *label) :
m_line_table (set),
m_ranges (),
m_column_override (0),
@@ -2006,7 +2005,7 @@ rich_location::rich_location (line_maps *set, source_location loc) :
m_seen_impossible_fixit (false),
m_fixits_cannot_be_auto_applied (false)
{
- add_range (loc, true);
+ add_range (loc, SHOW_RANGE_WITH_CARET, label);
}
/* The destructor for class rich_location. */
@@ -2082,16 +2081,19 @@ rich_location::override_column (int column)
/* Add the given range. */
void
-rich_location::add_range (source_location loc, bool show_caret_p)
+rich_location::add_range (source_location loc,
+ enum range_display_kind range_display_kind,
+ const range_label *label)
{
location_range range;
range.m_loc = loc;
- range.m_show_caret_p = show_caret_p;
+ range.m_range_display_kind = range_display_kind;
+ range.m_label = label;
m_ranges.push (range);
}
/* Add or overwrite the location given by IDX, setting its location to LOC,
- and setting its "should my caret be printed" flag to SHOW_CARET_P.
+ and setting its m_range_display_kind to RANGE_DISPLAY_KIND.
It must either overwrite an existing location, or add one *exactly* on
the end of the array.
@@ -2105,19 +2107,19 @@ rich_location::add_range (source_location loc, bool show_caret_p)
void
rich_location::set_range (unsigned int idx, source_location loc,
- bool show_caret_p)
+ enum range_display_kind range_display_kind)
{
/* We can either overwrite an existing range, or add one exactly
on the end of the array. */
linemap_assert (idx <= m_ranges.count ());
if (idx == m_ranges.count ())
- add_range (loc, show_caret_p);
+ add_range (loc, range_display_kind);
else
{
location_range *locrange = get_range (idx);
locrange->m_loc = loc;
- locrange->m_show_caret_p = show_caret_p;
+ locrange->m_range_display_kind = range_display_kind;
}
if (idx == 0)
diff --git a/libcpp/macro.c b/libcpp/macro.c
index 683f918..3629e83 100644
--- a/libcpp/macro.c
+++ b/libcpp/macro.c
@@ -85,8 +85,9 @@ struct macro_arg_token_iter
struct macro_arg_saved_data {
/* The canonical (UTF-8) spelling of this identifier. */
cpp_hashnode *canonical_node;
- /* The previous value of this identifier. */
+ /* The previous value & type of this identifier. */
union _cpp_hashnode_value value;
+ node_type type;
};
static const char *vaopt_paste_error =
@@ -308,15 +309,14 @@ static void replace_args (cpp_reader *, cpp_hashnode *, cpp_macro *,
macro_arg *, source_location);
static _cpp_buff *funlike_invocation_p (cpp_reader *, cpp_hashnode *,
_cpp_buff **, unsigned *);
-static bool create_iso_definition (cpp_reader *, cpp_macro *);
+static cpp_macro *create_iso_definition (cpp_reader *);
/* #define directive parsing and handling. */
-static cpp_token *alloc_expansion_token (cpp_reader *, cpp_macro *);
-static cpp_token *lex_expansion_token (cpp_reader *, cpp_macro *);
+static cpp_macro *lex_expansion_token (cpp_reader *, cpp_macro *);
static bool warn_of_redefinition (cpp_reader *, cpp_hashnode *,
const cpp_macro *);
-static bool parse_params (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 *);
@@ -342,7 +342,7 @@ int
_cpp_warn_if_unused_macro (cpp_reader *pfile, cpp_hashnode *node,
void *v ATTRIBUTE_UNUSED)
{
- if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN))
+ if (cpp_user_macro_p (node))
{
cpp_macro *macro = node->value.macro;
@@ -1235,13 +1235,14 @@ funlike_invocation_p (cpp_reader *pfile, cpp_hashnode *node,
static inline unsigned int
macro_real_token_count (const cpp_macro *macro)
{
- unsigned int i;
if (__builtin_expect (!macro->extra_tokens, true))
return macro->count;
- for (i = 0; i < macro->count; i++)
- if (macro->exp.tokens[i].type == CPP_PASTE)
- return i;
- abort ();
+
+ for (unsigned i = macro->count; i--;)
+ if (macro->exp.tokens[i].type != CPP_PASTE)
+ return i + 1;
+
+ return 0;
}
/* Push the context of a macro with hash entry NODE onto the context
@@ -1273,17 +1274,7 @@ enter_macro_context (cpp_reader *pfile, cpp_hashnode *node,
function where set this flag to FALSE. */
pfile->about_to_expand_macro_p = true;
- if ((node->flags & NODE_BUILTIN) && !(node->flags & NODE_USED))
- {
- node->flags |= NODE_USED;
- if ((!pfile->cb.user_builtin_macro
- || !pfile->cb.user_builtin_macro (pfile, node))
- && pfile->cb.used_define)
- pfile->cb.used_define (pfile, pfile->directive_line, node);
- }
-
- /* Handle standard macros. */
- if (! (node->flags & NODE_BUILTIN))
+ if (cpp_user_macro_p (node))
{
cpp_macro *macro = node->value.macro;
_cpp_buff *pragma_buff = NULL;
@@ -1329,13 +1320,9 @@ enter_macro_context (cpp_reader *pfile, cpp_hashnode *node,
/* Disable the macro within its expansion. */
node->flags |= NODE_DISABLED;
- if (!(node->flags & NODE_USED))
- {
- node->flags |= NODE_USED;
- if (pfile->cb.used_define)
- pfile->cb.used_define (pfile, pfile->directive_line, node);
- }
-
+ /* Laziness can only affect the expansion tokens of the macro,
+ not its fun-likeness or parameters. */
+ _cpp_maybe_notify_macro_use (pfile, node);
if (pfile->cb.used)
pfile->cb.used (pfile, location, node);
@@ -1413,10 +1400,8 @@ enter_macro_context (cpp_reader *pfile, cpp_hashnode *node,
source_location expand_loc;
if (/* The top-level macro invocation that triggered the expansion
- we are looking at is with a standard macro ... */
- !(pfile->top_most_macro_node->flags & NODE_BUILTIN)
- /* ... and it's a function-like macro invocation, */
- && pfile->top_most_macro_node->value.macro->fun_like
+ we are looking at is with a function-like user macro ... */
+ cpp_fun_like_macro_p (pfile->top_most_macro_node)
/* ... and we are tracking the macro expansion. */
&& CPP_OPTION (pfile, track_macro_expansion))
/* Then the location of the end of the macro invocation is the
@@ -1776,7 +1761,7 @@ replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro,
arg->stringified = stringify_arg (pfile, arg);
}
else if ((src->flags & PASTE_LEFT)
- || (src > macro->exp.tokens && (src[-1].flags & PASTE_LEFT)))
+ || (src != macro->exp.tokens && (src[-1].flags & PASTE_LEFT)))
total += arg->count - 1;
else
{
@@ -2746,7 +2731,7 @@ cpp_get_token_1 (cpp_reader *pfile, source_location *location)
node = result->val.node.node;
- if (node->type != NT_MACRO || (result->flags & NO_EXPAND))
+ if (node->type == NT_VOID || (result->flags & NO_EXPAND))
break;
if (!(node->flags & NODE_DISABLED))
@@ -2996,7 +2981,6 @@ static bool
warn_of_redefinition (cpp_reader *pfile, cpp_hashnode *node,
const cpp_macro *macro2)
{
- const cpp_macro *macro1;
unsigned int i;
/* Some redefinitions need to be warned about regardless. */
@@ -3005,9 +2989,7 @@ warn_of_redefinition (cpp_reader *pfile, cpp_hashnode *node,
/* Suppress warnings for builtins that lack the NODE_WARN flag,
unless Wbuiltin-macro-redefined. */
- if (node->flags & NODE_BUILTIN
- && (!pfile->cb.user_builtin_macro
- || !pfile->cb.user_builtin_macro (pfile, node)))
+ if (cpp_builtin_macro_p (node))
return CPP_OPTION (pfile, warn_builtin_macro_redefined);
/* Redefinitions of conditional (context-sensitive) macros, on
@@ -3015,9 +2997,17 @@ warn_of_redefinition (cpp_reader *pfile, cpp_hashnode *node,
if (node->flags & NODE_CONDITIONAL)
return false;
+ cpp_macro *macro1 = node->value.macro;
+ if (macro1->lazy)
+ {
+ /* We don't want to mark MACRO as used, but do need to finalize
+ its laziness. */
+ pfile->cb.user_lazy_macro (pfile, macro1, macro1->lazy - 1);
+ macro1->lazy = 0;
+ }
+
/* Redefinition of a macro is allowed if and only if the old and new
definitions are the same. (6.10.3 paragraph 2). */
- macro1 = node->value.macro;
/* Don't check count here as it can be different in valid
traditional redefinitions with just whitespace differences. */
@@ -3028,7 +3018,7 @@ warn_of_redefinition (cpp_reader *pfile, cpp_hashnode *node,
/* Check parameter spellings. */
for (i = 0; i < macro1->paramc; i++)
- if (macro1->params[i] != macro2->params[i])
+ if (macro1->parm.params[i] != macro2->parm.params[i])
return true;
/* Check the replacement text or tokens. */
@@ -3051,124 +3041,164 @@ _cpp_free_definition (cpp_hashnode *h)
{
/* Macros and assertions no longer have anything to free. */
h->type = NT_VOID;
- /* Clear builtin flag in case of redefinition. */
- h->flags &= ~(NODE_BUILTIN | NODE_DISABLED | NODE_USED);
+ h->value.answers = NULL;
+ h->flags &= ~(NODE_DISABLED | NODE_USED);
}
/* Save parameter NODE (spelling SPELLING) to the parameter list of
- macro MACRO. Returns zero on success, nonzero if the parameter is
- a duplicate. */
+ macro MACRO. Returns true on success, false on failure. */
bool
-_cpp_save_parameter (cpp_reader *pfile, cpp_macro *macro, cpp_hashnode *node,
+_cpp_save_parameter (cpp_reader *pfile, unsigned n, cpp_hashnode *node,
cpp_hashnode *spelling)
{
- unsigned int len;
/* Constraint 6.10.3.6 - duplicate parameter names. */
- if (node->flags & NODE_MACRO_ARG)
+ if (node->type == NT_MACRO_ARG)
{
cpp_error (pfile, CPP_DL_ERROR, "duplicate macro parameter \"%s\"",
NODE_NAME (node));
- return true;
+ return false;
}
- if (BUFF_ROOM (pfile->a_buff)
- < (macro->paramc + 1) * sizeof (cpp_hashnode *))
- _cpp_extend_buff (pfile, &pfile->a_buff, sizeof (cpp_hashnode *));
-
- ((cpp_hashnode **) BUFF_FRONT (pfile->a_buff))[macro->paramc++] = spelling;
- node->flags |= NODE_MACRO_ARG;
- len = macro->paramc * sizeof (struct macro_arg_saved_data);
+ unsigned len = (n + 1) * sizeof (struct macro_arg_saved_data);
if (len > pfile->macro_buffer_len)
{
- pfile->macro_buffer = XRESIZEVEC (unsigned char, pfile->macro_buffer,
- len);
+ pfile->macro_buffer
+ = XRESIZEVEC (unsigned char, pfile->macro_buffer, len);
pfile->macro_buffer_len = len;
}
- struct macro_arg_saved_data save;
- save.value = node->value;
- save.canonical_node = node;
- ((struct macro_arg_saved_data *) pfile->macro_buffer)[macro->paramc - 1]
- = save;
- node->value.arg_index = macro->paramc;
- return false;
+ macro_arg_saved_data *saved = (macro_arg_saved_data *)pfile->macro_buffer;
+ saved[n].canonical_node = node;
+ saved[n].value = node->value;
+ saved[n].type = node->type;
+
+ void *base = _cpp_reserve_room (pfile, n * sizeof (cpp_hashnode *),
+ sizeof (cpp_hashnode *));
+ ((cpp_hashnode **)base)[n] = spelling;
+
+ /* Morph into a macro arg. */
+ node->type = NT_MACRO_ARG;
+ /* Index is 1 based. */
+ node->value.arg_index = n + 1;
+
+ return true;
}
-/* Check the syntax of the parameters in a MACRO definition. Returns
- false if an error occurs. */
+/* Restore the parameters to their previous state. */
+void
+_cpp_unsave_parameters (cpp_reader *pfile, unsigned n)
+{
+ /* Clear the fast argument lookup indices. */
+ while (n--)
+ {
+ struct macro_arg_saved_data *save =
+ &((struct macro_arg_saved_data *) pfile->macro_buffer)[n];
+
+ struct cpp_hashnode *node = save->canonical_node;
+ node->type = save->type;
+ node->value = save->value;
+ }
+}
+
+/* Check the syntax of the parameters in a MACRO definition. Return
+ false on failure. Set *N_PTR and *VARADIC_PTR as appropriate.
+ '(' ')'
+ '(' parm-list ',' last-parm ')'
+ '(' last-parm ')'
+ parm-list: name
+ | parm-list, name
+ last-parm: name
+ | name '...'
+ | '...'
+*/
+
static bool
-parse_params (cpp_reader *pfile, cpp_macro *macro)
+parse_params (cpp_reader *pfile, unsigned *n_ptr, bool *varadic_ptr)
{
- unsigned int prev_ident = 0;
+ unsigned nparms = 0;
+ bool ok = false;
- for (;;)
+ for (bool prev_ident = false;;)
{
const cpp_token *token = _cpp_lex_token (pfile);
switch (token->type)
{
- default:
+ case CPP_COMMENT:
/* Allow/ignore comments in parameter lists if we are
preserving comments in macro expansions. */
- if (token->type == CPP_COMMENT
- && ! CPP_OPTION (pfile, discard_comments_in_macro_exp))
- continue;
+ if (!CPP_OPTION (pfile, discard_comments_in_macro_exp))
+ break;
- cpp_error (pfile, CPP_DL_ERROR,
- "\"%s\" may not appear in macro parameter list",
- cpp_token_as_text (pfile, token));
- return false;
+ /* FALLTHRU */
+ default:
+ bad:
+ {
+ const char *const msgs[5] =
+ {
+ N_("expected parameter name, found \"%s\""),
+ N_("expected ',' or ')', found \"%s\""),
+ N_("expected parameter name before end of line"),
+ N_("expected ')' before end of line"),
+ N_("expected ')' after \"...\"")
+ };
+ unsigned ix = prev_ident;
+ const unsigned char *as_text = NULL;
+ if (*varadic_ptr)
+ ix = 4;
+ else if (token->type == CPP_EOF)
+ ix += 2;
+ else
+ as_text = cpp_token_as_text (pfile, token);
+ cpp_error (pfile, CPP_DL_ERROR, msgs[ix], as_text);
+ }
+ goto out;
case CPP_NAME:
- if (prev_ident)
- {
- cpp_error (pfile, CPP_DL_ERROR,
- "macro parameters must be comma-separated");
- return false;
- }
- prev_ident = 1;
-
- if (_cpp_save_parameter (pfile, macro, token->val.node.node,
- token->val.node.spelling))
- return false;
- continue;
+ if (prev_ident || *varadic_ptr)
+ goto bad;
+ prev_ident = true;
+
+ if (!_cpp_save_parameter (pfile, nparms, token->val.node.node,
+ token->val.node.spelling))
+ goto out;
+ nparms++;
+ break;
case CPP_CLOSE_PAREN:
- if (prev_ident || macro->paramc == 0)
- return true;
+ if (prev_ident || !nparms || *varadic_ptr)
+ {
+ ok = true;
+ goto out;
+ }
- /* Fall through to pick up the error. */
/* FALLTHRU */
case CPP_COMMA:
- if (!prev_ident)
- {
- cpp_error (pfile, CPP_DL_ERROR, "parameter name missing");
- return false;
- }
- prev_ident = 0;
- continue;
+ if (!prev_ident || *varadic_ptr)
+ goto bad;
+ prev_ident = false;
+ break;
case CPP_ELLIPSIS:
- macro->variadic = 1;
+ if (*varadic_ptr)
+ goto bad;
+ *varadic_ptr = true;
if (!prev_ident)
{
- _cpp_save_parameter (pfile, macro,
+ /* An ISO bare ellipsis. */
+ _cpp_save_parameter (pfile, nparms,
pfile->spec_nodes.n__VA_ARGS__,
pfile->spec_nodes.n__VA_ARGS__);
+ nparms++;
pfile->state.va_args_ok = 1;
if (! CPP_OPTION (pfile, c99)
&& CPP_OPTION (pfile, cpp_pedantic)
&& CPP_OPTION (pfile, warn_variadic_macros))
- {
- if (CPP_OPTION (pfile, cplusplus))
- cpp_pedwarning
- (pfile, CPP_W_VARIADIC_MACROS,
- "anonymous variadic macros were introduced in C++11");
- else
- cpp_pedwarning
- (pfile, CPP_W_VARIADIC_MACROS,
- "anonymous variadic macros were introduced in C99");
- }
+ cpp_pedwarning
+ (pfile, CPP_W_VARIADIC_MACROS,
+ CPP_OPTION (pfile, cplusplus)
+ ? N_("anonymous variadic macros were introduced in C++11")
+ : N_("anonymous variadic macros were introduced in C99"));
else if (CPP_OPTION (pfile, cpp_warn_c90_c99_compat) > 0
&& ! CPP_OPTION (pfile, cplusplus))
cpp_error (pfile, CPP_DL_WARNING,
@@ -3176,54 +3206,38 @@ parse_params (cpp_reader *pfile, cpp_macro *macro)
}
else if (CPP_OPTION (pfile, cpp_pedantic)
&& CPP_OPTION (pfile, warn_variadic_macros))
- {
- if (CPP_OPTION (pfile, cplusplus))
- cpp_pedwarning (pfile, CPP_W_VARIADIC_MACROS,
- "ISO C++ does not permit named variadic macros");
- else
- cpp_pedwarning (pfile, CPP_W_VARIADIC_MACROS,
- "ISO C does not permit named variadic macros");
- }
-
- /* We're at the end, and just expect a closing parenthesis. */
- token = _cpp_lex_token (pfile);
- if (token->type == CPP_CLOSE_PAREN)
- return true;
- /* Fall through. */
-
- case CPP_EOF:
- cpp_error (pfile, CPP_DL_ERROR, "missing ')' in macro parameter list");
- return false;
+ cpp_pedwarning (pfile, CPP_W_VARIADIC_MACROS,
+ CPP_OPTION (pfile, cplusplus)
+ ? N_("ISO C++ does not permit named variadic macros")
+ : N_("ISO C does not permit named variadic macros"));
+ break;
}
}
-}
-/* Allocate room for a token from a macro's replacement list. */
-static cpp_token *
-alloc_expansion_token (cpp_reader *pfile, cpp_macro *macro)
-{
- if (BUFF_ROOM (pfile->a_buff) < (macro->count + 1) * sizeof (cpp_token))
- _cpp_extend_buff (pfile, &pfile->a_buff, sizeof (cpp_token));
+ out:
+ *n_ptr = nparms;
- return &((cpp_token *) BUFF_FRONT (pfile->a_buff))[macro->count++];
+ return ok;
}
/* Lex a token from the expansion of MACRO, but mark parameters as we
find them and warn of traditional stringification. */
-static cpp_token *
+static cpp_macro *
lex_expansion_token (cpp_reader *pfile, cpp_macro *macro)
{
- cpp_token *token, *saved_cur_token;
-
- saved_cur_token = pfile->cur_token;
- pfile->cur_token = alloc_expansion_token (pfile, macro);
- token = _cpp_lex_direct (pfile);
+ macro = (cpp_macro *)_cpp_reserve_room (pfile,
+ sizeof (cpp_macro) - sizeof (cpp_token)
+ + macro->count * sizeof (cpp_token),
+ sizeof (cpp_token));
+ cpp_token *saved_cur_token = pfile->cur_token;
+ pfile->cur_token = &macro->exp.tokens[macro->count];
+ cpp_token *token = _cpp_lex_direct (pfile);
pfile->cur_token = saved_cur_token;
/* Is this a parameter? */
- if (token->type == CPP_NAME
- && (token->val.node.node->flags & NODE_MACRO_ARG) != 0)
+ if (token->type == CPP_NAME && token->val.node.node->type == NT_MACRO_ARG)
{
+ /* Morph into a parameter reference. */
cpp_hashnode *spelling = token->val.node.spelling;
token->type = CPP_MACRO_ARG;
token->val.macro_arg.arg_no = token->val.node.node->value.arg_index;
@@ -3233,62 +3247,58 @@ lex_expansion_token (cpp_reader *pfile, cpp_macro *macro)
&& (token->type == CPP_STRING || token->type == CPP_CHAR))
check_trad_stringification (pfile, macro, &token->val.str);
- return token;
+ return macro;
}
-static bool
-create_iso_definition (cpp_reader *pfile, cpp_macro *macro)
+static cpp_macro *
+create_iso_definition (cpp_reader *pfile)
{
- cpp_token *token;
- const cpp_token *ctoken;
bool following_paste_op = false;
const char *paste_op_error_msg =
N_("'##' cannot appear at either end of a macro expansion");
unsigned int num_extra_tokens = 0;
+ unsigned nparms = 0;
+ cpp_hashnode **params = NULL;
+ bool varadic = false;
+ bool ok = false;
+ cpp_macro *macro = NULL;
+
+ /* Look at the first token, to see if this is a function-like
+ macro. */
+ cpp_token first;
+ cpp_token *saved_cur_token = pfile->cur_token;
+ pfile->cur_token = &first;
+ cpp_token *token = _cpp_lex_direct (pfile);
+ pfile->cur_token = saved_cur_token;
- /* Get the first token of the expansion (or the '(' of a
- function-like macro). */
- ctoken = _cpp_lex_token (pfile);
-
- if (ctoken->type == CPP_OPEN_PAREN && !(ctoken->flags & PREV_WHITE))
+ if (token->flags & PREV_WHITE)
+ /* Preceeded by space, must be part of expansion. */;
+ else if (token->type == CPP_OPEN_PAREN)
{
- bool ok = parse_params (pfile, macro);
- macro->params = (cpp_hashnode **) BUFF_FRONT (pfile->a_buff);
- if (!ok)
- return false;
+ /* An open-paren, get a parameter list. */
+ if (!parse_params (pfile, &nparms, &varadic))
+ goto out;
- /* Success. Commit or allocate the parameter array. */
- if (pfile->hash_table->alloc_subobject)
- {
- cpp_hashnode **params =
- (cpp_hashnode **) pfile->hash_table->alloc_subobject
- (sizeof (cpp_hashnode *) * macro->paramc);
- memcpy (params, macro->params,
- sizeof (cpp_hashnode *) * macro->paramc);
- macro->params = params;
- }
- else
- BUFF_FRONT (pfile->a_buff) = (uchar *) &macro->params[macro->paramc];
- macro->fun_like = 1;
+ params = (cpp_hashnode **)_cpp_commit_buff
+ (pfile, sizeof (cpp_hashnode *) * nparms);
+ token = NULL;
}
- else if (ctoken->type != CPP_EOF && !(ctoken->flags & PREV_WHITE))
+ else if (token->type != CPP_EOF
+ && !(token->type == CPP_COMMENT
+ && ! CPP_OPTION (pfile, discard_comments_in_macro_exp)))
{
/* While ISO C99 requires whitespace before replacement text
in a macro definition, ISO C90 with TC1 allows characters
from the basic source character set there. */
if (CPP_OPTION (pfile, c99))
- {
- if (CPP_OPTION (pfile, cplusplus))
- cpp_error (pfile, CPP_DL_PEDWARN,
- "ISO C++11 requires whitespace after the macro name");
- else
- cpp_error (pfile, CPP_DL_PEDWARN,
- "ISO C99 requires whitespace after the macro name");
- }
+ cpp_error (pfile, CPP_DL_PEDWARN,
+ CPP_OPTION (pfile, cplusplus)
+ ? N_("ISO C++11 requires whitespace after the macro name")
+ : N_("ISO C99 requires whitespace after the macro name"));
else
{
int warntype = CPP_DL_WARNING;
- switch (ctoken->type)
+ switch (token->type)
{
case CPP_ATSIGN:
case CPP_AT_NAME:
@@ -3299,7 +3309,7 @@ create_iso_definition (cpp_reader *pfile, cpp_macro *macro)
case CPP_OTHER:
/* Basic character set sans letters, digits and _. */
if (strchr ("!\"#%&'()*+,-./:;<=>?[\\]^{|}~",
- ctoken->val.str.text[0]) == NULL)
+ token->val.str.text[0]) == NULL)
warntype = CPP_DL_PEDWARN;
break;
default:
@@ -3312,19 +3322,32 @@ create_iso_definition (cpp_reader *pfile, cpp_macro *macro)
}
}
- if (macro->fun_like)
- token = lex_expansion_token (pfile, macro);
+ macro = _cpp_new_macro (pfile, cmk_macro,
+ _cpp_reserve_room (pfile, 0, sizeof (cpp_macro)));
+
+ if (!token)
+ {
+ macro->variadic = varadic;
+ macro->paramc = nparms;
+ macro->parm.params = params;
+ macro->fun_like = true;
+ }
else
{
- token = alloc_expansion_token (pfile, macro);
- *token = *ctoken;
+ /* Preserve the token we peeked, there is already a single slot for it. */
+ macro->exp.tokens[0] = *token;
+ token = &macro->exp.tokens[0];
+ macro->count = 1;
}
- /* The argument doesn't matter here. */
- vaopt_state vaopt_tracker (pfile, macro->variadic, true);
-
- for (;;)
+ for (vaopt_state vaopt_tracker (pfile, macro->variadic, true);; token = NULL)
{
+ if (!token)
+ {
+ macro = lex_expansion_token (pfile, macro);
+ token = &macro->exp.tokens[macro->count++];
+ }
+
/* Check the stringifying # constraint 6.10.3.2.1 of
function-like macros when lexing the subsequent token. */
if (macro->count > 1 && token[-1].type == CPP_HASH && macro->fun_like)
@@ -3346,7 +3369,7 @@ create_iso_definition (cpp_reader *pfile, cpp_macro *macro)
{
cpp_error (pfile, CPP_DL_ERROR,
"'#' is not followed by a macro parameter");
- return false;
+ goto out;
}
}
@@ -3358,8 +3381,10 @@ create_iso_definition (cpp_reader *pfile, cpp_macro *macro)
if (following_paste_op)
{
cpp_error (pfile, CPP_DL_ERROR, paste_op_error_msg);
- return false;
+ goto out;
}
+ if (!vaopt_tracker.completed ())
+ goto out;
break;
}
@@ -3371,17 +3396,19 @@ create_iso_definition (cpp_reader *pfile, cpp_macro *macro)
if (macro->count == 1)
{
cpp_error (pfile, CPP_DL_ERROR, paste_op_error_msg);
- return false;
+ goto out;
}
- if (token[-1].flags & PASTE_LEFT)
+ if (following_paste_op)
{
- macro->extra_tokens = 1;
+ /* Consecutive paste operators. This one will be moved
+ to the end. */
num_extra_tokens++;
token->val.token_no = macro->count - 1;
}
else
{
+ /* Drop the paste operator. */
--macro->count;
token[-1].flags |= PASTE_LEFT;
if (token->flags & DIGRAPH)
@@ -3389,78 +3416,67 @@ create_iso_definition (cpp_reader *pfile, cpp_macro *macro)
if (token->flags & PREV_WHITE)
token[-1].flags |= SP_PREV_WHITE;
}
+ following_paste_op = true;
}
+ else
+ following_paste_op = false;
if (vaopt_tracker.update (token) == vaopt_state::ERROR)
- return false;
-
- following_paste_op = (token->type == CPP_PASTE);
- token = lex_expansion_token (pfile, macro);
+ goto out;
}
- if (!vaopt_tracker.completed ())
- return false;
-
- macro->exp.tokens = (cpp_token *) BUFF_FRONT (pfile->a_buff);
- macro->traditional = 0;
+ /* We're committed to winning now. */
+ ok = true;
/* Don't count the CPP_EOF. */
macro->count--;
+ macro = (cpp_macro *)_cpp_commit_buff
+ (pfile, sizeof (cpp_macro) - sizeof (cpp_token)
+ + sizeof (cpp_token) * macro->count);
+
/* Clear whitespace on first token for warn_of_redefinition(). */
if (macro->count)
macro->exp.tokens[0].flags &= ~PREV_WHITE;
- /* Commit or allocate the memory. */
- if (pfile->hash_table->alloc_subobject)
+ if (num_extra_tokens)
{
- cpp_token *tokns =
- (cpp_token *) pfile->hash_table->alloc_subobject (sizeof (cpp_token)
- * macro->count);
- if (num_extra_tokens)
- {
- /* Place second and subsequent ## or %:%: tokens in
- sequences of consecutive such tokens at the end of the
- list to preserve information about where they appear, how
- they are spelt and whether they are preceded by
- whitespace without otherwise interfering with macro
- expansion. */
- cpp_token *normal_dest = tokns;
- cpp_token *extra_dest = tokns + macro->count - num_extra_tokens;
- unsigned int i;
- for (i = 0; i < macro->count; i++)
- {
- if (macro->exp.tokens[i].type == CPP_PASTE)
- *extra_dest++ = macro->exp.tokens[i];
- else
- *normal_dest++ = macro->exp.tokens[i];
- }
- }
- else
- memcpy (tokns, macro->exp.tokens, sizeof (cpp_token) * macro->count);
- macro->exp.tokens = tokns;
+ /* Place second and subsequent ## or %:%: tokens in sequences of
+ consecutive such tokens at the end of the list to preserve
+ information about where they appear, how they are spelt and
+ whether they are preceded by whitespace without otherwise
+ interfering with macro expansion. Remember, this is
+ extremely rare, so efficiency is not a priority. */
+ cpp_token *temp = (cpp_token *)_cpp_reserve_room
+ (pfile, 0, num_extra_tokens * sizeof (cpp_token));
+ unsigned extra_ix = 0, norm_ix = 0;
+ cpp_token *exp = macro->exp.tokens;
+ for (unsigned ix = 0; ix != macro->count; ix++)
+ if (exp[ix].type == CPP_PASTE)
+ temp[extra_ix++] = exp[ix];
+ else
+ exp[norm_ix++] = exp[ix];
+ memcpy (&exp[norm_ix], temp, num_extra_tokens * sizeof (cpp_token));
+
+ /* Record there are extra tokens. */
+ macro->extra_tokens = 1;
}
- else
- BUFF_FRONT (pfile->a_buff) = (uchar *) &macro->exp.tokens[macro->count];
- return true;
+ out:
+ pfile->state.va_args_ok = 0;
+ _cpp_unsave_parameters (pfile, nparms);
+
+ return ok ? macro : NULL;
}
-/* Parse a macro and save its expansion. Returns nonzero on success. */
-bool
-_cpp_create_definition (cpp_reader *pfile, cpp_hashnode *node)
+cpp_macro *
+_cpp_new_macro (cpp_reader *pfile, cpp_macro_kind kind, void *placement)
{
- cpp_macro *macro;
- unsigned int i;
- bool ok;
+ cpp_macro *macro = (cpp_macro *) placement;
- if (pfile->hash_table->alloc_subobject)
- macro = (cpp_macro *) pfile->hash_table->alloc_subobject
- (sizeof (cpp_macro));
- else
- macro = (cpp_macro *) _cpp_aligned_alloc (pfile, sizeof (cpp_macro));
macro->line = pfile->directive_line;
- macro->params = 0;
+ macro->parm.params = 0;
+ macro->lazy = 0;
macro->paramc = 0;
macro->variadic = 0;
macro->used = !CPP_OPTION (pfile, warn_unused_macros);
@@ -3470,62 +3486,51 @@ _cpp_create_definition (cpp_reader *pfile, cpp_hashnode *node)
/* To suppress some diagnostics. */
macro->syshdr = pfile->buffer && pfile->buffer->sysp != 0;
- if (CPP_OPTION (pfile, traditional))
- ok = _cpp_create_trad_definition (pfile, macro);
- else
- {
- ok = create_iso_definition (pfile, macro);
+ macro->kind = kind;
- /* We set the type for SEEN_EOL() in directives.c.
-
- Longer term we should lex the whole line before coming here,
- and just copy the expansion. */
+ return macro;
+}
- /* Stop the lexer accepting __VA_ARGS__. */
- pfile->state.va_args_ok = 0;
- }
+/* Parse a macro and save its expansion. Returns nonzero on success. */
+bool
+_cpp_create_definition (cpp_reader *pfile, cpp_hashnode *node)
+{
+ cpp_macro *macro;
- /* Clear the fast argument lookup indices. */
- for (i = macro->paramc; i-- > 0; )
- {
- struct macro_arg_saved_data *save =
- &((struct macro_arg_saved_data *) pfile->macro_buffer)[i];
- struct cpp_hashnode *node = save->canonical_node;
- node->flags &= ~ NODE_MACRO_ARG;
- node->value = save->value;
- }
+ if (CPP_OPTION (pfile, traditional))
+ macro = _cpp_create_trad_definition (pfile);
+ else
+ macro = create_iso_definition (pfile);
- if (!ok)
- return ok;
+ if (!macro)
+ return false;
- if (node->type == NT_MACRO)
+ if (cpp_macro_p (node))
{
if (CPP_OPTION (pfile, warn_unused_macros))
_cpp_warn_if_unused_macro (pfile, node, NULL);
if (warn_of_redefinition (pfile, node, macro))
{
- const int reason = ((node->flags & NODE_BUILTIN)
- && !(node->flags & NODE_WARN))
- ? CPP_W_BUILTIN_MACRO_REDEFINED : CPP_W_NONE;
+ const int reason
+ = (cpp_builtin_macro_p (node) && !(node->flags & NODE_WARN))
+ ? CPP_W_BUILTIN_MACRO_REDEFINED : CPP_W_NONE;
bool warned =
cpp_pedwarning_with_line (pfile, reason,
pfile->directive_line, 0,
"\"%s\" redefined", NODE_NAME (node));
- if (warned && node->type == NT_MACRO && !(node->flags & NODE_BUILTIN))
+ if (warned && cpp_user_macro_p (node))
cpp_error_with_line (pfile, CPP_DL_NOTE,
node->value.macro->line, 0,
"this is the location of the previous definition");
}
+ _cpp_free_definition (node);
}
- if (node->type != NT_VOID)
- _cpp_free_definition (node);
-
/* Enter definition in hash table. */
- node->type = NT_MACRO;
+ node->type = NT_USER_MACRO;
node->value.macro = macro;
if (! ustrncmp (NODE_NAME (node), DSC ("__STDC_"))
&& ustrcmp (NODE_NAME (node), (const uchar *) "__STDC_FORMAT_MACROS")
@@ -3541,7 +3546,52 @@ _cpp_create_definition (cpp_reader *pfile, cpp_hashnode *node)
conditional flag */
node->flags &= ~NODE_CONDITIONAL;
- return ok;
+ return true;
+}
+
+extern void
+cpp_define_lazily (cpp_reader *pfile, cpp_hashnode *node, unsigned num)
+{
+ cpp_macro *macro = node->value.macro;
+
+ gcc_checking_assert (pfile->cb.user_lazy_macro && macro && num < UCHAR_MAX);
+
+ macro->lazy = num + 1;
+}
+
+/* Notify the use of NODE in a macro-aware context (i.e. expanding it,
+ or testing its existance). Also applies any lazy definition. */
+
+extern void
+_cpp_notify_macro_use (cpp_reader *pfile, cpp_hashnode *node)
+{
+ node->flags |= NODE_USED;
+ switch (node->type)
+ {
+ case NT_USER_MACRO:
+ {
+ cpp_macro *macro = node->value.macro;
+ if (macro->lazy)
+ {
+ pfile->cb.user_lazy_macro (pfile, macro, macro->lazy - 1);
+ macro->lazy = 0;
+ }
+ }
+ /* FALLTHROUGH. */
+
+ case NT_BUILTIN_MACRO:
+ if (pfile->cb.used_define)
+ pfile->cb.used_define (pfile, pfile->directive_line, node);
+ break;
+
+ case NT_VOID:
+ if (pfile->cb.used_undef)
+ pfile->cb.used_undef (pfile, pfile->directive_line, node);
+ break;
+
+ default:
+ abort ();
+ }
}
/* Warn if a token in STRING matches one of a function-like MACRO's
@@ -3572,7 +3622,7 @@ check_trad_stringification (cpp_reader *pfile, const cpp_macro *macro,
identifier inside the string matches one of them. */
for (i = 0; i < macro->paramc; i++)
{
- const cpp_hashnode *node = macro->params[i];
+ const cpp_hashnode *node = macro->parm.params[i];
if (NODE_LEN (node) == len
&& !memcmp (p, NODE_NAME (node), len))
@@ -3586,15 +3636,6 @@ check_trad_stringification (cpp_reader *pfile, const cpp_macro *macro,
}
}
-/* Returns true of NODE is a function-like macro. */
-bool
-cpp_fun_like_macro_p (cpp_hashnode *node)
-{
- return (node->type == NT_MACRO
- && (node->flags & (NODE_BUILTIN | NODE_MACRO_ARG)) == 0
- && node->value.macro->fun_like);
-}
-
/* Returns the name, arguments and expansion of a macro, in a format
suitable to be read back in again, and therefore also for DWARF 2
debugging info. e.g. "PASTE(X, Y) X ## Y", or "MACNAME EXPANSION".
@@ -3604,23 +3645,12 @@ const unsigned char *
cpp_macro_definition (cpp_reader *pfile, cpp_hashnode *node)
{
unsigned int i, len;
- const cpp_macro *macro;
unsigned char *buffer;
- if (node->type != NT_MACRO || (node->flags & NODE_BUILTIN))
- {
- if (node->type != NT_MACRO
- || !pfile->cb.user_builtin_macro
- || !pfile->cb.user_builtin_macro (pfile, node))
- {
- cpp_error (pfile, CPP_DL_ICE,
- "invalid hash type %d in cpp_macro_definition",
- node->type);
- return 0;
- }
- }
+ gcc_checking_assert (cpp_user_macro_p (node));
+
+ const cpp_macro *macro = node->value.macro;
- macro = node->value.macro;
/* Calculate length. */
len = NODE_LEN (node) * 10 + 2; /* ' ' and NUL. */
if (macro->fun_like)
@@ -3628,7 +3658,7 @@ cpp_macro_definition (cpp_reader *pfile, cpp_hashnode *node)
len += 4; /* "()" plus possible final ".." of named
varargs (we have + 1 below). */
for (i = 0; i < macro->paramc; i++)
- len += NODE_LEN (macro->params[i]) + 1; /* "," */
+ len += NODE_LEN (macro->parm.params[i]) + 1; /* "," */
}
/* This should match below where we fill in the buffer. */
@@ -3639,7 +3669,7 @@ cpp_macro_definition (cpp_reader *pfile, cpp_hashnode *node)
unsigned int count = macro_real_token_count (macro);
for (i = 0; i < count; i++)
{
- cpp_token *token = &macro->exp.tokens[i];
+ const cpp_token *token = &macro->exp.tokens[i];
if (token->type == CPP_MACRO_ARG)
len += NODE_LEN (token->val.macro_arg.spelling);
@@ -3672,7 +3702,7 @@ cpp_macro_definition (cpp_reader *pfile, cpp_hashnode *node)
*buffer++ = '(';
for (i = 0; i < macro->paramc; i++)
{
- cpp_hashnode *param = macro->params[i];
+ cpp_hashnode *param = macro->parm.params[i];
if (param != pfile->spec_nodes.n__VA_ARGS__)
{
@@ -3703,7 +3733,7 @@ cpp_macro_definition (cpp_reader *pfile, cpp_hashnode *node)
unsigned int count = macro_real_token_count (macro);
for (i = 0; i < count; i++)
{
- cpp_token *token = &macro->exp.tokens[i];
+ const cpp_token *token = &macro->exp.tokens[i];
if (token->flags & PREV_WHITE)
*buffer++ = ' ';
diff --git a/libcpp/pch.c b/libcpp/pch.c
index 997c4da..04d7094 100644
--- a/libcpp/pch.c
+++ b/libcpp/pch.c
@@ -50,50 +50,47 @@ static int
write_macdef (cpp_reader *pfile, cpp_hashnode *hn, void *file_p)
{
FILE *f = (FILE *) file_p;
+ bool is_void = false;
switch (hn->type)
{
case NT_VOID:
if (! (hn->flags & NODE_POISONED))
return 1;
- /* XXX Really fallthru? */
- /* FALLTHRU */
+ is_void = true;
+ goto poisoned;
- case NT_MACRO:
- if ((hn->flags & NODE_BUILTIN)
- && (!pfile->cb.user_builtin_macro
- || !pfile->cb.user_builtin_macro (pfile, hn)))
- return 1;
-
- {
- struct macrodef_struct s;
- const unsigned char *defn;
+ case NT_BUILTIN_MACRO:
+ return 1;
- s.name_length = NODE_LEN (hn);
- s.flags = hn->flags & NODE_POISONED;
+ case NT_USER_MACRO:
+ if (hn->value.macro->kind != cmk_assert)
+ {
+ poisoned:
+ struct macrodef_struct s;
+ const unsigned char *defn;
- if (hn->type == NT_MACRO)
- {
- defn = cpp_macro_definition (pfile, hn);
- s.definition_length = ustrlen (defn);
- }
- else
- {
- defn = NODE_NAME (hn);
- s.definition_length = s.name_length;
- }
+ s.name_length = NODE_LEN (hn);
+ s.flags = hn->flags & NODE_POISONED;
- if (fwrite (&s, sizeof (s), 1, f) != 1
- || fwrite (defn, 1, s.definition_length, f) != s.definition_length)
- {
- cpp_errno (pfile, CPP_DL_ERROR,
- "while writing precompiled header");
- return 0;
- }
- }
- return 1;
+ if (is_void)
+ {
+ defn = NODE_NAME (hn);
+ s.definition_length = s.name_length;
+ }
+ else
+ {
+ defn = cpp_macro_definition (pfile, hn);
+ s.definition_length = ustrlen (defn);
+ }
- case NT_ASSERTION:
- /* Not currently implemented. */
+ if (fwrite (&s, sizeof (s), 1, f) != 1
+ || fwrite (defn, 1, s.definition_length, f) != s.definition_length)
+ {
+ cpp_errno (pfile, CPP_DL_ERROR,
+ "while writing precompiled header");
+ return 0;
+ }
+ }
return 1;
default:
@@ -228,8 +225,11 @@ count_defs (cpp_reader *pfile ATTRIBUTE_UNUSED, cpp_hashnode *hn, void *ss_p)
switch (hn->type)
{
- case NT_MACRO:
- if (hn->flags & NODE_BUILTIN)
+ case NT_BUILTIN_MACRO:
+ return 1;
+
+ case NT_USER_MACRO:
+ if (hn->value.macro->kind == cmk_assert)
return 1;
/* fall through. */
@@ -250,10 +250,6 @@ count_defs (cpp_reader *pfile ATTRIBUTE_UNUSED, cpp_hashnode *hn, void *ss_p)
}
return 1;
- case NT_ASSERTION:
- /* Not currently implemented. */
- return 1;
-
default:
abort ();
}
@@ -267,8 +263,11 @@ write_defs (cpp_reader *pfile ATTRIBUTE_UNUSED, cpp_hashnode *hn, void *ss_p)
switch (hn->type)
{
- case NT_MACRO:
- if (hn->flags & NODE_BUILTIN)
+ case NT_BUILTIN_MACRO:
+ return 1;
+
+ case NT_USER_MACRO:
+ if (hn->value.macro->kind == cmk_assert)
return 1;
/* fall through. */
@@ -289,10 +288,6 @@ write_defs (cpp_reader *pfile ATTRIBUTE_UNUSED, cpp_hashnode *hn, void *ss_p)
}
return 1;
- case NT_ASSERTION:
- /* Not currently implemented. */
- return 1;
-
default:
abort ();
}
@@ -623,7 +618,7 @@ cpp_valid_state (cpp_reader *r, const char *name, int fd)
goto fail;
}
- if (h->type != NT_MACRO)
+ if (h->type == NT_VOID)
{
/* It's ok if __GCC_HAVE_DWARF2_CFI_ASM becomes undefined,
as in, when the PCH file is created with -g and we're
@@ -760,13 +755,7 @@ save_macros (cpp_reader *r, cpp_hashnode *h, void *data_p)
{
struct save_macro_data *data = (struct save_macro_data *)data_p;
- if ((h->flags & NODE_BUILTIN)
- && h->type == NT_MACRO
- && r->cb.user_builtin_macro)
- r->cb.user_builtin_macro (r, h);
-
- if (h->type != NT_VOID
- && (h->flags & NODE_BUILTIN) == 0)
+ if (cpp_user_macro_p (h))
{
if (data->count == data->array_size)
{
@@ -774,28 +763,14 @@ save_macros (cpp_reader *r, cpp_hashnode *h, void *data_p)
data->defns = XRESIZEVEC (uchar *, data->defns, (data->array_size));
}
- switch (h->type)
- {
- case NT_ASSERTION:
- /* Not currently implemented. */
- return 1;
-
- case NT_MACRO:
- {
- const uchar * defn = cpp_macro_definition (r, h);
- size_t defnlen = ustrlen (defn);
+ const uchar * defn = cpp_macro_definition (r, h);
+ size_t defnlen = ustrlen (defn);
- data->defns[data->count] = (uchar *) xmemdup (defn, defnlen,
- defnlen + 2);
- data->defns[data->count][defnlen] = '\n';
- }
- break;
-
- default:
- abort ();
- }
+ data->defns[data->count] = (uchar *) xmemdup (defn, defnlen, defnlen + 2);
+ data->defns[data->count][defnlen] = '\n';
data->count++;
}
+
return 1;
}
diff --git a/libcpp/traditional.c b/libcpp/traditional.c
index b25d522..51c3e35 100644
--- a/libcpp/traditional.c
+++ b/libcpp/traditional.c
@@ -89,7 +89,7 @@ static cpp_hashnode *lex_identifier (cpp_reader *, const uchar *);
static const uchar *copy_comment (cpp_reader *, const uchar *, int);
static void check_output_buffer (cpp_reader *, size_t);
static void push_replacement_text (cpp_reader *, cpp_hashnode *);
-static bool scan_parameters (cpp_reader *, cpp_macro *);
+static bool scan_parameters (cpp_reader *, unsigned *);
static bool recursive_macro (cpp_reader *, cpp_hashnode *);
static void save_replacement_text (cpp_reader *, cpp_macro *, unsigned int);
static void maybe_start_funlike (cpp_reader *, cpp_hashnode *, const uchar *,
@@ -325,7 +325,7 @@ _cpp_read_logical_line_trad (cpp_reader *pfile)
static inline bool
fun_like_macro (cpp_hashnode *node)
{
- if (node->flags & NODE_BUILTIN)
+ if (cpp_builtin_macro_p (node))
return node->value.builtin == BT_HAS_ATTRIBUTE;
else
return node->value.macro->fun_like;
@@ -338,7 +338,7 @@ maybe_start_funlike (cpp_reader *pfile, cpp_hashnode *node, const uchar *start,
struct fun_macro *macro)
{
unsigned int n;
- if (node->flags & NODE_BUILTIN)
+ if (cpp_builtin_macro_p (node))
n = 1;
else
n = node->value.macro->paramc;
@@ -521,7 +521,7 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro,
out = pfile->out.cur;
cur = CUR (context);
- if (node->type == NT_MACRO
+ if (cpp_macro_p (node)
/* Should we expand for ls_answer? */
&& (lex_state == ls_none || lex_state == ls_fun_open)
&& !pfile->state.prevent_expansion)
@@ -545,7 +545,7 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro,
goto new_context;
}
}
- else if (macro && (node->flags & NODE_MACRO_ARG) != 0)
+ else if (macro && node->type == NT_MACRO_ARG)
{
/* Found a parameter in the replacement text of a
#define. Remove its name from the output. */
@@ -610,7 +610,7 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro,
paren_depth--;
if (lex_state == ls_fun_close && paren_depth == 0)
{
- if (fmacro.node->flags & NODE_BUILTIN)
+ if (cpp_builtin_macro_p (fmacro.node))
{
/* Handle builtin function-like macros like
__has_attribute. The already parsed arguments
@@ -839,7 +839,7 @@ push_replacement_text (cpp_reader *pfile, cpp_hashnode *node)
const uchar *text;
uchar *buf;
- if (node->flags & NODE_BUILTIN)
+ if (cpp_builtin_macro_p (node))
{
text = _cpp_builtin_macro_text (pfile, node);
len = ustrlen (text);
@@ -853,7 +853,6 @@ push_replacement_text (cpp_reader *pfile, cpp_hashnode *node)
cpp_macro *macro = node->value.macro;
macro->used = 1;
text = macro->exp.text;
- macro->traditional = 1;
len = macro->count;
}
@@ -919,7 +918,7 @@ _cpp_replacement_text_len (const cpp_macro *macro)
len += b->text_len;
if (b->arg_index == 0)
break;
- len += NODE_LEN (macro->params[b->arg_index - 1]);
+ len += NODE_LEN (macro->parm.params[b->arg_index - 1]);
exp += BLOCK_LEN (b->text_len);
}
}
@@ -948,7 +947,7 @@ _cpp_copy_replacement_text (const cpp_macro *macro, uchar *dest)
dest += b->text_len;
if (b->arg_index == 0)
break;
- param = macro->params[b->arg_index - 1];
+ param = macro->parm.params[b->arg_index - 1];
memcpy (dest, NODE_NAME (param), NODE_LEN (param));
dest += NODE_LEN (param);
exp += BLOCK_LEN (b->text_len);
@@ -1082,11 +1081,12 @@ replace_args_and_push (cpp_reader *pfile, struct fun_macro *fmacro)
duplicate parameter). On success, CUR (pfile->context) is just
past the closing parenthesis. */
static bool
-scan_parameters (cpp_reader *pfile, cpp_macro *macro)
+scan_parameters (cpp_reader *pfile, unsigned *n_ptr)
{
const uchar *cur = CUR (pfile->context) + 1;
bool ok;
+ unsigned nparms = 0;
for (;;)
{
cur = skip_whitespace (pfile, cur, true /* skip_comments */);
@@ -1095,8 +1095,9 @@ scan_parameters (cpp_reader *pfile, cpp_macro *macro)
{
struct cpp_hashnode *id = lex_identifier (pfile, cur);
ok = false;
- if (_cpp_save_parameter (pfile, macro, id, id))
+ if (!_cpp_save_parameter (pfile, nparms, id, id))
break;
+ nparms++;
cur = skip_whitespace (pfile, CUR (pfile->context),
true /* skip_comments */);
if (*cur == ',')
@@ -1108,10 +1109,12 @@ scan_parameters (cpp_reader *pfile, cpp_macro *macro)
break;
}
- ok = (*cur == ')' && macro->paramc == 0);
+ ok = (*cur == ')' && !nparms);
break;
}
+ *n_ptr = nparms;
+
if (!ok)
cpp_error (pfile, CPP_DL_ERROR, "syntax error in macro parameter list");
@@ -1139,7 +1142,6 @@ save_replacement_text (cpp_reader *pfile, cpp_macro *macro,
memcpy (exp, pfile->out.base, len);
exp[len] = '\n';
macro->exp.text = exp;
- macro->traditional = 1;
macro->count = len;
}
else
@@ -1155,7 +1157,6 @@ save_replacement_text (cpp_reader *pfile, cpp_macro *macro,
exp = BUFF_FRONT (pfile->a_buff);
block = (struct block *) (exp + macro->count);
macro->exp.text = exp;
- macro->traditional = 1;
/* Write out the block information. */
block->text_len = len;
@@ -1175,12 +1176,15 @@ save_replacement_text (cpp_reader *pfile, cpp_macro *macro,
/* Analyze and save the replacement text of a macro. Returns true on
success. */
-bool
-_cpp_create_trad_definition (cpp_reader *pfile, cpp_macro *macro)
+cpp_macro *
+_cpp_create_trad_definition (cpp_reader *pfile)
{
const uchar *cur;
uchar *limit;
cpp_context *context = pfile->context;
+ unsigned nparms = 0;
+ int fun_like = 0;
+ cpp_hashnode **params = NULL;
/* The context has not been set up for command line defines, and CUR
has not been updated for the macro name for in-file defines. */
@@ -1192,20 +1196,23 @@ _cpp_create_trad_definition (cpp_reader *pfile, cpp_macro *macro)
/* Is this a function-like macro? */
if (* CUR (context) == '(')
{
- bool ok = scan_parameters (pfile, macro);
+ fun_like = +1;
+ if (scan_parameters (pfile, &nparms))
+ params = (cpp_hashnode **)_cpp_commit_buff
+ (pfile, sizeof (cpp_hashnode *) * nparms);
+ else
+ fun_like = -1;
+ }
- /* Remember the params so we can clear NODE_MACRO_ARG flags. */
- macro->params = (cpp_hashnode **) BUFF_FRONT (pfile->a_buff);
+ cpp_macro *macro = NULL;
- /* Setting macro to NULL indicates an error occurred, and
- prevents unnecessary work in _cpp_scan_out_logical_line. */
- if (!ok)
- macro = NULL;
- else
- {
- BUFF_FRONT (pfile->a_buff) = (uchar *) &macro->params[macro->paramc];
- macro->fun_like = 1;
- }
+ if (fun_like >= 0)
+ {
+ macro = _cpp_new_macro (pfile, cmk_traditional,
+ _cpp_aligned_alloc (pfile, sizeof (cpp_macro)));
+ macro->parm.params = params;
+ macro->paramc = nparms;
+ macro->fun_like = fun_like != 0;
}
/* Skip leading whitespace in the replacement text. */
@@ -1217,18 +1224,20 @@ _cpp_create_trad_definition (cpp_reader *pfile, cpp_macro *macro)
_cpp_scan_out_logical_line (pfile, macro, false);
pfile->state.prevent_expansion--;
- if (!macro)
- return false;
+ _cpp_unsave_parameters (pfile, nparms);
- /* Skip trailing white space. */
- cur = pfile->out.base;
- limit = pfile->out.cur;
- while (limit > cur && is_space (limit[-1]))
- limit--;
- pfile->out.cur = limit;
- save_replacement_text (pfile, macro, 0);
+ if (macro)
+ {
+ /* Skip trailing white space. */
+ cur = pfile->out.base;
+ limit = pfile->out.cur;
+ while (limit > cur && is_space (limit[-1]))
+ limit--;
+ pfile->out.cur = limit;
+ save_replacement_text (pfile, macro, 0);
+ }
- return true;
+ return macro;
}
/* Copy SRC of length LEN to DEST, but convert all contiguous