]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Fix the handling or arguments and macro pseudo-variables inside nested assembler...
authorNick Clifton <nickc@redhat.com>
Thu, 19 Dec 2024 09:59:11 +0000 (09:59 +0000)
committerNick Clifton <nickc@redhat.com>
Thu, 19 Dec 2024 09:59:11 +0000 (09:59 +0000)
PR 32391

gas/config/tc-iq2000.c
gas/doc/as.texi
gas/input-scrub.c
gas/macro.c
gas/macro.h
gas/read.c
gas/testsuite/gas/macros/macros.exp
gas/testsuite/gas/macros/nesting.d [new file with mode: 0644]
gas/testsuite/gas/macros/nesting.s [new file with mode: 0644]

index 2198ffda2b971963beb41baf5cb30cdd7fd694fb..1cbc578281f5a936c5c5876c7298665e6b848fae 100644 (file)
@@ -105,8 +105,6 @@ struct iq2000_hi_fixup
 /* The list of unmatched HI relocs.  */
 static struct iq2000_hi_fixup * iq2000_hi_fixup_list;
 
-/* Macro hash table, which we will add to.  */
-extern struct htab *macro_hash;
 \f
 const char md_shortopts[] = "";
 const struct option md_longopts[] =
@@ -279,9 +277,7 @@ iq2000_add_macro (const char *  name,
        }
     }
 
-  str_hash_insert (macro_hash, macro->name, macro, 1);
-
-  macro_defined = 1;
+  (void) add_macro (macro, true);
 }
 
 static void
index 6be54b575992af607f2846480b661d7e4a537b10..1683594a0bb1a79c3cd38ab9b5882bd319146212 100644 (file)
@@ -6215,7 +6215,12 @@ With that definition, @samp{SUM 0,5} is equivalent to this assembly input:
 @item .macro @var{macname}
 @itemx .macro @var{macname} @var{macargs} @dots{}
 @cindex @code{macro} directive
-Begin the definition of a macro called @var{macname}.  If your macro
+Begin the definition of a macro called @var{macname}.  Macro names are case
+insensitive.  Macro definitions can be nested, although their behaviour is
+sometimes counter intuitive.  Nested macros only have scope within their
+defining macro.
+
+If your macro
 definition requires arguments, specify their names after the macro name,
 separated by commas or spaces.  You can qualify the macro argument to
 indicate whether all invocations must specify a non-blank value (through
@@ -6380,6 +6385,29 @@ adjacent string literals - even if separated only by a blank - will not be
 concatenated when determining macro arguments, even if they're only separated
 by white space.  This is unlike certain other pseudo ops, e.g. @code{.ascii}.
 
+Nested macros can access the arguments of their parents.  But also if their
+argument names clash with those of their parents, their versions are used.  So
+for example:
+
+@smallexample
+.macro OUTER arg1, arg2, arg3:vararg
+     .macro INNER arg4 arg2
+        .dc.a \arg2
+       .dc.a \arg3
+     .endm
+     INNER \arg1 bert
+       .dc.a \arg2
+.endm
+
+OUTER fred, jim, harry\arg4
+@end smallexample
+
+This will generate references to symbols called @samp{jim} - from the
+definition of the OUTER macro, @samp{bert} - from the definition in INNER
+where arg2 has been overridden and @samp{harryfred} - from the definition in
+INNER where the value of arg3 from OUTER is used, but with the value of arg4
+substituted into the symbol.
+
 @item .endm
 @cindex @code{endm} directive
 Mark the end of a macro definition.
@@ -6395,6 +6423,33 @@ Exit early from the current macro definition.
 executed in this pseudo-variable; you can copy that number to your
 output with @samp{\@@}, but @emph{only within a macro definition}.
 
+Note - the @samp{\@@} counter is incremented at the end of the expansion of a
+macro, but before the contents of any nested macros are evaluated.  This can
+lead to counter-intuitive behaviour when nested macros are used.  For example:
+
+@smallexample
+  .macro o
+    .macro i
+    _i\@@_:
+    .endm
+    i
+    _o\@@_:
+  .endm
+  o
+@end smallexample
+
+Produces two symbols @samp{_o0_} and @samp{_i1_}.  This happens because the
+@samp{o} macro executes entirely first, putting the definition and invocation
+of the @samp{i} macro into the input buffer.  It also puts the definition of
+the @samp{_o\@@_} symbol into the input buffer, evaluating the @samp{\@@}
+counter in the process and so generating a symbol called @samp{_o0_}.
+
+That finishes the invocation of @samp{o} so the @samp{\@@} counter is
+incremented.  Then the input buffer is re-evaluated and the definition and
+invocation of macro @samp{i} is found.  This results in @samp{_i\@@_} being put
+into the input buffer and this time @samp{\@@} evaluates to 1, so the symbol
+created is @samp{_i1_}.
+
 @cindex number of times a macro has been executed
 @cindex macro, execution count
 @item \+
@@ -6681,6 +6736,9 @@ those explicitly specified with @code{.eject}.
 Undefine the macro @var{name}, so that later uses of the string will not be
 expanded.  @xref{Macro}.
 
+Note - nested macros are automatically purged at the end of the macro that
+defines them.
+
 @ifset ELF
 @node PushSection
 @section @code{.pushsection @var{name} [, @var{subsection}] [, "@var{flags}"[, @@@var{type}[,@var{arguments}]]]}
index 878edc8fd3672ab62ece60d58e869913de7ce71f..25fac879a56c82b485d56ac380b26ac491d4c9c2 100644 (file)
@@ -23,6 +23,7 @@
 #include "input-file.h"
 #include "sb.h"
 #include "listing.h"
+#include "macro.h"
 
 /*
  * O/S independent module to supply buffers of sanitised source code
@@ -290,12 +291,13 @@ input_scrub_include_sb (sb *from, char *position, enum expansion expansion)
       ++macro_nest;
     }
 
-#ifdef md_macro_start
   if (expansion == expanding_macro)
     {
+#ifdef md_macro_start
       md_macro_start ();
-    }
 #endif
+      increment_macro_nesting_depth ();
+    }
 
   next_saved_file = input_scrub_push (position);
 
@@ -350,6 +352,7 @@ input_scrub_next_buffer (char **bufp)
                 data.  */
              md_macro_end ();
 #endif
+             decrement_macro_nesting_depth ();
            }
          if (from_sb_expansion != expanding_app)
            --macro_nest;
index 8b376f7f490ba6923f99c8b77875b0946b937989..a0f2a5c764c52ff35f3835216561b210f070dee3 100644 (file)
 
 /* The macro hash table.  */
 
-htab_t macro_hash;
+/* Macro nesting depth.  Similar to macro_nest defined in sb.c, but this
+   counter is specific to macros, whereas macro_nest also counts repeated
+   string blocks.  */
+static unsigned int macro_nesting_depth;
 
-/* Whether any macros have been defined.  */
+/* Maximum nesting depth.  Ideally the same as the value of max_macro_nest
+   as defined in as.c (ie 100).  But there is one test in the assembler
+   testsuite (bfin/allinsn16.s) that nests macros to a depth of 8192.  So
+   we have a ridiculously large number here.  */
+#define MAX_MACRO_DEPTH 8193
 
-int macro_defined;
+static htab_t macro_hash[MAX_MACRO_DEPTH];
+
+/* Whether any macros have been defined.
+   FIXME:  This could be a counter that is incremented
+   with .macro and decremented with .purgem.  */
+
+static bool macros_defined = false;
 
 /* Whether we should strip '@' characters.  */
 
@@ -60,6 +73,18 @@ static unsigned int macro_number;
 
 static void free_macro (macro_entry *);
 
+bool
+add_macro (macro_entry * macro, bool replace)
+{
+  if (str_hash_insert (macro_hash [macro_nesting_depth],
+                      macro->name, macro, replace) == NULL)
+    {
+      macros_defined = true;
+      return true;
+    }
+  return false;
+}
+
 static void
 macro_del_f (void *ent)
 {
@@ -72,15 +97,23 @@ macro_del_f (void *ent)
 void
 macro_init (void)
 {
-  macro_hash = htab_create_alloc (16, hash_string_tuple, eq_string_tuple,
-                                 macro_del_f, notes_calloc, NULL);
-  macro_defined = 0;
+  int i;
+
+  for (i = 0; i < MAX_MACRO_DEPTH; i++)
+    macro_hash[i] = htab_create_alloc (16, hash_string_tuple, eq_string_tuple,
+                                      macro_del_f, notes_calloc, NULL);
+  macros_defined = false;
 }
 
 void
 macro_end (void)
 {
-  htab_delete (macro_hash);
+  int i;
+
+  for (i = MAX_MACRO_DEPTH; i--;)
+    htab_delete (macro_hash[i]);
+
+  macros_defined = false;
 }
 
 /* Read input lines till we get to a TO string.
@@ -655,6 +688,13 @@ free_macro (macro_entry *macro)
   free (macro);
 }
 
+static macro_entry * last_recorded_macro = NULL;
+void
+macro_record_invocation (macro_entry * macro)
+{
+  last_recorded_macro = macro;
+}
+
 /* Define a new macro.  */
 
 macro_entry *
@@ -718,15 +758,19 @@ define_macro (sb *in, sb *label, size_t (*get_line) (sb *))
   /* And stick it in the macro hash table.  */
   for (idx = 0; idx < name.len; idx++)
     name.ptr[idx] = TOLOWER (name.ptr[idx]);
+
+  if (macro_nesting_depth > 0)
+    macro->parent = last_recorded_macro;
+  else
+    macro->parent = NULL;
+
   if (!error)
     {
-      if (str_hash_insert (macro_hash, macro->name, macro, 0) != NULL)
+      if (! add_macro (macro, false))
        error = _("Macro `%s' was already defined");
     }
 
-  if (!error)
-    macro_defined = 1;
-  else
+  if (error != NULL)
     {
       as_bad_where (macro->file, macro->line, error, macro->name);
       free_macro (macro);
@@ -750,11 +794,25 @@ get_apost_token (size_t idx, sb *in, sb *name, int kind)
   return idx;
 }
 
-/* Substitute the actual value for a formal parameter.  */
+static const char *
+macro_expand_body (sb *, sb *, formal_entry *, struct htab *,
+                  const macro_entry *, unsigned int);
+
+/* Find the actual value for a formal parameter starting at START inside IN.
+    Appends the value of parameter onto OUT.
+   The hash table of formal parameters is provided by FORMAL_HASH.
+   The character that indicated the presense of a formal parameter is passed
+    in KIND.
+   If COPYIFNOTTHERE is true and the parameter is not found in the hash table
+    then it is appended as plain text onto OUT.
+   The macro containing the formal parameters is passed in MACRO.
+    This can be empty.
+   Returns the offset inside IN after advanceing past the parameter.
+   Also stores the parameter's name into T.  */
 
 static size_t
 sub_actual (size_t start, sb *in, sb *t, struct htab *formal_hash,
-           int kind, sb *out, int copyifnotthere)
+           int kind, sb *out, int copyifnotthere, const macro_entry * macro)
 {
   size_t src;
   formal_entry *ptr;
@@ -768,16 +826,12 @@ sub_actual (size_t start, sb *in, sb *t, struct htab *formal_hash,
     ptr = NULL;
   else
     ptr = str_hash_find (formal_hash, sb_terminate (t));
+  
   if (ptr)
     {
-      if (ptr->actual.len)
-       {
-         sb_add_sb (out, &ptr->actual);
-       }
-      else
-       {
-         sb_add_sb (out, &ptr->def);
-       }
+      sb * add = ptr->actual.len ? &ptr->actual : &ptr->def;
+
+      sb_add_sb (out, add);
     }
   else if (kind == '&')
     {
@@ -791,6 +845,55 @@ sub_actual (size_t start, sb *in, sb *t, struct htab *formal_hash,
     {
       sb_add_sb (out, t);
     }
+  else if (!macro_strip_at
+          && macro_nesting_depth > 0
+          && macro != NULL
+          && macro->parent != NULL)
+    {
+      const macro_entry * orig_macro = macro;
+      bool success = false;
+
+      /* We have failed to find T, but we are inside nested macros.  So check
+        the parent macros so see if they have a FORMAL that matches T.  */
+      while (macro->parent != NULL)
+       {
+         macro = macro->parent;
+
+         ptr = str_hash_find (macro->formal_hash, t->ptr);
+         if (ptr == NULL)
+           continue;
+
+         sb * add = ptr->actual.len ? &ptr->actual : &ptr->def;
+
+         /* The parent's FORMALs might contain parameters that need further
+            substitution.  See gas/testsuite/gas/arm/macro-vld1.s for an
+            example of this.  */
+         if (strchr (add->ptr, '\\'))
+           {
+             sb newadd;
+
+             sb_new (&newadd);
+             /* FIXME: Should we do something if the call to
+                macro_expand_body returns an error message ?  */
+             (void) macro_expand_body (add, &newadd, NULL, NULL,
+                                       orig_macro, orig_macro->count);
+             sb_add_sb (out, &newadd);
+           }
+         else
+           {
+             sb_add_sb (out, add);
+           }
+         success = true;
+         break;
+       }
+      if (! success)
+       {
+         /* We reached the outermost macro and failed to find T, so
+            just copy the entire parameter as is.  */
+         sb_add_char (out, '\\');
+         sb_add_sb (out, t);
+       }
+    }
   else
     {
       sb_add_char (out, '\\');
@@ -799,7 +902,12 @@ sub_actual (size_t start, sb *in, sb *t, struct htab *formal_hash,
   return src;
 }
 
-/* Expand the body of a macro.  */
+/* Expands the body of a macro / block of text IN, copying it into OUT.
+   Parameters for substitution are found in FORMALS and FORMAL_HASH or
+   MACRO.
+   The number of times that this macro / block of text have already been
+   copied into the output is held in INSTANCE.
+   Returns NULL upon success or an error message otherwise.  */
 
 static const char *
 macro_expand_body (sb *in, sb *out, formal_entry *formals,
@@ -811,18 +919,38 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
   int inquote = 0, macro_line = 0;
   formal_entry *loclist = NULL;
   const char *err = NULL;
+  int nesting = 0;
 
+  if (formals == NULL && macro != NULL)
+    formals = macro->formals;
+
+  if (formal_hash == NULL && macro != NULL)
+    formal_hash = macro->formal_hash;
+  
   sb_new (&t);
 
   while (src < in->len && !err)
     {
+      if (in->ptr[src] == '.')
+       {
+         /* Check to see if we have encountered ".macro" or ".endm" */
+         if (in->len > src + 5
+             && strncmp (in->ptr + src, ".macro", 6) == 0)
+           ++ nesting;
+
+         else if (in->len > src + 4
+                  && strncmp (in->ptr + src, ".endm", 5) == 0)
+           -- nesting;
+       }
+
       if (in->ptr[src] == '&')
        {
          sb_reset (&t);
          if (flag_mri)
            {
              if (src + 1 < in->len && in->ptr[src + 1] == '&')
-               src = sub_actual (src + 2, in, &t, formal_hash, '\'', out, 1);
+               src = sub_actual (src + 2, in, &t, formal_hash,
+                                 '\'', out, 1, macro);
              else
                sb_add_char (out, in->ptr[src++]);
            }
@@ -830,7 +958,8 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
            {
              /* Permit macro parameter substitution delineated with
                 an '&' prefix and optional '&' suffix.  */
-             src = sub_actual (src + 1, in, &t, formal_hash, '&', out, 0);
+             src = sub_actual (src + 1, in, &t, formal_hash,
+                               '&', out, 0, macro);
            }
        }
       else if (in->ptr[src] == '\\')
@@ -851,7 +980,12 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
              else
                as_bad_where (macro->file, macro->line + macro_line, _("missing `)'"));
            }
-         else if (src < in->len && in->ptr[src] == '@')
+         else if (src < in->len
+                  && in->ptr[src] == '@'
+                  /* PR 32391: Do not perform the substition inside nested
+                     macros.  Instead wait until they are re-evaluated and
+                     perform the substition then.  */
+                  && ! nesting)
            {
              /* Sub in the total macro invocation number.  */
 
@@ -860,7 +994,12 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
              sprintf (buffer, "%u", macro_number);
              sb_add_string (out, buffer);
            }
-         else if (src < in->len && in->ptr[src] == '+')
+         else if (src < in->len
+                  && in->ptr[src] == '+'
+                  /* PR 32391: Do not perform the substition inside nested
+                     macros.  Instead wait until they are re-evaluated and
+                     perform the substition then.  */
+                  && ! nesting)
            {
              /* Sub in the current macro invocation number.  */
 
@@ -904,7 +1043,18 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
          else
            {
              sb_reset (&t);
-             src = sub_actual (src, in, &t, formal_hash, '\'', out, 0);
+
+             if (nesting)
+               {
+                 src = get_apost_token (src, in, &t, '\'');
+                 sb_add_char (out, '\\');
+                 sb_add_sb (out, &t);
+               }
+             else
+               {
+                 src = sub_actual (src, in, &t, formal_hash,
+                                   '\'', out, 0, macro);
+               }
            }
        }
       else if ((flag_macro_alternate || flag_mri)
@@ -923,7 +1073,7 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
              sb_reset (&t);
              src = sub_actual (src, in, &t, formal_hash,
                                (macro_strip_at && inquote) ? '@' : '\'',
-                               out, 1);
+                               out, 1, macro);
            }
          else
            {
@@ -1035,6 +1185,7 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
 
   if (!err && (out->len == 0 || out->ptr[out->len - 1] != '\n'))
     sb_add_char (out, '\n');
+
   return err;
 }
 
@@ -1219,8 +1370,7 @@ macro_expand (size_t idx, sb *in, macro_entry *m, sb *out)
            }
        }
 
-      err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, m,
-                              m->count);
+      err = macro_expand_body (&m->sub, out, NULL, NULL, m, m->count);
     }
 
   /* Discard any unnamed formal arguments.  */
@@ -1253,9 +1403,9 @@ macro_expand (size_t idx, sb *in, macro_entry *m, sb *out)
 }
 
 /* Check for a macro.  If one is found, put the expansion into
-   *EXPAND.  Return 1 if a macro is found, 0 otherwise.  */
+   *EXPAND.  Return TRUE if a macro is found, FALSE otherwise.  */
 
-int
+bool
 check_macro (const char *line, sb *expand,
             const char **error, macro_entry **info)
 {
@@ -1264,9 +1414,12 @@ check_macro (const char *line, sb *expand,
   macro_entry *macro;
   sb line_sb;
 
+  if (! macros_defined)
+    return false;
+
   if (! is_name_beginner (*line)
       && (! flag_mri || *line != '.'))
-    return 0;
+    return false;
 
   s = line + 1;
   while (is_part_of_name (*s))
@@ -1278,11 +1431,17 @@ check_macro (const char *line, sb *expand,
   for (cls = copy; *cls != '\0'; cls ++)
     *cls = TOLOWER (*cls);
 
-  macro = str_hash_find (macro_hash, copy);
+  int i;
+  for (i = macro_nesting_depth; i >= 0; i--)
+    {
+      macro = str_hash_find (macro_hash[i], copy);
+      if (macro != NULL)
+       break;
+    }
   free (copy);
 
   if (macro == NULL)
-    return 0;
+    return false;
 
   /* Wrap the line up in an sb.  */
   sb_new (&line_sb);
@@ -1298,7 +1457,7 @@ check_macro (const char *line, sb *expand,
   if (info)
     *info = macro;
 
-  return 1;
+  return true;
 }
 
 /* Delete a macro.  */
@@ -1316,11 +1475,20 @@ delete_macro (const char *name)
     copy[i] = TOLOWER (name[i]);
   copy[i] = '\0';
 
-  macro = str_hash_find (macro_hash, copy);
-  if (macro != NULL)
-    str_hash_delete (macro_hash, copy);
-  else
+  int j;
+  for (j = macro_nesting_depth; j >= 0; j--)
+    {
+      macro = str_hash_find (macro_hash [j], copy);
+      if (macro != NULL)
+       {
+         str_hash_delete (macro_hash[j], copy);
+         break;
+       }
+    }
+
+  if (macro == NULL)
     as_warn (_("Attempt to purge non-existing macro `%s'"), copy);
+
   free (copy);
 }
 
@@ -1422,3 +1590,25 @@ expand_irp (int irpc, size_t idx, sb *in, sb *out, size_t (*get_line) (sb *))
 
   return err;
 }
+
+void
+increment_macro_nesting_depth (void)
+{
+ if (macro_nesting_depth >= (MAX_MACRO_DEPTH - 1))
+    as_fatal (_("macros nested too deeply"));
+  else
+    ++macro_nesting_depth;
+}
+
+void
+decrement_macro_nesting_depth (void)
+{
+  if (macro_nesting_depth == 0)
+    as_fatal (_("too much macro un-nesting"));
+  else
+    {
+      /* FIXME: Potential memory leak here.  */
+      htab_empty (macro_hash [macro_nesting_depth]);
+      --macro_nesting_depth;
+    }
+}
index e87f64e70ca225fe23716e5c99a95319377f6e8a..97f2a5a4066b6beb3df256eaae9eb146072747e8 100644 (file)
@@ -64,31 +64,28 @@ typedef struct macro_struct
   int             formal_count;                /* Number of formal args.  */
   formal_entry *  formals;             /* List of formal_structs.  */
   htab_t          formal_hash;         /* Hash table of formals.  */
+  struct macro_struct * parent;         /* Parent of nested macros.  */
   const char *    name;                        /* Macro name.  */
   const char *    file;                        /* File the macro was defined in.  */
   unsigned int    line;                        /* Line number of definition.  */
   unsigned int    count;                /* Invocation count.  */
 } macro_entry;
 
-/* Whether any macros have been defined.  */
-
-extern int macro_defined;
-
-/* The macro nesting level.  */
+/* The macro/text block nesting level.  */
 
 extern int macro_nest;
 
-/* The macro hash table.  */
-
-extern htab_t macro_hash;
-
 extern int buffer_and_nest (const char *, const char *, sb *,
                            size_t (*) (sb *));
 extern void macro_init (void);
 extern void macro_end (void);
 extern macro_entry *define_macro (sb *, sb *, size_t (*) (sb *));
-extern int check_macro (const char *, sb *, const char **, macro_entry **);
+extern bool check_macro (const char *, sb *, const char **, macro_entry **);
 extern void delete_macro (const char *);
 extern const char *expand_irp (int, size_t, sb *, sb *, size_t (*) (sb *));
+extern void increment_macro_nesting_depth (void);
+extern void decrement_macro_nesting_depth (void);
+extern void macro_record_invocation (macro_entry *);
+extern bool add_macro (macro_entry *, bool);
 
 #endif
index 589c7b080c228fe27bd09bbffb2ced0280c3061e..e5185f4ba26d641df2e2f71b7df20d25915156c7 100644 (file)
@@ -655,7 +655,8 @@ poend (void)
     }
 
 /* Helper function of read_a_source_file, which tries to expand a macro.  */
-static int
+
+static bool
 try_macro (char term, const char *line)
 {
   sb out;
@@ -672,12 +673,14 @@ try_macro (char term, const char *line)
       sb_kill (&out);
       buffer_limit =
        input_scrub_next_buffer (&input_line_pointer);
+
+      macro_record_invocation (macro);
 #ifdef md_macro_info
       md_macro_info (macro);
 #endif
-      return 1;
+      return true;
     }
-  return 0;
+  return false;
 }
 
 #ifdef HANDLE_BUNDLE
@@ -1269,7 +1272,7 @@ read_a_source_file (const char *name)
                          s_ignore (0);
                          nul_char = next_char = *--input_line_pointer;
                          *input_line_pointer = '\0';
-                         if (! macro_defined || ! try_macro (next_char, s))
+                         if (! try_macro (next_char, s))
                            {
                              *end = '\0';
                              as_bad (_("unknown pseudo-op: `%s'"), s);
@@ -1306,7 +1309,7 @@ read_a_source_file (const char *name)
 
                      generate_lineno_debug ();
 
-                     if (macro_defined && try_macro (next_char, s))
+                     if (try_macro (next_char, s))
                        continue;
 
                      if (mri_pending_align)
@@ -2816,7 +2819,7 @@ s_macro (int ignore ATTRIBUTE_UNUSED)
          as_warn_where (macro->file, macro->line,
                         _("attempt to redefine pseudo-op `%s' ignored"),
                         macro->name);
-         str_hash_delete (macro_hash, macro->name);
+         delete_macro (macro->name);
        }
     }
 
index 3ac199feaa500344a21a56168845b16e657063ea..94ac37cdb8b8f5bdf29fc3ed7c41f530b9615554 100644 (file)
@@ -112,3 +112,4 @@ run_list_test count
 run_list_test irp-count
 run_list_test irpc-quote
 run_list_test rept-count
+run_dump_test nesting
diff --git a/gas/testsuite/gas/macros/nesting.d b/gas/testsuite/gas/macros/nesting.d
new file mode 100644 (file)
index 0000000..2f44aed
--- /dev/null
@@ -0,0 +1,28 @@
+#nm: -j 
+#name: Nested macros (PR 32391)
+# Sone targets do not support macros used like this.
+#skip: tic*-*-* mmix-*
+
+#...
+_m7_
+_m8_
+after_at_0
+after_at_3
+after_plus_0
+after_plus_1
+before_at_0
+before_at_3
+before_plus_0
+before_plus_1
+bert
+harryfred
+i3_bar
+inside_at_1
+inside_at_2
+inside_at_4
+inside_at_5
+inside_plus_0
+inside_plus_1
+jim
+o3_foo
+other_inner_6
diff --git a/gas/testsuite/gas/macros/nesting.s b/gas/testsuite/gas/macros/nesting.s
new file mode 100644 (file)
index 0000000..438d5af
--- /dev/null
@@ -0,0 +1,104 @@
+
+       .text
+/* PR 32391: Automatic counters inside macros should increment when nested
+       macros finish execution.  */
+.macro o1
+.global before_at_\@
+before_at_\@:
+.global before_plus_\+
+before_plus_\+:
+
+       .macro i1
+.global inside_at_\@
+inside_at_\@:
+.global inside_plus_\+
+inside_plus_\+:
+       .endm
+
+       i1
+       i1
+
+.global after_at_\@
+after_at_\@:
+.global after_plus_\+
+after_plus_\+:
+
+.endm
+
+/* Invoking o1 should produce these symbols in this order:
+
+       before_at_0
+       before_plus_0
+       inside_at_1
+       inside_plus_0
+       inside_at_2
+       inside_plus_1
+       after_at_0
+       after_plus_0  */
+o1
+       
+/* A second invocation of o1 should not produce any errors about
+       symbols or macros being redefined.  */
+o1
+       
+/* This definition should not collide with the definition inside o1.  */
+.macro i1
+.global other_inner_\@
+other_inner_\@:
+.endm 
+
+/* And invoking it should invoke the second defintion of i1, not the first.  */        
+i1
+               
+.macro o2
+.global _m\@_
+_m\@_:
+.macro i2
+.global _m\@_
+_m\@_:
+.endm
+i2
+.endm
+
+/* This should not generate conflicting symbols because the assembler
+   inserts the contents of o2 into the input buffer as pure text (ie
+   without evaluating i2).  The first use of \@ is evaluated at this
+   time, creating _m4_.  But the second use is not evaluated because
+   it is inside a .macro definition.
+       
+   This finishes the evaluation of o2, so the \@ counter is incremented.
+       
+   Next the input buffer is re-evaluated and the i2 macro definition
+   and invocation are encounterd.  The text from i2 are inserted into
+   the input buffer and at this point the second use of \@ is evaluated
+   resulting in the creation of a symbol called _m5_.  */
+o2
+
+/* Macro arguments should be independent of nesting.  */
+.macro O3 arg
+.global o3_\arg
+o3_\arg:
+
+       .macro I3 arg
+.global i3_\arg
+i3_\arg:
+       .endm
+
+       i3 bar          /* Macro names are case insensitive.  */
+.endm
+
+o3 foo /* Should produce two labels: o3_foo and i3_bar.  */
+
+/* Nested macros can access the arguments of their parents.
+   In addition their arguments can be substituted into the arguments
+   that are substited from their parents:  */
+.macro OUTER arg1, arg2, arg3:vararg
+     .macro INNER arg4 arg2
+        .dc.a \arg2
+       .dc.a \arg3
+     .endm
+     INNER \arg1 bert
+       .dc.a \arg2
+.endm
+
+OUTER fred, jim, harry\arg4 /* This produces references to "jim", "bert" and "harryfred".  */