]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - libcpp/directives.c
* config/microblaze/microblaze.c (microblaze_expand_block_move): Treat
[thirdparty/gcc.git] / libcpp / directives.c
index 7cac653dbbc105949e187484afef653e26bbb411..1ada834da17482ebd75fd9ed57312b0e41cd24a7 100644 (file)
@@ -1,5 +1,5 @@
 /* CPP Library. (Directive handling.)
-   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+   Copyright (C) 1986-2019 Free Software Foundation, Inc.
    Contributed by Per Bothner, 1994-95.
    Based on CCCP program by Paul Rubin, June 1986
    Adapted to ANSI C, Richard Stallman, Jan 1987
@@ -30,7 +30,7 @@ along with this program; see the file COPYING3.  If not see
 struct if_stack
 {
   struct if_stack *next;
-  source_location line;                /* Line where condition started.  */
+  location_t line;             /* Line where condition started.  */
   const cpp_hashnode *mi_cmacro;/* macro name for #ifndef around entire file */
   bool skip_elses;             /* Can future #else / #elif be skipped?  */
   bool was_skipping;           /* If were skipping on entry.  */
@@ -98,11 +98,12 @@ static void directive_diagnostics (cpp_reader *, const directive *, int);
 static void run_directive (cpp_reader *, int, const char *, size_t);
 static char *glue_header_name (cpp_reader *);
 static const char *parse_include (cpp_reader *, int *, const cpp_token ***,
-                                 source_location *);
+                                 location_t *);
 static void push_conditional (cpp_reader *, int, int, const cpp_hashnode *);
 static unsigned int read_flag (cpp_reader *, unsigned int);
 static bool strtolinenum (const uchar *, size_t, linenum_type *, bool *);
-static void do_diagnostic (cpp_reader *, int, int, int);
+static void do_diagnostic (cpp_reader *, enum cpp_diagnostic_level code,
+                          enum cpp_warning_reason reason, int);
 static cpp_hashnode *lex_macro_node (cpp_reader *, bool);
 static int undefine_macros (cpp_reader *, cpp_hashnode *, void *);
 static void do_include_common (cpp_reader *, enum include_type);
@@ -123,44 +124,39 @@ static void do_linemarker (cpp_reader *);
 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 *);
+                                location_t);
+static bool parse_answer (cpp_reader *, int, location_t, 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 *);
 static void cpp_pop_definition (cpp_reader *, struct def_pragma_macro *);
 
-/* This is the table of directive handlers.  It is ordered by
-   frequency of occurrence; the numbers at the end are directive
-   counts from all the source code I have lying around (egcs and libc
-   CVS as of 1999-05-18, plus grub-0.5.91, linux-2.2.9, and
-   pcmcia-cs-3.0.9).  This is no longer important as directive lookup
-   is now O(1).  All extensions other than #warning, #include_next,
-   and #import are deprecated.  The name is where the extension
-   appears to have come from.  */
+/* This is the table of directive handlers.  All extensions other than
+   #warning, #include_next, and #import are deprecated.  The name is
+   where the extension appears to have come from.  */
 
 #define DIRECTIVE_TABLE                                                        \
-D(define,      T_DEFINE = 0,   KANDR,     IN_I)           /* 270554 */ \
-D(include,     T_INCLUDE,      KANDR,     INCL | EXPAND)  /*  52262 */ \
-D(endif,       T_ENDIF,        KANDR,     COND)           /*  45855 */ \
-D(ifdef,       T_IFDEF,        KANDR,     COND | IF_COND) /*  22000 */ \
-D(if,          T_IF,           KANDR, COND | IF_COND | EXPAND) /*  18162 */ \
-D(else,                T_ELSE,         KANDR,     COND)           /*   9863 */ \
-D(ifndef,      T_IFNDEF,       KANDR,     COND | IF_COND) /*   9675 */ \
-D(undef,       T_UNDEF,        KANDR,     IN_I)           /*   4837 */ \
-D(line,                T_LINE,         KANDR,     EXPAND)         /*   2465 */ \
-D(elif,                T_ELIF,         STDC89,    COND | EXPAND)  /*    610 */ \
-D(error,       T_ERROR,        STDC89,    0)              /*    475 */ \
-D(pragma,      T_PRAGMA,       STDC89,    IN_I)           /*    195 */ \
-D(warning,     T_WARNING,      EXTENSION, 0)              /*     22 */ \
-D(include_next,        T_INCLUDE_NEXT, EXTENSION, INCL | EXPAND)  /*     19 */ \
-D(ident,       T_IDENT,        EXTENSION, IN_I)           /*     11 */ \
-D(import,      T_IMPORT,       EXTENSION, INCL | EXPAND)  /* 0 ObjC */ \
-D(assert,      T_ASSERT,       EXTENSION, DEPRECATED)     /* 0 SVR4 */ \
-D(unassert,    T_UNASSERT,     EXTENSION, DEPRECATED)     /* 0 SVR4 */ \
-D(sccs,                T_SCCS,         EXTENSION, IN_I)           /* 0 SVR4? */
+  D(define,    T_DEFINE = 0,   KANDR,     IN_I)                        \
+  D(include,   T_INCLUDE,      KANDR,     INCL | EXPAND)               \
+  D(endif,     T_ENDIF,        KANDR,     COND)                        \
+  D(ifdef,     T_IFDEF,        KANDR,     COND | IF_COND)              \
+  D(if,                T_IF,           KANDR,     COND | IF_COND | EXPAND)     \
+  D(else,      T_ELSE,         KANDR,     COND)                        \
+  D(ifndef,    T_IFNDEF,       KANDR,     COND | IF_COND)              \
+  D(undef,     T_UNDEF,        KANDR,     IN_I)                        \
+  D(line,      T_LINE,         KANDR,     EXPAND)                      \
+  D(elif,      T_ELIF,         STDC89,    COND | EXPAND)               \
+  D(error,     T_ERROR,        STDC89,    0)                           \
+  D(pragma,    T_PRAGMA,       STDC89,    IN_I)                        \
+  D(warning,   T_WARNING,      EXTENSION, 0)                           \
+  D(include_next, T_INCLUDE_NEXT, EXTENSION, INCL | EXPAND)            \
+  D(ident,     T_IDENT,        EXTENSION, IN_I)                        \
+  D(import,    T_IMPORT,       EXTENSION, INCL | EXPAND)  /* ObjC */   \
+  D(assert,    T_ASSERT,       EXTENSION, DEPRECATED)     /* SVR4 */   \
+  D(unassert,  T_UNASSERT,     EXTENSION, DEPRECATED)     /* SVR4 */   \
+  D(sccs,      T_SCCS,         EXTENSION, IN_I)           /*  SVR4? */
 
 /* #sccs is synonymous with #ident.  */
 #define do_sccs do_ident
@@ -208,8 +204,6 @@ static const directive linemarker_dir =
   do_linemarker, UC"#", 1, KANDR, IN_I
 };
 
-#define SEEN_EOL() (pfile->cur_token[-1].type == CPP_EOF)
-
 /* Skip any remaining tokens in a directive.  */
 static void
 skip_rest_of_line (cpp_reader *pfile)
@@ -227,7 +221,7 @@ skip_rest_of_line (cpp_reader *pfile)
 /* Helper function for check_oel.  */
 
 static void
-check_eol_1 (cpp_reader *pfile, bool expand, int reason)
+check_eol_1 (cpp_reader *pfile, bool expand, enum cpp_warning_reason reason)
 {
   if (! SEEN_EOL () && (expand
                        ? cpp_get_token (pfile)
@@ -527,10 +521,10 @@ _cpp_handle_directive (cpp_reader *pfile, int indented)
              source_range misspelled_token_range
                = get_range_from_loc (pfile->line_table, dname->src_loc);
              richloc.add_fixit_replace (misspelled_token_range, hint);
-             cpp_error_at_richloc (pfile, CPP_DL_ERROR, &richloc,
-                                   "invalid preprocessing directive #%s;"
-                                   " did you mean #%s?",
-                                   unrecognized, hint);
+             cpp_error_at (pfile, CPP_DL_ERROR, &richloc,
+                           "invalid preprocessing directive #%s;"
+                           " did you mean #%s?",
+                           unrecognized, hint);
            }
          else
            cpp_error (pfile, CPP_DL_ERROR,
@@ -665,12 +659,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 +689,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;
 }
 
@@ -759,7 +754,7 @@ glue_header_name (cpp_reader *pfile)
 
 static const char *
 parse_include (cpp_reader *pfile, int *pangle_brackets,
-              const cpp_token ***buf, source_location *location)
+              const cpp_token ***buf, location_t *location)
 {
   char *fname;
   const cpp_token *header;
@@ -817,7 +812,7 @@ do_include_common (cpp_reader *pfile, enum include_type type)
   const char *fname;
   int angle_brackets;
   const cpp_token **buf = NULL;
-  source_location location;
+  location_t location;
 
   /* Re-enable saving of comments if requested, so that the include
      callback can dump comments which follow #include.  */
@@ -825,22 +820,15 @@ do_include_common (cpp_reader *pfile, enum include_type type)
 
   fname = parse_include (pfile, &angle_brackets, &buf, &location);
   if (!fname)
-    {
-      if (buf)
-       XDELETEVEC (buf);
-      return;
-    }
+    goto done;
 
   if (!*fname)
-  {
-    cpp_error_with_line (pfile, CPP_DL_ERROR, location, 0,
-                        "empty filename in #%s",
-                        pfile->directive->name);
-    XDELETEVEC (fname);
-    if (buf)
-      XDELETEVEC (buf);
-    return;
-  }
+    {
+      cpp_error_with_line (pfile, CPP_DL_ERROR, location, 0,
+                          "empty filename in #%s",
+                          pfile->directive->name);
+      goto done;
+    }
 
   /* Prevent #include recursion.  */
   if (pfile->line_table->depth >= CPP_STACK_MAX)
@@ -858,6 +846,7 @@ do_include_common (cpp_reader *pfile, enum include_type type)
       _cpp_stack_include (pfile, fname, angle_brackets, type, location);
     }
 
+ done:
   XDELETEVEC (fname);
   if (buf)
     XDELETEVEC (buf);
@@ -1088,10 +1077,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,
@@ -1102,7 +1091,7 @@ do_linemarker (cpp_reader *pfile)
     }
   /* Compensate for the increment in linemap_add that occurs in
      _cpp_do_file_change.  We're currently at the start of the line
-     *following* the #line directive.  A separate source_location for this
+     *following* the #line directive.  A separate location_t for this
      location makes no sense (until we do the LC_LEAVE), and
      complicates LAST_SOURCE_LINE_LOCATION.  */
   pfile->line_table->highest_location--;
@@ -1139,11 +1128,12 @@ _cpp_do_file_change (cpp_reader *pfile, enum lc_reason reason,
 /* Report a warning or error detected by the program we are
    processing.  Use the directive's tokens in the error message.  */
 static void
-do_diagnostic (cpp_reader *pfile, int code, int reason, int print_dir)
+do_diagnostic (cpp_reader *pfile, enum cpp_diagnostic_level code,
+              enum cpp_warning_reason reason, int print_dir)
 {
   const unsigned char *dir_name;
   unsigned char *line;
-  source_location src_loc = pfile->cur_token[-1].src_loc;
+  location_t src_loc = pfile->cur_token[-1].src_loc;
 
   if (print_dir)
     dir_name = pfile->directive->name;
@@ -1165,7 +1155,7 @@ do_diagnostic (cpp_reader *pfile, int code, int reason, int print_dir)
 static void
 do_error (cpp_reader *pfile)
 {
-  do_diagnostic (pfile, CPP_DL_ERROR, 0, 1);
+  do_diagnostic (pfile, CPP_DL_ERROR, CPP_W_NONE, 1);
 }
 
 static void
@@ -1440,7 +1430,7 @@ do_pragma (cpp_reader *pfile)
 {
   const struct pragma_entry *p = NULL;
   const cpp_token *token, *pragma_token;
-  source_location pragma_token_virt_loc = 0;
+  location_t pragma_token_virt_loc = 0;
   cpp_token ns_token;
   unsigned int count = 1;
 
@@ -1546,7 +1536,7 @@ do_pragma_push_macro (cpp_reader *pfile)
   txt = get__Pragma_string (pfile);
   if (!txt)
     {
-      source_location src_loc = pfile->cur_token[-1].src_loc;
+      location_t src_loc = pfile->cur_token[-1].src_loc;
       cpp_error_with_line (pfile, CPP_DL_ERROR, src_loc, 0,
                 "invalid #pragma push_macro directive");
       check_eol (pfile, false);
@@ -1601,7 +1591,7 @@ do_pragma_pop_macro (cpp_reader *pfile)
   txt = get__Pragma_string (pfile);
   if (!txt)
     {
-      source_location src_loc = pfile->cur_token[-1].src_loc;
+      location_t src_loc = pfile->cur_token[-1].src_loc;
       cpp_error_with_line (pfile, CPP_DL_ERROR, src_loc, 0,
                 "invalid #pragma pop_macro directive");
       check_eol (pfile, false);
@@ -1666,7 +1656,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);
@@ -1703,7 +1693,7 @@ do_pragma_dependency (cpp_reader *pfile)
 {
   const char *fname;
   int angle_brackets, ordering;
-  source_location location;
+  location_t location;
 
   fname = parse_include (pfile, &angle_brackets, NULL, &location);
   if (!fname)
@@ -1719,7 +1709,7 @@ do_pragma_dependency (cpp_reader *pfile)
       if (cpp_get_token (pfile)->type != CPP_EOF)
        {
          _cpp_backup_tokens (pfile, 1);
-         do_diagnostic (pfile, CPP_DL_WARNING, 0, 0);
+         do_diagnostic (pfile, CPP_DL_WARNING, CPP_W_NONE, 0);
        }
     }
 
@@ -1809,7 +1799,7 @@ get__Pragma_string (cpp_reader *pfile)
    \" and \\ sequences, and process the result as a #pragma directive.  */
 static void
 destringize_and_run (cpp_reader *pfile, const cpp_string *in,
-                    source_location expansion_loc)
+                    location_t expansion_loc)
 {
   const unsigned char *src, *limit;
   char *dest, *result;
@@ -1929,7 +1919,7 @@ destringize_and_run (cpp_reader *pfile, const cpp_string *in,
 
 /* Handle the _Pragma operator.  Return 0 on error, 1 if ok.  */
 int
-_cpp_do__Pragma (cpp_reader *pfile, source_location expansion_loc)
+_cpp_do__Pragma (cpp_reader *pfile, location_t expansion_loc)
 {
   const cpp_token *string = get__Pragma_string (pfile);
   pfile->directive_result.type = CPP_PADDING;
@@ -1960,26 +1950,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 +1979,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 +2139,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, location_t 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 +2155,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 +2182,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 +2239,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 +2276,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 +2299,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 +2330,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;
-
-         /* Remove the answer from the list.  */
-         temp = *p;
-         if (temp)
-           *p = temp->next;
+         cpp_macro **p = find_answer (node, answer);
 
-         /* 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 +2441,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 +2463,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)
       {
@@ -2674,6 +2605,8 @@ _cpp_pop_buffer (cpp_reader *pfile)
 
       _cpp_do_file_change (pfile, LC_LEAVE, 0, 0, 0);
     }
+  else if (to_free)
+    free ((void *)to_free);
 }
 
 /* Enter all recognized directives in the hash table.  */