[Ada] Consistently use explicit Entity_Id type instead of alias
[gcc.git] / libcpp / traditional.c
index 38e301c43ff767fac0773b5c305b21ace9257cf9..225e3c2c2f2127d22030963ac40ab8a9006a4552 100644 (file)
@@ -1,10 +1,10 @@
 /* CPP Library - traditional lexical analysis and macro expansion.
-   Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2002-2020 Free Software Foundation, Inc.
    Contributed by Neil Booth, May 2002
 
 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 2, or (at your option) any
+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,
@@ -13,8 +13,8 @@ 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; if not, write to the Free Software
-Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+along with this program; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -60,7 +60,10 @@ struct fun_macro
   size_t offset;
 
   /* The line the macro name appeared on.  */
-  unsigned int line;
+  location_t line;
+
+  /* Number of parameters.  */
+  unsigned int paramc;
 
   /* Zero-based index of argument being currently lexed.  */
   unsigned int argc;
@@ -74,9 +77,10 @@ enum ls {ls_none = 0,                /* Normal state.  */
         ls_defined_close,      /* Looking for ')' of defined().  */
         ls_hash,               /* After # in preprocessor conditional.  */
         ls_predicate,          /* After the predicate, maybe paren?  */
-        ls_answer};            /* In answer to predicate.  */
+        ls_answer              /* In answer to predicate.  */
+};
 
-/* Lexing TODO: Maybe handle space in escaped newlines.  Stop cpplex.c
+/* Lexing TODO: Maybe handle space in escaped newlines.  Stop lex.c
    from recognizing comments and directives during its lexing pass.  */
 
 static const uchar *skip_whitespace (cpp_reader *, const uchar *, int);
@@ -84,7 +88,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 *,
@@ -107,15 +111,18 @@ check_output_buffer (cpp_reader *pfile, size_t n)
       size_t size = pfile->out.cur - pfile->out.base;
       size_t new_size = (size + n) * 3 / 2;
 
-      pfile->out.base = xrealloc (pfile->out.base, new_size);
+      pfile->out.base = XRESIZEVEC (unsigned char, pfile->out.base, new_size);
       pfile->out.limit = pfile->out.base + new_size;
       pfile->out.cur = pfile->out.base + size;
     }
 }
 
 /* Skip a C-style block comment in a macro as a result of -CC.
-   Buffer->cur points to the initial asterisk of the comment.  */
-static void
+   PFILE->buffer->cur points to the initial asterisk of the comment,
+   change it to point to after the '*' and '/' characters that terminate it.
+   Return true if the macro has not been termined, in that case set
+   PFILE->buffer->cur to the end of the buffer.  */
+static bool
 skip_macro_block_comment (cpp_reader *pfile)
 {
   const uchar *cur = pfile->buffer->cur;
@@ -126,10 +133,15 @@ skip_macro_block_comment (cpp_reader *pfile)
 
   /* People like decorating comments with '*', so check for '/'
      instead for efficiency.  */
-  while(! (*cur++ == '/' && cur[-2] == '*') )
-    ;
+  while (! (*cur++ == '/' && cur[-2] == '*'))
+    if (cur[-1] == '\n')
+      {
+       pfile->buffer->cur = cur - 1;
+       return true;
+      }
 
   pfile->buffer->cur = cur;
+  return false;
 }
 
 /* CUR points to the asterisk introducing a comment in the current
@@ -148,12 +160,12 @@ static const uchar *
 copy_comment (cpp_reader *pfile, const uchar *cur, int in_define)
 {
   bool unterminated, copy = false;
-  source_location src_loc = pfile->line_table->highest_line;
+  location_t src_loc = pfile->line_table->highest_line;
   cpp_buffer *buffer = pfile->buffer;
 
   buffer->cur = cur;
   if (pfile->context->prev)
-    unterminated = false, skip_macro_block_comment (pfile);
+    unterminated = skip_macro_block_comment (pfile);
   else
     unterminated = _cpp_skip_block_comment (pfile);
     
@@ -253,8 +265,8 @@ lex_identifier (cpp_reader *pfile, const uchar *cur)
 
   CUR (pfile->context) = cur;
   len = out - pfile->out.cur;
-  result = (cpp_hashnode *) ht_lookup (pfile->hash_table, pfile->out.cur,
-                                      len, HT_ALLOC);
+  result = CPP_HASHNODE (ht_lookup (pfile->hash_table, pfile->out.cur,
+                                   len, HT_ALLOC));
   pfile->out.cur = out;
   return result;
 }
@@ -300,26 +312,50 @@ _cpp_read_logical_line_trad (cpp_reader *pfile)
   do
     {
       if (pfile->buffer->need_line && !_cpp_get_fresh_line (pfile))
-       return false;
+       {
+         /* Now pop the buffer that _cpp_get_fresh_line did not.  */
+         _cpp_pop_buffer (pfile);
+         return false;
+       }
     }
-  while (!_cpp_scan_out_logical_line (pfile, NULL) || pfile->state.skipping);
+  while (!_cpp_scan_out_logical_line (pfile, NULL, false)
+        || pfile->state.skipping);
 
   return pfile->buffer != NULL;
 }
 
+/* Return true if NODE is a fun_like macro.  */
+static inline bool
+fun_like_macro (cpp_hashnode *node)
+{
+  if (cpp_builtin_macro_p (node))
+    return (node->value.builtin == BT_HAS_ATTRIBUTE
+           || node->value.builtin == BT_HAS_STD_ATTRIBUTE
+           || node->value.builtin == BT_HAS_BUILTIN
+           || node->value.builtin == BT_HAS_INCLUDE
+           || node->value.builtin == BT_HAS_INCLUDE_NEXT);
+  return node->value.macro->fun_like;
+}
+
 /* Set up state for finding the opening '(' of a function-like
    macro.  */
 static void
-maybe_start_funlike (cpp_reader *pfile, cpp_hashnode *node, const uchar *start, struct fun_macro *macro)
+maybe_start_funlike (cpp_reader *pfile, cpp_hashnode *node, const uchar *start,
+                    struct fun_macro *macro)
 {
-  unsigned int n = node->value.macro->paramc + 1;
+  unsigned int n;
+  if (cpp_builtin_macro_p (node))
+    n = 1;
+  else
+    n = node->value.macro->paramc;
 
   if (macro->buff)
     _cpp_release_buff (pfile, macro->buff);
-  macro->buff = _cpp_get_buff (pfile, n * sizeof (size_t));
+  macro->buff = _cpp_get_buff (pfile, (n + 1) * sizeof (size_t));
   macro->args = (size_t *) BUFF_FRONT (macro->buff);
   macro->node = node;
   macro->offset = start - pfile->out.base;
+  macro->paramc = n;
   macro->argc = 0;
 }
 
@@ -328,7 +364,7 @@ static void
 save_argument (struct fun_macro *macro, size_t offset)
 {
   macro->argc++;
-  if (macro->argc <= macro->node->value.macro->paramc)
+  if (macro->argc <= macro->paramc)
     macro->args[macro->argc] = offset;
 }
 
@@ -338,9 +374,13 @@ save_argument (struct fun_macro *macro, size_t offset)
 
    If MACRO is non-NULL, then we are scanning the replacement list of
    MACRO, and we call save_replacement_text() every time we meet an
-   argument.  */
+   argument.
+
+   If BUILTIN_MACRO_ARG is true, this is called to macro expand
+   arguments of builtin function-like macros.  */
 bool
-_cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro)
+_cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro,
+                           bool builtin_macro_arg)
 {
   bool result = true;
   cpp_context *context;
@@ -353,13 +393,22 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro)
   const uchar *start_of_input_line;
 
   fmacro.buff = NULL;
+  fmacro.args = NULL;
+  fmacro.node = NULL;
+  fmacro.offset = 0;
+  fmacro.line = 0;
+  fmacro.paramc = 0;
+  fmacro.argc = 0;
 
   quote = 0;
   header_ok = pfile->state.angled_headers;
   CUR (pfile->context) = pfile->buffer->cur;
   RLIMIT (pfile->context) = pfile->buffer->rlimit;
-  pfile->out.cur = pfile->out.base;
-  pfile->out.first_line = pfile->line_table->highest_line;
+  if (!builtin_macro_arg)
+    {
+      pfile->out.cur = pfile->out.base;
+      pfile->out.first_line = pfile->line_table->highest_line;
+    }
   /* start_of_input_line is needed to make sure that directives really,
      really start at the first character of the line.  */
   start_of_input_line = pfile->buffer->cur;
@@ -372,6 +421,7 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro)
   for (;;)
     {
       if (!context->prev
+         && !builtin_macro_arg
          && cur >= pfile->buffer->notes[pfile->buffer->cur_note].pos)
        {
          pfile->buffer->cur = cur;
@@ -403,6 +453,8 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro)
          /* Omit the newline from the output buffer.  */
          pfile->out.cur = out - 1;
          pfile->buffer->cur = cur;
+         if (builtin_macro_arg)
+           goto done;
          pfile->buffer->need_line = true;
          CPP_INCREMENT_LINE (pfile, 0);
 
@@ -475,15 +527,14 @@ _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)
                {
                  /* Macros invalidate MI optimization.  */
                  pfile->mi_valid = false;
-                 if (! (node->flags & NODE_BUILTIN)
-                     && node->value.macro->fun_like)
+                 if (fun_like_macro (node))
                    {
                      maybe_start_funlike (pfile, node, out_start, &fmacro);
                      lex_state = ls_fun_open;
@@ -500,7 +551,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.  */
@@ -556,6 +607,103 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro)
              paren_depth--;
              if (lex_state == ls_fun_close && paren_depth == 0)
                {
+                 if (cpp_builtin_macro_p (fmacro.node))
+                   {
+                     /* Handle builtin function-like macros like
+                        __has_attribute.  The already parsed arguments
+                        are put into a buffer, which is then preprocessed
+                        and the result is fed to _cpp_push_text_context
+                        with disabled expansion, where the ISO preprocessor
+                        parses it.  While in traditional preprocessing
+                        macro arguments aren't immediately expanded, they in
+                        the end are because the macro with replaced arguments
+                        is preprocessed again.  For the builtin function-like
+                        macros we need the argument immediately though,
+                        if we don't preprocess them, they would behave
+                        very differently from ISO preprocessor handling
+                        of those builtin macros.  So, this handling is
+                        more similar to traditional preprocessing of
+                        #if directives, where we also keep preprocessing
+                        until everything is expanded, and then feed the
+                        result with disabled expansion to ISO preprocessor
+                        for handling the directives.  */
+                     lex_state = ls_none;
+                     save_argument (&fmacro, out - pfile->out.base);
+                     cpp_macro m;
+                     memset (&m, '\0', sizeof (m));
+                     m.paramc = fmacro.paramc;
+                     if (_cpp_arguments_ok (pfile, &m, fmacro.node,
+                                            fmacro.argc))
+                       {
+                         size_t len = fmacro.args[1] - fmacro.args[0];
+                         uchar *buf;
+
+                         /* Remove the macro's invocation from the
+                            output, and push its replacement text.  */
+                         pfile->out.cur = pfile->out.base + fmacro.offset;
+                         CUR (context) = cur;
+                         buf = _cpp_unaligned_alloc (pfile, len + 2);
+                         buf[0] = '(';
+                         memcpy (buf + 1, pfile->out.base + fmacro.args[0],
+                                 len);
+                         buf[len + 1] = '\n';
+
+                         const unsigned char *ctx_rlimit = RLIMIT (context);
+                         const unsigned char *saved_cur = pfile->buffer->cur;
+                         const unsigned char *saved_rlimit
+                           = pfile->buffer->rlimit;
+                         const unsigned char *saved_line_base
+                           = pfile->buffer->line_base;
+                         bool saved_need_line = pfile->buffer->need_line;
+                         cpp_buffer *saved_overlaid_buffer
+                           = pfile->overlaid_buffer;
+                         pfile->buffer->cur = buf;
+                         pfile->buffer->line_base = buf;
+                         pfile->buffer->rlimit = buf + len + 1;
+                         pfile->buffer->need_line = false;
+                         pfile->overlaid_buffer = pfile->buffer;
+                         bool saved_in_directive = pfile->state.in_directive;
+                         pfile->state.in_directive = true;
+                         cpp_context *saved_prev_context = context->prev;
+                         context->prev = NULL;
+
+                         _cpp_scan_out_logical_line (pfile, NULL, true);
+
+                         pfile->state.in_directive = saved_in_directive;
+                         check_output_buffer (pfile, 1);
+                         *pfile->out.cur = '\n';
+                         pfile->buffer->cur = pfile->out.base + fmacro.offset;
+                         pfile->buffer->line_base = pfile->buffer->cur;
+                         pfile->buffer->rlimit = pfile->out.cur;
+                         CUR (context) = pfile->buffer->cur;
+                         RLIMIT (context) = pfile->buffer->rlimit;
+
+                         pfile->state.prevent_expansion++;
+                         const uchar *text
+                           = _cpp_builtin_macro_text (pfile, fmacro.node);
+                         pfile->state.prevent_expansion--;
+
+                         context->prev = saved_prev_context;
+                         pfile->buffer->cur = saved_cur;
+                         pfile->buffer->rlimit = saved_rlimit;
+                         pfile->buffer->line_base = saved_line_base;
+                         pfile->buffer->need_line = saved_need_line;
+                         pfile->overlaid_buffer = saved_overlaid_buffer;
+                         pfile->out.cur = pfile->out.base + fmacro.offset;
+                         CUR (context) = cur;
+                         RLIMIT (context) = ctx_rlimit;
+                         len = ustrlen (text);
+                         buf = _cpp_unaligned_alloc (pfile, len + 1);
+                         memcpy (buf, text, len);
+                         buf[len] = '\n';
+                         text = buf;
+                         _cpp_push_text_context (pfile, fmacro.node,
+                                                 text, len);
+                         goto new_context;
+                       }
+                     break;
+                   }
+
                  cpp_macro *m = fmacro.node->value.macro;
 
                  m->used = 1;
@@ -572,8 +720,7 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro)
                    {
                      /* Remove the macro's invocation from the
                         output, and push its replacement text.  */
-                     pfile->out.cur = (pfile->out.base
-                                            + fmacro.offset);
+                     pfile->out.cur = pfile->out.base + fmacro.offset;
                      CUR (context) = cur;
                      replace_args_and_push (pfile, &fmacro);
                      goto new_context;
@@ -687,13 +834,13 @@ 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);
       buf = _cpp_unaligned_alloc (pfile, len + 1);
       memcpy (buf, text, len);
-      buf[len]='\n';
+      buf[len] = '\n';
       text = buf;
     }
   else
@@ -701,7 +848,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;
     }
 
@@ -724,7 +870,7 @@ recursive_macro (cpp_reader *pfile, cpp_hashnode *node)
      detect true recursion; instead we assume any expansion more than
      20 deep since the first invocation of this macro must be
      recursing.  */
-  if (recursing && node->value.macro->fun_like)
+  if (recursing && fun_like_macro (node))
     {
       size_t depth = 0;
       cpp_context *context = pfile->context;
@@ -732,7 +878,7 @@ recursive_macro (cpp_reader *pfile, cpp_hashnode *node)
       do
        {
          depth++;
-         if (context->macro == node && depth > 20)
+         if (context->c.macro == node && depth > 20)
            break;
          context = context->prev;
        }
@@ -767,7 +913,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);
        }
     }
@@ -796,7 +942,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);
@@ -827,8 +973,11 @@ replace_args_and_push (cpp_reader *pfile, struct fun_macro *fmacro)
       uchar *p;
       _cpp_buff *buff;
       size_t len = 0;
+      int cxtquote = 0;
 
-      /* Calculate the length of the argument-replaced text.  */
+      /* Get an estimate of the length of the argument-replaced text.
+        This is a worst case estimate, assuming that every replacement
+        text character needs quoting.  */
       for (exp = macro->exp.text;;)
        {
          struct block *b = (struct block *) exp;
@@ -836,8 +985,8 @@ replace_args_and_push (cpp_reader *pfile, struct fun_macro *fmacro)
          len += b->text_len;
          if (b->arg_index == 0)
            break;
-         len += (fmacro->args[b->arg_index]
-                 - fmacro->args[b->arg_index - 1] - 1);
+         len += 2 * (fmacro->args[b->arg_index]
+                     - fmacro->args[b->arg_index - 1] - 1);
          exp += BLOCK_LEN (b->text_len);
        }
 
@@ -845,21 +994,69 @@ replace_args_and_push (cpp_reader *pfile, struct fun_macro *fmacro)
       buff = _cpp_get_buff (pfile, len + 1);
 
       /* Copy the expansion and replace arguments.  */
+      /* Accumulate actual length, including quoting as necessary */
       p = BUFF_FRONT (buff);
+      len = 0;
       for (exp = macro->exp.text;;)
        {
          struct block *b = (struct block *) exp;
          size_t arglen;
+         int argquote;
+         uchar *base;
+         uchar *in;
 
-         memcpy (p, b->text, b->text_len);
-         p += b->text_len;
+         len += b->text_len;
+         /* Copy the non-argument text literally, keeping
+            track of whether matching quotes have been seen. */
+         for (arglen = b->text_len, in = b->text; arglen > 0; arglen--)
+           {
+             if (*in == '"')
+               cxtquote = ! cxtquote;
+             *p++ = *in++;
+           }
+         /* Done if no more arguments */
          if (b->arg_index == 0)
            break;
          arglen = (fmacro->args[b->arg_index]
                    - fmacro->args[b->arg_index - 1] - 1);
-         memcpy (p, pfile->out.base + fmacro->args[b->arg_index - 1],
-                 arglen);
-         p += arglen;
+         base = pfile->out.base + fmacro->args[b->arg_index - 1];
+         in = base;
+#if 0
+         /* Skip leading whitespace in the text for the argument to
+            be substituted. To be compatible with gcc 2.95, we would
+            also need to trim trailing whitespace. Gcc 2.95 trims
+            leading and trailing whitespace, which may be a bug.  The
+            current gcc testsuite explicitly checks that this leading
+            and trailing whitespace in actual arguments is
+            preserved. */
+         while (arglen > 0 && is_space (*in))
+           {
+             in++;
+             arglen--;
+           }
+#endif
+         for (argquote = 0; arglen > 0; arglen--)
+           {
+             if (cxtquote && *in == '"')
+               {
+                 if (in > base && *(in-1) != '\\')
+                   argquote = ! argquote;
+                 /* Always add backslash before double quote if argument
+                    is expanded in a quoted context */
+                 *p++ = '\\';
+                 len++;
+               }
+             else if (cxtquote && argquote && *in == '\\')
+               {
+                 /* Always add backslash before a backslash in an argument
+                    that is expanded in a quoted context and also in the
+                    range of a quoted context in the argument itself. */
+                 *p++ = '\\';
+                 len++;
+               }
+             *p++ = *in++;
+             len++;
+           }
          exp += BLOCK_LEN (b->text_len);
        }
 
@@ -879,20 +1076,23 @@ 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 */);
 
       if (is_idstart (*cur))
        {
+         struct cpp_hashnode *id = lex_identifier (pfile, cur);
          ok = false;
-         if (_cpp_save_parameter (pfile, macro, lex_identifier (pfile, cur)))
+         if (!_cpp_save_parameter (pfile, nparms, id, id))
            break;
+         nparms++;
          cur = skip_whitespace (pfile, CUR (pfile->context),
                                 true /* skip_comments */);
          if (*cur == ',')
@@ -904,10 +1104,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");
 
@@ -935,7 +1137,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
@@ -951,7 +1152,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;
@@ -971,12 +1171,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.  */
@@ -988,20 +1191,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.  */
@@ -1010,21 +1216,23 @@ _cpp_create_trad_definition (cpp_reader *pfile, cpp_macro *macro)
                       CPP_OPTION (pfile, discard_comments_in_macro_exp));
 
   pfile->state.prevent_expansion++;
-  _cpp_scan_out_logical_line (pfile, 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
@@ -1069,7 +1277,7 @@ bool
 _cpp_expansions_different_trad (const cpp_macro *macro1,
                                const cpp_macro *macro2)
 {
-  uchar *p1 = xmalloc (macro1->count + macro2->count);
+  uchar *p1 = XNEWVEC (uchar, macro1->count + macro2->count);
   uchar *p2 = p1 + macro1->count;
   uchar quote1 = 0, quote2 = 0;
   bool mismatch;