Re: popdef(undefined), __m4_version__

Eric Blake <[email protected]>
Newsgroups gmane.comp.gnu.m4.general,gmane.comp.sysutils.autoconf.general
Message-ID <[email protected]>
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

According to Eric Blake on 8/3/2008 5:39 PM:
> |
> | That's not to say the default mode need necessarily be compatible, but
> | at least detecting that we are running inside autoconf and setting the
> | right options to work without patching would be the kindest thing to
> | do.
> 
> You are doing a good job of convincing me that the inability of m4 1.6 to
> work with unpatched autoconf 2.62 is bad.  Here's my current idea:
> 
> In m4, add a new debugmode() letter (perhaps 'd' for dereference), then
> condition all warnings related to dereferencing undefined macros on that
> option being set.  Right now, if you don't use m4 -d, you default to a
> debugmode of ""; we could change this to default to a debugmode of "d", so
> that a vanilla user of m4 gets the warning.  Likewise, 'm4 -d' was
> equivalent to 'm4 -daeq'; it would now be equivalent to 'm4 -dadeq'.

Here's what I'm planning on committing to m4; it adds debugmode(d) as a
new flag that controls whether dereferencing undefined macros warns, then
enables the flag by default unless an explicit -d specifies other flags or
if -E is in effect.  Both conditions for disabling the debugmode(d) flag
were necessary, so that branch-1.6 of m4.git can once again handle
autoconf 2.62 out of the box.

By committing this series, I now need a followup patch to autoconf;
m4sugar now needs to explicitly request m4_debugmode([+d]) when it detects
__m4_version__, before it can rely on native defn/popdef/undefine for speed.

I am also working on an autom4te patch that detects status 63 when loading
a frozen file, and falls back to retrying the load without the use of a
frozen file; which, if I then make m4 1.6 use frozen file format 2, will
allow the user to install autoconf with m4 1.6, then downgrade to m4 1.4.x
without being penalized by quadratic performance.

- --
Don't work too hard, make some time for fun as well!

Eric Blake             [email protected]
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkiyrokACgkQ84KuGfSFAYA4VwCeM+wrCY82PDzbfZS4ZKYWJyuL
95MAoKG7EGXRMx7G04FpCHPCUplTnETH
=I2oY
-----END PGP SIGNATURE-----

_______________________________________________
m4-discuss mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/m4-discuss
m4.patch373 (text/plain, 37.2 KB)
From 8912baaae894abfe31716a003126b680351be33c Mon Sep 17 00:00:00 2001
From: Eric Blake <[email protected]>
Date: Mon, 18 Aug 2008 06:29:31 -0600
Subject: [PATCH] Allow + and - in --debug, and add --debugmode.

* src/builtin.c (m4_debugmode): Move +- handling...
* src/debug.c (debug_decode): ...here.
* src/m4.c (main): Adjust caller.
(long_options): Add alternate spelling for --debug.
(usage): Mention it.
* doc/m4.texinfo (Debugging options): Document additional
semantics.
* NEWS: Likewise.

Signed-off-by: Eric Blake <[email protected]>
(cherry picked from commit c2e093a955214b8aaf4da8dd44bd595b06fea235)
---
 ChangeLog      |   12 ++++++++++++
 NEWS           |    7 +++++++
 doc/m4.texinfo |   39 ++++++++++++++++++++++++++++++---------
 src/builtin.c  |   37 ++-----------------------------------
 src/debug.c    |   35 ++++++++++++++++++++++++++++++-----
 src/m4.c       |   12 +++++-------
 6 files changed, 86 insertions(+), 56 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 0e06082..bb719cf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2008-08-22  Eric Blake  <[email protected]>
+
+	Allow + and - in --debug, and add --debugmode.
+	* src/builtin.c (m4_debugmode): Move +- handling...
+	* src/debug.c (debug_decode): ...here.
+	* src/m4.c (main): Adjust caller.
+	(long_options): Add alternate spelling for --debug.
+	(usage): Mention it.
+	* doc/m4.texinfo (Debugging options): Document additional
+	semantics.
+	* NEWS: Likewise.
+
 2008-08-21  Eric Blake  <[email protected]>
 
 	Fix crash with traced defn(undef), regression from 2007-08-09.
diff --git a/NEWS b/NEWS
index 109c80a..0099383 100644
--- a/NEWS
+++ b/NEWS
@@ -42,6 +42,13 @@ Foundation, Inc.
    then apply this patch:
      http://git.sv.gnu.org/gitweb/?p=autoconf.git;a=commitdiff;h=56d42fa71
 
+** The `-d'/`--debug' command-line option now understands `-' and `+'
+   modifiers, the way the builtin `debugmode' has always done; this allows
+   `-d-V' to disable prior debug settings from the command line, similar to
+   using the builtin `debugmode' without arguments.  The option
+   `--debugmode' is added as an alias for `-d'.  When given the empty
+   string, the mode is treated as `+aeq' instead of `aeq'.
+
 ** New `-g'/`--gnu' command-line option overrides `-G'/`--traditional'.
    For now, the environment variable POSIXLY_CORRECT has no effect on M4
    behavior; but a future release of M4 will behave as though --traditional
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index 7540b2e..f47fd3c 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -838,12 +838,34 @@ Debugging options
 scripts.
 
 @table @code
-@item -d@r{[}@var{FLAGS}@r{]}
-@itemx --debug@r{[}=@var{FLAGS}@r{]}
+@item -d@r{[}@r{[}-@r{|}+@r{]}@var{FLAGS}@r{]}
+@itemx --debug@r{[}=@r{[}-@r{|}+@r{]}@var{FLAGS}@r{]}
+@itemx --debugmode@r{[}=@r{[}-@r{|}+@r{]}@var{FLAGS}@r{]}
 Set the debug-level according to the flags @var{FLAGS}.  The debug-level
 controls the format and amount of information presented by the debugging
 functions.  @xref{Debug Levels}, for more details on the format and
-meaning of @var{FLAGS}.  If omitted, @var{FLAGS} defaults to @samp{aeq}.
+meaning of @var{FLAGS}.  If omitted, @var{FLAGS} defaults to
+@samp{+aeq}.  If the option occurs multiple times, @var{FLAGS} starting
+with @samp{-} or @samp{+} are cumulative, while @var{FLAGS} starting
+with a letter override all earlier settings.  Therefore, to disable all
+previously set flags, specify an explicit @var{FLAGS} of @samp{-V}.  The
+spelling @option{--debug} is recognized as an unambiguous option for
+compatibility with earlier versions of @acronym{GNU} M4, but for
+consistency with the builtin name, you can also use the spelling
+@option{--debugmode}.
+
+The cumulative effect of the various options in this example is
+equivalent to a single invocation of @code{debugmode(`alqx')}:
+
+@comment options: -d-V -d+lx --debug --debugmode=-e
+@example
+$ @kbd{m4 -d+lx --debug --debugmode=-e}
+traceon(`len')
+@result{}
+len(`123')
+@error{}m4trace:2: -1- id 2: len(`123')
+@result{}3
+@end example
 
 @item --debugfile=@var{FILE}
 @itemx -o @var{FILE}
@@ -2483,6 +2505,7 @@ Pushdef
 @option{-Q} (@option{--quiet}, @pxref{Operation modes, , Invoking m4}).
 
 @example
+$ @kbd{m4}
 define(`a', `1')
 @result{}
 popdef
@@ -3646,10 +3669,10 @@ Dumpdef
 If you want to see what a name expands into, you can use the builtin
 @code{dumpdef}:
 
-@deffn Builtin dumpdef (@ovar{names@dots{}})
+@deffn Builtin dumpdef (@ovar{name@dots{}})
 Accepts any number of arguments.  If called without any arguments,
 it displays the definitions of all known names, otherwise it displays
-the definitions of the @var{names} given.  The output is printed to the
+the definitions of each @var{name} given.  The output is printed to the
 current debug file (usually standard error), and is sorted by name.  If
 an unknown name is encountered, a warning is printed.
 
@@ -3741,8 +3764,7 @@ Trace
 @option{-t}) can be used to invoke @code{traceon(@var{name})} before
 parsing input.
 
-@comment The explicit -dp neutralizes the testsuite default of -d.
-@comment options: -dp -L3 -tifelse
+@comment options: -d-V -L3 -tifelse
 @comment status: 1
 @example
 $ @kbd{m4 -L 3 -t ifelse}
@@ -3992,8 +4014,7 @@ Debug Levels
 The expansion of @code{debugmode} is void.
 @end deffn
 
-@comment The explicit -dp neutralizes the testsuite default of -d.
-@comment options: -dp
+@comment options: -d-V
 @example
 $ @kbd{m4}
 define(`foo', `FOO')
diff --git a/src/builtin.c b/src/builtin.c
index b8449a0..34387b9 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -1759,46 +1759,13 @@ m4_debugmode (struct obstack *obs, int argc, macro_arguments *argv)
 {
   const call_info *me = arg_info (argv);
   const char *str = ARG (1);
-  int new_debug_level;
-  int change_flag;
 
   bad_argc (me, argc, 0, 1);
 
   if (argc == 1)
     debug_level = 0;
-  else
-    {
-      if (*str == '+' || *str == '-')
-	{
-	  change_flag = *str;
-	  new_debug_level = debug_decode (str + 1);
-	}
-      else
-	{
-	  change_flag = 0;
-	  new_debug_level = debug_decode (str);
-	}
-
-      if (new_debug_level < 0)
-	m4_warn (0, me, _("bad debug flags: `%s'"), str);
-      else
-	{
-	  switch (change_flag)
-	    {
-	    case 0:
-	      debug_level = new_debug_level;
-	      break;
-
-	    case '+':
-	      debug_level |= new_debug_level;
-	      break;
-
-	    case '-':
-	      debug_level &= ~new_debug_level;
-	      break;
-	    }
-	}
-    }
+  else if (debug_decode (str) < 0)
+    m4_warn (0, me, _("bad debug flags: `%s'"), str);
 }
 
 /*-------------------------------------------------------------------------.
diff --git a/src/debug.c b/src/debug.c
index c3f85bd..579960b 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -43,20 +43,24 @@ debug_init (void)
   obstack_init (&trace);
 }
 
-/*-----------------------------------------------------------------.
-| Function to decode the debugging flags OPTS.  Used by main while |
-| processing option -d, and by the builtin debugmode ().	   |
-`-----------------------------------------------------------------*/
+/*------------------------------------------------------------------.
+| Function to decode the debugging flags OPTS.  Used by main while  |
+| processing option -d, and by the builtin debugmode ().  Return -1 |
+| if the parse failed, otherwise change the debug level.	    |
+`------------------------------------------------------------------*/
 
 int
 debug_decode (const char *opts)
 {
   int level;
+  char mode = '\0';
 
   if (opts == NULL || *opts == '\0')
-    level = DEBUG_TRACE_DEFAULT;
+    level = DEBUG_TRACE_DEFAULT | debug_level;
   else
     {
+      if (*opts == '-' || *opts == '+')
+	mode = *opts++;
       for (level = 0; *opts; opts++)
 	{
 	  switch (*opts)
@@ -110,6 +114,27 @@ debug_decode (const char *opts)
 	    }
 	}
     }
+  switch (mode)
+    {
+    case '\0':
+      /* Replace old level.  */
+      break;
+
+    case '-':
+      /* Subtract flags.  */
+      level = debug_level & ~level;
+      break;
+
+    case '+':
+      /* Add flags.  */
+      level |= debug_level;
+      break;
+
+    default:
+      assert (!"debug_decode");
+      abort ();
+    }
+  debug_level = level;
   return level;
 }
 
diff --git a/src/m4.c b/src/m4.c
index 73ccce1..c368021 100644
--- a/src/m4.c
+++ b/src/m4.c
@@ -256,7 +256,8 @@ Frozen state files:\n\
       puts ("");
       fputs (_("\
 Debugging:\n\
-  -d, --debug[=FLAGS]          set debug level (no FLAGS implies `aeq')\n\
+  -d, --debug[=[-|+]FLAGS], --debugmode[=[-|+]FLAGS]\n\
+                               set debug level (no FLAGS implies `+aeq')\n\
       --debugfile=FILE         redirect debug and trace output\n\
   -l, --arglength=NUM          restrict macro tracing size\n\
   -t, --trace=NAME             trace NAME when it is defined\n\
@@ -318,6 +319,7 @@ static const struct option long_options[] =
 {
   {"arglength", required_argument, NULL, 'l'},
   {"debug", optional_argument, NULL, 'd'},
+  {"debugmode", optional_argument, NULL, 'd'},
   {"define", required_argument, NULL, 'D'},
   {"error-output", required_argument, NULL, 'o'}, /* FIXME: deprecate in 2.0 */
   {"fatal-warnings", no_argument, NULL, 'E'},
@@ -521,12 +523,8 @@ main (int argc, char *const *argv, char *const *envp)
 #endif
 
       case 'd':
-	debug_level = debug_decode (optarg);
-	if (debug_level < 0)
-	  {
-	    error (0, 0, "bad debug flags: `%s'", optarg);
-	    debug_level = 0;
-	  }
+	if (debug_decode (optarg) < 0)
+	  error (0, 0, "bad debug flags: `%s'", optarg);
 	break;
 
       case 'e':
-- 
1.6.0


From cb3bbd28fa8a04d3eddc08261169b5c3e98c252f Mon Sep 17 00:00:00 2001
From: Eric Blake <[email protected]>
Date: Mon, 18 Aug 2008 07:17:35 -0600
Subject: [PATCH] Interleave -d handling with files.

* src/m4.c (main): Defer -d handling when appropriate.
* doc/m4.texinfo (Debugging options): Mention it.
(Command line files): Test it.
* NEWS: Mention it.

Signed-off-by: Eric Blake <[email protected]>
---
 ChangeLog      |    6 ++++++
 NEWS           |    4 +++-
 doc/m4.texinfo |   18 +++++++++++++++++-
 src/m4.c       |   13 +++++++++++--
 4 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index bb719cf..07fced3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2008-08-22  Eric Blake  <[email protected]>
 
+	Interleave -d handling with files.
+	* src/m4.c (main): Defer -d handling when appropriate.
+	* doc/m4.texinfo (Debugging options): Mention it.
+	(Command line files): Test it.
+	* NEWS: Mention it.
+
 	Allow + and - in --debug, and add --debugmode.
 	* src/builtin.c (m4_debugmode): Move +- handling...
 	* src/debug.c (debug_decode): ...here.
diff --git a/NEWS b/NEWS
index 0099383..9e69a3b 100644
--- a/NEWS
+++ b/NEWS
@@ -47,7 +47,9 @@ Foundation, Inc.
    `-d-V' to disable prior debug settings from the command line, similar to
    using the builtin `debugmode' without arguments.  The option
    `--debugmode' is added as an alias for `-d'.  When given the empty
-   string, the mode is treated as `+aeq' instead of `aeq'.
+   string, the mode is treated as `+aeq' instead of `aeq'.  Also, the
+   position of `-d' with respect to files on the command line is now
+   significant.
 
 ** New `-g'/`--gnu' command-line option overrides `-G'/`--traditional'.
    For now, the environment variable POSIXLY_CORRECT has no effect on M4
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index f47fd3c..5cfdb1a 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -852,7 +852,7 @@ Debugging options
 spelling @option{--debug} is recognized as an unambiguous option for
 compatibility with earlier versions of @acronym{GNU} M4, but for
 consistency with the builtin name, you can also use the spelling
-@option{--debugmode}.
+@option{--debugmode}.  Order is significant with respect to file names.
 
 The cumulative effect of the various options in this example is
 equivalent to a single invocation of @code{debugmode(`alqx')}:
@@ -926,6 +926,7 @@ Command line files
 The text @samp{bar} can then be redefined over multiple uses of
 @file{foo}:
 
+@comment examples
 @comment options: -Dbar=hello foo -Dbar=world foo
 @example
 $ @kbd{m4 -Dbar=hello foo -Dbar=world foo}
@@ -933,6 +934,21 @@ Command line files
 @result{}world
 @end example
 
+@ignore
+@comment Not worth putting the manual, but worth testing.
+
+@comment examples
+@comment options: -Dbar=hello -d foo -t bar foo -d-V foo
+@example
+$ @kbd{m4 -Dbar=hello -d foo -t bar foo -d-V foo
+@result{}hello
+@error{}m4trace: -1- bar -> `hello'
+@result{}hello
+@error{}m4trace: -1- bar
+@result{}hello
+@end example
+@end ignore
+
 If none of the input files invoked @code{m4exit} (@pxref{M4exit}), the
 exit status of @code{m4} will be 0 for success, 1 for general failure
 (such as problems with reading an input file), and 63 for version
diff --git a/src/m4.c b/src/m4.c
index c368021..22586fc 100644
--- a/src/m4.c
+++ b/src/m4.c
@@ -455,11 +455,14 @@ main (int argc, char *const *argv, char *const *envp)
 	       optchar);
 	break;
 
+      case '\1':
+	seen_file = true;
+	/* fall through */
       case 'D':
       case 'U':
       case 's':
       case 't':
-      case '\1':
+      defer:
 	/* Arguments that cannot be handled until later are accumulated.  */
 
 	defn = (macro_definition *) xmalloc (sizeof (macro_definition));
@@ -523,6 +526,8 @@ main (int argc, char *const *argv, char *const *envp)
 #endif
 
       case 'd':
+	if (seen_file)
+	  goto defer;
 	if (debug_decode (optarg) < 0)
 	  error (0, 0, "bad debug flags: `%s'", optarg);
 	break;
@@ -621,6 +626,11 @@ main (int argc, char *const *argv, char *const *envp)
 	  lookup_symbol (defines->arg, strlen (defines->arg), SYMBOL_DELETE);
 	  break;
 
+	case 'd':
+	  if (debug_decode (defines->arg) < 0)
+	    error (0, 0, "bad debug flags: `%s'", defines->arg);
+	  break;
+
 	case 't':
 	  sym = lookup_symbol (defines->arg, strlen (defines->arg),
 			       SYMBOL_INSERT);
@@ -632,7 +642,6 @@ main (int argc, char *const *argv, char *const *envp)
 	  break;
 
 	case '\1':
-	  seen_file = true;
 	  process_file (defines->arg);
 	  break;
 
-- 
1.6.0


From d918ca5f34a4653ed4120d5732c8b46738f78bb3 Mon Sep 17 00:00:00 2001
From: Eric Blake <[email protected]>
Date: Fri, 22 Aug 2008 17:26:01 -0600
Subject: [PATCH] Allow debugmode control over whether defn(undef) warns.

* src/m4.h (DEBUG_TRACE_DEREF): New define.
(DEBUG_TRACE_VERBOSE, DEBUG_TRACE_DEFAULT): Adjust.
* src/m4.c (debug_level): Start with debugmode = d.
(usage): Mention this.
(main): Let -E impact debug mode.
* src/builtin.c (m4_undefine, m4_popdef, m4_dumpdef, m4_builtin)
(m4_indir, m4_defn): Squelch undefined warning if debug flag is
clear.
* src/debug.c (debug_decode): Parse new mode.
* doc/m4.texinfo (Debugging options): Mention change in the
default behavior.
(Debug Levels): Mention new flag d.
(Operation modes): Mention interaction with -E.
(Undefine, Defn, Pushdef, Indir, Builtin, Dumpdef): Document and
test its effect.
* NEWS: Document this.
Reported by Ralf Wildenhues; without this patch, M4 1.6 would be
incompatible with Autoconf 2.62.

Signed-off-by: Eric Blake <[email protected]>
---
 ChangeLog      |   22 +++++++
 NEWS           |   32 ++++------
 doc/m4.texinfo |  186 ++++++++++++++++++++++++++++++++++++++-----------------
 src/builtin.c  |   29 ++++++---
 src/debug.c    |    4 +
 src/m4.c       |    6 +-
 src/m4.h       |    8 ++-
 7 files changed, 195 insertions(+), 92 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 07fced3..1b9bbaa 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2008-08-23  Eric Blake  <[email protected]>
+
+	Allow debugmode control over whether defn(undef) warns.
+	* src/m4.h (DEBUG_TRACE_DEREF): New define.
+	(DEBUG_TRACE_VERBOSE, DEBUG_TRACE_DEFAULT): Adjust.
+	* src/m4.c (debug_level): Start with debugmode = d.
+	(usage): Mention this.
+	(main): Let -E impact debug mode.
+	* src/builtin.c (m4_undefine, m4_popdef, m4_dumpdef, m4_builtin)
+	(m4_indir, m4_defn): Squelch undefined warning if debug flag is
+	clear.
+	* src/debug.c (debug_decode): Parse new mode.
+	* doc/m4.texinfo (Debugging options): Mention change in the
+	default behavior.
+	(Debug Levels): Mention new flag d.
+	(Operation modes): Mention interaction with -E.
+	(Undefine, Defn, Pushdef, Indir, Builtin, Dumpdef): Document and
+	test its effect.
+	* NEWS: Document this.
+	Reported by Ralf Wildenhues; without this patch, M4 1.6 would be
+	incompatible with Autoconf 2.62.
+
 2008-08-22  Eric Blake  <[email protected]>
 
 	Interleave -d handling with files.
diff --git a/NEWS b/NEWS
index 9e69a3b..5a3ecb3 100644
--- a/NEWS
+++ b/NEWS
@@ -46,10 +46,12 @@ Foundation, Inc.
    modifiers, the way the builtin `debugmode' has always done; this allows
    `-d-V' to disable prior debug settings from the command line, similar to
    using the builtin `debugmode' without arguments.  The option
-   `--debugmode' is added as an alias for `-d'.  When given the empty
-   string, the mode is treated as `+aeq' instead of `aeq'.  Also, the
-   position of `-d' with respect to files on the command line is now
-   significant.
+   `--debugmode' is added as an alias for `-d'.  The new flag `d' is added
+   to control whether dereferncing an undefined macro causes a warning;
+   this flag is enabled by default if neither `-d' nor `-E' are specified.
+   When given the empty string, the mode is treated as `+adeq' instead of
+   `aeq'.  Also, the position of `-d' with respect to files on the command
+   line is now significant.
 
 ** New `-g'/`--gnu' command-line option overrides `-G'/`--traditional'.
    For now, the environment variable POSIXLY_CORRECT has no effect on M4
@@ -69,21 +71,13 @@ Foundation, Inc.
    be used, via `defn', to determine whether the version of m4 processing
    your file is adequate.
 
-** The `defn', `popdef', and `undefine' builtins now warn when operating
-   on an undefined macro name, similar to what was already done in the
-   `indir' and `dumpdef' builtins.  To simulate 1.4.x behavior, use:
-     pushdef(`defn', `ifelse(`$#', `0', ``defn'',
-                             `ifdef(`$1', `builtin(`defn', `$1')')')')
-     pushdef(`popdef', `ifelse(`$#', `0', ``popdef'', `_$0($@)')')
-     define(`_popdef', `ifdef(`$1', `builtin(`popdef', `$1')')ifelse(`$#',
-                `1', `', `$0(shift($@))')')
-     pushdef(`undefine', `ifelse(`$#', `0', ``undefine'', `_$0($@)')')
-     define(`_undefine', `ifdef(`$1', `builtin(`undefine', `$1')')ifelse(`$#',
-                `1', `', `$0(shift($@))')')
-
-   Additionally, if you want to install Autoconf 2.62 or earlier, then
-   apply this patch:
-     http://git.sv.gnu.org/gitweb/?p=autoconf.git;a=commitdiff;h=c4a32a009
+** The `defn', `popdef', and `undefine' builtins gained a new warning when
+   operating on an undefined macro name, to match the warning already
+   present in `builtin', `indir', and `dumpdef'.  For backwards
+   compatibility, the warning can be disabled by using `debugmode(`-d')'
+   (or the command line option `--debug=-d').  The flag is also cleared by
+   the command line option `-E'/`--fatal-warnings', so that scripts written
+   for 1.4.x do not cause the script to fail because of new warnings.
 
 ** Enhance the `indir' builtin to trace indirect macros, where the trace
    is requested via `traceon' or the command-line option `-t'.  Previously,
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index 5cfdb1a..e537c79 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -598,6 +598,56 @@ Operation modes
 1.4.9; for behavior consistent with earlier versions, you should specify
 @option{-E} twice.
 
+For backwards compatibility reasons, using @option{-E} behaves as if an
+implicit @option{--debug=-d} option is also present.  This is so that
+scripts written for older M4 versions will not fail if they used
+constructs that were previously silently allowed, but would now trigger
+a warning.
+
+@example
+$ @kbd{m4}
+defn(`oops')
+@error{}m4:stdin:1: Warning: defn: undefined macro `oops'
+@result{}
+^D
+@end example
+
+@comment ignore
+@example
+$ @kbd{echo $?}
+@result{}0
+@end example
+
+@comment options: -E
+@example
+$ @kbd{m4 -E}
+defn(`oops')
+@result{}
+^D
+@end example
+
+@comment ignore
+@example
+$ @kbd{echo $?}
+@result{}0
+@end example
+
+@comment options: -E -d
+@comment status: 1
+@example
+$ @kbd{m4 -E -d}
+defn(`oops')
+@error{}m4:stdin:1: Warning: defn: undefined macro `oops'
+@result{}
+^D
+@end example
+
+@comment ignore
+@example
+$ @kbd{echo $?}
+@result{}1
+@end example
+
 @item -i
 @itemx --interactive
 @itemx -e
@@ -845,17 +895,20 @@ Debugging options
 controls the format and amount of information presented by the debugging
 functions.  @xref{Debug Levels}, for more details on the format and
 meaning of @var{FLAGS}.  If omitted, @var{FLAGS} defaults to
-@samp{+aeq}.  If the option occurs multiple times, @var{FLAGS} starting
+@samp{+adeq}.  If the option occurs multiple times, @var{FLAGS} starting
 with @samp{-} or @samp{+} are cumulative, while @var{FLAGS} starting
-with a letter override all earlier settings.  Therefore, to disable all
-previously set flags, specify an explicit @var{FLAGS} of @samp{-V}.  The
-spelling @option{--debug} is recognized as an unambiguous option for
+with a letter override all earlier settings.  The debug-level starts
+with @samp{d} enabled and all other flags disabled.  To disable all
+previously set flags, specify an explicit @var{FLAGS} of @samp{-V}.  For
+backward compatibility reasons, the option @option{--fatal-warnings}
+implies @samp{--debug=-d} as part of its effects.  The spelling
+@option{--debug} is recognized as an unambiguous option for
 compatibility with earlier versions of @acronym{GNU} M4, but for
 consistency with the builtin name, you can also use the spelling
 @option{--debugmode}.  Order is significant with respect to file names.
 
 The cumulative effect of the various options in this example is
-equivalent to a single invocation of @code{debugmode(`alqx')}:
+equivalent to a single invocation of @code{debugmode(`adlqx')}:
 
 @comment options: -d-V -d+lx --debug --debugmode=-e
 @example
@@ -2130,7 +2183,8 @@ Undefine
 @deffn Builtin undefine (@var{name}@dots{})
 For each argument, remove the macro @var{name}.  The macro names must
 necessarily be quoted, since they will be expanded otherwise.  If an
-argument is not a defined macro, a warning is issued.
+argument is not a defined macro, then the @samp{d} debug level controls
+whether a warning is issued (@pxref{Debug Levels}).
 
 The expansion of @code{undefine} is void.
 The macro @code{undefine} is recognized only with parameters.
@@ -2165,30 +2219,19 @@ Undefine
 @result{}f(bye)
 @end example
 
-As of M4 1.6, @code{undefine} will warn if @var{name} is not a macro.
-The following example shows how to recover earlier behavior that
-silently ignores undefined names, using concepts that will be explained
-later in the manual.  Or, you could use the command line option
-@option{-Q} (@option{--quiet}, @pxref{Operation modes, , Invoking m4}).
+As of M4 1.6, @code{undefine} can warn if @var{name} is not a macro, by
+using @code{debugmode} (@pxref{Debug Levels}) or the command line option
+@option{-d} (@option{--debugmode}, @pxref{Debugging options, , Invoking
+m4}).
 
 @example
-define(`a', `1')
-@result{}
-undefine
-@result{}undefine
-undefine(`a', `a')
-@error{}m4:stdin:3: Warning: undefine: undefined macro `a'
-@result{}
-define(`a', `1')
-@result{}
-pushdef(`undefine', `ifelse(`$#', `0', ``undefine'', `_$0($@@)')')
+$ @kbd{m4}
+undefine(`a')
+@error{}m4:stdin:1: Warning: undefine: undefined macro `a'
 @result{}
-define(`_undefine', `ifdef(`$1', `builtin(`undefine',
-  `$1')')ifelse(`$#', `1', `', `$0(shift($@@))')')
+debugmode(`-d')
 @result{}
-undefine
-@result{}undefine
-undefine(`a', `a')
+undefine(`a')
 @result{}
 @end example
 
@@ -2205,7 +2248,8 @@ Defn
 @deffn Builtin defn (@var{name}@dots{})
 Expands to the @emph{quoted definition} of each @var{name}.  If an
 argument is not a defined macro, the expansion for that argument is
-empty and triggers a warning.
+empty, and the @samp{d} debug level controls whether a warning is issued
+(@pxref{Debug Levels}).
 
 If @var{name} is a user-defined macro, the quoted definition is simply
 the quoted expansion text.  If, instead, @var{name} is a builtin, the
@@ -2371,9 +2415,11 @@ Defn
 @result{}0
 @end example
 
-A warning is issued if @var{name} is undefined.  Also note that as of M4
-1.6, @code{defn} with multiple arguments can join text with builtin
-tokens.  However, when defining a macro via @code{define} or
+As of M4 1.6, @code{defn} can warn if @var{name} is not a macro, by
+using @code{debugmode} (@pxref{Debug Levels}) or the command line option
+@option{-d} (@option{--debugmode}, @pxref{Debugging options, , Invoking
+m4}).  Also, @code{defn} with multiple arguments can join text with
+builtin tokens.  However, when defining a macro via @code{define} or
 @code{pushdef}, a warning is issued and the builtin token ignored if the
 builtin token does not occur in isolation.  A future version of
 @acronym{GNU} M4 may lift this restriction.
@@ -2383,6 +2429,10 @@ Defn
 defn(`foo')
 @error{}m4:stdin:1: Warning: defn: undefined macro `foo'
 @result{}
+debugmode(`-d')
+@result{}
+defn(`foo')
+@result{}
 define(`a', `A')define(`AA', `b')
 @result{}
 traceon(`defn', `define')
@@ -2392,25 +2442,25 @@ Defn
 @result{}AA
 define(`mydivnum', defn(`divnum', `divnum'))mydivnum
 @error{}m4trace: -2- defn(`divnum', `divnum') -> `<divnum><divnum>'
-@error{}m4:stdin:5: Warning: define: cannot concatenate builtins
+@error{}m4:stdin:7: Warning: define: cannot concatenate builtins
 @error{}m4trace: -1- define(`mydivnum', `<divnum><divnum>') -> `'
 @result{}
 traceoff(`defn', `define')dumpdef(`mydivnum')
 @error{}mydivnum:@tabchar{}`'
 @result{}
 define(`mydivnum', defn(`divnum')defn(`divnum'))mydivnum
-@error{}m4:stdin:7: Warning: define: cannot concatenate builtins
+@error{}m4:stdin:9: Warning: define: cannot concatenate builtins
 @result{}
 define(`mydivnum', defn(`divnum')`a')mydivnum
-@error{}m4:stdin:8: Warning: define: cannot concatenate builtins
+@error{}m4:stdin:10: Warning: define: cannot concatenate builtins
 @result{}A
 define(`mydivnum', `a'defn(`divnum'))mydivnum
-@error{}m4:stdin:9: Warning: define: cannot concatenate builtins
+@error{}m4:stdin:11: Warning: define: cannot concatenate builtins
 @result{}A
 define(`q', ``$@@'')
 @result{}
 define(`foo', q(`a', defn(`divnum')))foo
-@error{}m4:stdin:11: Warning: define: cannot concatenate builtins
+@error{}m4:stdin:13: Warning: define: cannot concatenate builtins
 @result{}a,
 ifdef(`foo', `yes', `no')
 @result{}yes
@@ -2441,7 +2491,8 @@ Pushdef
 If a macro has several definitions (of which only one is accessible),
 the topmost definition can be removed with @code{popdef}.  If there is
 no previous definition, @code{popdef} behaves like @code{undefine}, and
-if there is no definition at all, @code{popdef} issues a warning.
+if there is no definition at all, the @samp{d} debug level controls
+whether a warning is issued (@pxref{Debug Levels}).
 
 The expansion of both @code{pushdef} and @code{popdef} is void.
 The macros @code{pushdef} and @code{popdef} are recognized only with
@@ -2514,11 +2565,10 @@ Pushdef
 It is possible to temporarily redefine a builtin with @code{pushdef}
 and @code{defn}.
 
-As of M4 1.6, @code{popdef} will warn if @var{name} is not a macro.
-The following example shows how to recover earlier behavior that
-silently ignores undefined names, using concepts that will be explained
-later in the manual.  Or, you could use the command line option
-@option{-Q} (@option{--quiet}, @pxref{Operation modes, , Invoking m4}).
+As of M4 1.6, @code{popdef} can warn if @var{name} is not a macro, by
+using @code{debugmode} (@pxref{Debug Levels}) or the command line option
+@option{-d} (@option{--debugmode}, @pxref{Debugging options, , Invoking
+m4}).
 
 @example
 $ @kbd{m4}
@@ -2529,16 +2579,9 @@ Pushdef
 popdef(`a', `a')
 @error{}m4:stdin:3: Warning: popdef: undefined macro `a'
 @result{}
-define(`a', `1')
-@result{}
-pushdef(`popdef', `ifelse(`$#', `0', ``popdef'', `_$0($@@)')')
-@result{}
-define(`_popdef', `ifdef(`$1', `builtin(`popdef',
-  `$1')')ifelse(`$#', `1', `', `$0(shift($@@))')')
+debugmode(`-d')
 @result{}
-popdef
-@result{}popdef
-popdef(`a', `a')
+popdef(`a')
 @result{}
 @end example
 
@@ -2552,9 +2595,10 @@ Indir
 Any macro can be called indirectly with @code{indir}:
 
 @deffn Builtin indir (@var{name}, @ovar{args@dots{}})
-Results in a call to the macro @var{name}, which is passed the
-rest of the arguments @var{args}.  If @var{name} is not defined, an
-error message is printed, and the expansion is void.
+Results in a call to the macro @var{name}, which is passed the rest of
+the arguments @var{args}.  If @var{name} is not defined, the expansion
+is void, and the @samp{d} debug level controls whether a warning is
+issued (@pxref{Debug Levels}).
 
 The macro @code{indir} is recognized only with parameters.
 @end deffn
@@ -2593,6 +2637,10 @@ Indir
 indir(`f', undefine(`f'))
 @error{}m4:stdin:4: Warning: indir: undefined macro `f'
 @result{}
+debugmode(`-d')
+@result{}
+indir(`f')
+@result{}
 @end example
 
 When handed the result of @code{defn} (@pxref{Defn}) as one of its
@@ -2643,7 +2691,8 @@ Builtin
 @deffn Builtin builtin (@var{name}, @ovar{args@dots{}})
 Results in a call to the builtin @var{name}, which is passed the
 rest of the arguments @var{args}.  If @var{name} does not name a
-builtin, an error message is printed, and the expansion is void.
+builtin, the expansion is void, and the @samp{d} debug level controls
+whether a warning is issued (@pxref{Debug Levels}).
 
 The macro @code{builtin} is recognized only with parameters.
 @end deffn
@@ -2697,6 +2746,10 @@ Builtin
 @result{}
 m4_indir(`m4_divnum')
 @result{}0
+m4_debugmode(`-d')
+@result{}
+m4_builtin(`m4_divnum')
+@result{}
 @end example
 
 Note that @code{indir} and @code{builtin} can be used to invoke builtins
@@ -3690,7 +3743,8 @@ Dumpdef
 it displays the definitions of all known names, otherwise it displays
 the definitions of each @var{name} given.  The output is printed to the
 current debug file (usually standard error), and is sorted by name.  If
-an unknown name is encountered, a warning is printed.
+a @var{name} is undefined, the @samp{d} debug level controls whether a
+warning is issued (@pxref{Debug Levels}).
 
 The expansion of @code{dumpdef} is void.
 @end deffn
@@ -3722,6 +3776,10 @@ Dumpdef
 f(popdef(`f')dumpdef(`f'))
 @error{}m4:stdin:3: Warning: dumpdef: undefined macro `f'
 @result{}f1
+debugmode(`-d')
+@result{}
+dumpdef(`f')
+@result{}
 @end example
 
 @xref{Debug Levels}, for information on controlling the details of the
@@ -3966,6 +4024,18 @@ Debug Levels
 only one line is printed, after all arguments are collected and the
 expansion determined.  This is often used with the @samp{x} flag.
 
+@item d
+Output a warning on any attempt to dereference an undefined macro via
+@code{builtin}, @code{defn}, @code{dumpdef}, @code{indir},
+@code{popdef}, or @code{undefine}.  Note that @code{indef},
+@code{traceon}, and @code{traceoff} do not dereference undefined macros.
+Like any other warning, the warnings enabled by this flag go to standard
+error regardless of the current @code{debugfile} setting, and will
+change exit status if the command line option @option{--fatal-warnings}
+was specified.  This flag is useful in diagnosing spelling mistakes in
+macro names.  It is enabled by default when neither @option{--debug} nor
+@option{--fatal-warnings} are specified on the command line.
+
 @item e
 In trace output, show the expansion of each macro call, if it is not
 void.  This applies to all macro calls if the @samp{t} flag is used,
@@ -4012,7 +4082,7 @@ Debug Levels
 @end table
 
 If no flags are specified with the @option{-d} option, the default is
-@samp{aeq}.  The examples throughout this manual assume the default
+@samp{+adeq}.  The examples throughout this manual assume the default
 flags.
 
 @cindex @acronym{GNU} extensions
@@ -4024,8 +4094,8 @@ Debug Levels
 As special cases, if the argument starts with a @samp{+}, the flags are
 added to the current debug flags, and if it starts with a @samp{-}, they
 are removed.  If no argument is present, all debugging flags are cleared
-(as if no @option{-d} was given), and with an empty argument the flags
-are reset to the default of @samp{aeq}.
+(as if by @samp{-V}), and with an empty argument the flags are reset to
+the default of @samp{+adeq}.
 
 The expansion of @code{debugmode} is void.
 @end deffn
diff --git a/src/builtin.c b/src/builtin.c
index 34387b9..a4e5bee 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -724,7 +724,8 @@ m4_undefine (struct obstack *obs, int argc, macro_arguments *argv)
   for (i = 1; i < argc; i++)
     if (arg_type (argv, i) != TOKEN_TEXT)
       m4_warn (0, me, _("invalid macro name ignored"));
-    else if (!lookup_symbol (ARG (i), ARG_LEN (i), SYMBOL_DELETE))
+    else if (!lookup_symbol (ARG (i), ARG_LEN (i), SYMBOL_DELETE)
+	     && (debug_level & DEBUG_TRACE_DEREF))
       m4_warn (0, me, _("undefined macro %s"),
 	       quotearg_style_mem (locale_quoting_style, ARG (i),
 				   ARG_LEN (i)));
@@ -746,7 +747,8 @@ m4_popdef (struct obstack *obs, int argc, macro_arguments *argv)
   for (i = 1; i < argc; i++)
     if (arg_type (argv, i) != TOKEN_TEXT)
       m4_warn (0, me, _("invalid macro name ignored"));
-    else if (!lookup_symbol (ARG (i), ARG_LEN (i), SYMBOL_POPDEF))
+    else if (!lookup_symbol (ARG (i), ARG_LEN (i), SYMBOL_POPDEF)
+	     && (debug_level & DEBUG_TRACE_DEREF))
       m4_warn (0, me, _("undefined macro %s"),
 	       quotearg_style_mem (locale_quoting_style, ARG (i),
 				   ARG_LEN (i)));
@@ -896,7 +898,7 @@ m4_dumpdef (struct obstack *obs, int argc, macro_arguments *argv)
 	  s = lookup_symbol (ARG (i), ARG_LEN (i), SYMBOL_LOOKUP);
 	  if (s != NULL && SYMBOL_TYPE (s) != TOKEN_VOID)
 	    dump_symbol (s, &data);
-	  else
+	  else if (debug_level & DEBUG_TRACE_DEREF)
 	    m4_warn (0, me, _("undefined macro %s"),
 		     quotearg_style_mem (locale_quoting_style, ARG (i),
 					 ARG_LEN (i)));
@@ -970,8 +972,11 @@ m4_builtin (struct obstack *obs, int argc, macro_arguments *argv)
   name = ARG (1);
   bp = find_builtin_by_name (name);
   if (bp->func == m4_placeholder)
-    m4_warn (0, me, _("undefined builtin %s"),
-	     quotearg_style_mem (locale_quoting_style, name, ARG_LEN (1)));
+    {
+      if (debug_level & DEBUG_TRACE_DEREF)
+	m4_warn (0, me, _("undefined builtin %s"),
+		 quotearg_style_mem (locale_quoting_style, name, ARG_LEN (1)));
+    }
   else
     {
       macro_arguments *new_argv = make_argv_ref (argv, name, ARG_LEN (1),
@@ -1007,8 +1012,11 @@ m4_indir (struct obstack *obs, int argc, macro_arguments *argv)
   len = ARG_LEN (1);
   s = lookup_symbol (name, len, SYMBOL_LOOKUP);
   if (s == NULL || SYMBOL_TYPE (s) == TOKEN_VOID)
-    m4_warn (0, me, _("undefined macro %s"),
-	     quotearg_style_mem (locale_quoting_style, name, len));
+    {
+      if (debug_level & DEBUG_TRACE_DEREF)
+	m4_warn (0, me, _("undefined macro %s"),
+		 quotearg_style_mem (locale_quoting_style, name, len));
+    }
   else
     {
       macro_arguments *new_argv = make_argv_ref (argv, name, len,
@@ -1046,9 +1054,10 @@ m4_defn (struct obstack *obs, int argc, macro_arguments *argv)
       s = lookup_symbol (ARG (i), ARG_LEN (i), SYMBOL_LOOKUP);
       if (s == NULL || SYMBOL_TYPE (s) == TOKEN_VOID)
 	{
-	  m4_warn (0, me, _("undefined macro %s"),
-		   quotearg_style_mem (locale_quoting_style, ARG (i),
-				       ARG_LEN (i)));
+	  if (debug_level & DEBUG_TRACE_DEREF)
+	    m4_warn (0, me, _("undefined macro %s"),
+		     quotearg_style_mem (locale_quoting_style, ARG (i),
+					 ARG_LEN (i)));
 	  continue;
 	}
 
diff --git a/src/debug.c b/src/debug.c
index 579960b..babaf87 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -105,6 +105,10 @@ debug_decode (const char *opts)
 	      level |= DEBUG_TRACE_CALLID;
 	      break;
 
+	    case 'd':
+	      level |= DEBUG_TRACE_DEREF;
+	      break;
+
 	    case 'V':
 	      level |= DEBUG_TRACE_VERBOSE;
 	      break;
diff --git a/src/m4.c b/src/m4.c
index 22586fc..93beb40 100644
--- a/src/m4.c
+++ b/src/m4.c
@@ -36,7 +36,7 @@ static void usage (int);
 int sync_output = 0;
 
 /* Debug (-d[flags]).  */
-int debug_level = 0;
+int debug_level = DEBUG_TRACE_DEREF;
 
 /* Disable GNU extensions (-G).  */
 int no_gnu_extensions = 0;
@@ -257,7 +257,7 @@ Frozen state files:\n\
       fputs (_("\
 Debugging:\n\
   -d, --debug[=[-|+]FLAGS], --debugmode[=[-|+]FLAGS]\n\
-                               set debug level (no FLAGS implies `+aeq')\n\
+                               set debug level (no FLAGS implies `+adeq')\n\
       --debugfile=FILE         redirect debug and trace output\n\
   -l, --arglength=NUM          restrict macro tracing size\n\
   -t, --trace=NAME             trace NAME when it is defined\n\
@@ -267,6 +267,7 @@ Debugging:\n\
 FLAGS is any of:\n\
   a   show actual arguments in trace\n\
   c   show collection line in trace\n\
+  d   warn when dereferencing undefined macros (default on unless -E)\n\
   e   show expansion in trace\n\
   f   include current input file name in trace and debug\n\
   i   show changes in input files in debug\n\
@@ -479,6 +480,7 @@ main (int argc, char *const *argv, char *const *envp)
 	break;
 
       case 'E':
+	debug_decode ("-d");
 	if (!fatal_warnings)
 	  fatal_warnings = true;
 	else
diff --git a/src/m4.h b/src/m4.h
index 8da7d3c..27c0fa7 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -192,11 +192,13 @@ extern FILE *debug;
 #define DEBUG_TRACE_INPUT 0x100
 /* x: add call id to trace output */
 #define DEBUG_TRACE_CALLID 0x200
+/* d: warn if dereferencing undefined macro */
+#define DEBUG_TRACE_DEREF 0x400
 
 /* V: very verbose --  print everything */
-#define DEBUG_TRACE_VERBOSE 0x3FF
-/* default flags -- equiv: aeq */
-#define DEBUG_TRACE_DEFAULT 0x007
+#define DEBUG_TRACE_VERBOSE 0x7FF
+/* default flags -- equiv: adeq */
+#define DEBUG_TRACE_DEFAULT 0x407
 
 void debug_init (void);
 int debug_decode (const char *);
-- 
1.6.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.