cppopts.texi (-dU): Document.

gcc:
	* doc/cppopts.texi (-dU): Document.
	* c-common.h (flag_dump_macros): Update comment.
	* c-opts.c (handle_OPT_d): Handle -dU.
	* c-ppoutput.c (macro_queue, define_queue, undef_queue,
	dump_queued_macros, cb_used_define, cb_used_undef): New.
	(init_pp_output): Handle -dU.
	(cb_line_change): Call dump_queued_macros.
	* toplev.c (decode_d_option): Accept -dU as preprocessor option.

gcc/testsuite:
	* gcc.dg/cpp/cmdlne-dU-1.c, gcc.dg/cpp/cmdlne-dU-2.c,
	gcc.dg/cpp/cmdlne-dU-3.c, gcc.dg/cpp/cmdlne-dU-4.c,
	gcc.dg/cpp/cmdlne-dU-5.c, gcc.dg/cpp/cmdlne-dU-6.c,
	gcc.dg/cpp/cmdlne-dU-7.c, gcc.dg/cpp/cmdlne-dU-8.c,
	gcc.dg/cpp/cmdlne-dU-9.c, gcc.dg/cpp/cmdlne-dU-10.c,
	gcc.dg/cpp/cmdlne-dU-11.c, gcc.dg/cpp/cmdlne-dU-12.c,
	gcc.dg/cpp/cmdlne-dU-13.c, gcc.dg/cpp/cmdlne-dU-14.c,
	gcc.dg/cpp/cmdlne-dU-15.c, gcc.dg/cpp/cmdlne-dU-16.c,
	gcc.dg/cpp/cmdlne-dU-17.c, gcc.dg/cpp/cmdlne-dU-18.c,
	gcc.dg/cpp/cmdlne-dU-19.c, gcc.dg/cpp/cmdlne-dU-20.c,
	gcc.dg/cpp/cmdlne-dU-21.c, gcc.dg/cpp/cmdlne-dU-22.c: New tests.

libcpp:
	* include/cpplib.h (struct cpp_callbacks): Add used_define,
	used_undef and before_define.
	(NODE_USED): Define.
	* directives.c (do_define, do_undef, undefine_macros, do_ifdef,
	do_ifndef, cpp_pop_definition): Handle new flag and use new
	callbacks.
	* expr.c (parse_defined): Handle new flag and use new callbacks.
	* macro.c (enter_macro_context, _cpp_free_definition): Handle new
	flag and use new callbacks.

From-SVN: r133847
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index e8719d9..f5c623d 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,15 @@
+2008-04-02  Joseph Myers  <joseph@codesourcery.com>
+
+	* include/cpplib.h (struct cpp_callbacks): Add used_define,
+	used_undef and before_define.
+	(NODE_USED): Define.
+	* directives.c (do_define, do_undef, undefine_macros, do_ifdef,
+	do_ifndef, cpp_pop_definition): Handle new flag and use new
+	callbacks.
+	* expr.c (parse_defined): Handle new flag and use new callbacks.
+	* macro.c (enter_macro_context, _cpp_free_definition): Handle new
+	flag and use new callbacks.
+
 2008-04-01  Jakub Jelinek  <jakub@redhat.com>
 
 	PR pch/13675
diff --git a/libcpp/directives.c b/libcpp/directives.c
index 249a232..0ca1117 100644
--- a/libcpp/directives.c
+++ b/libcpp/directives.c
@@ -559,9 +559,14 @@
       pfile->state.save_comments =
 	! CPP_OPTION (pfile, discard_comments_in_macro_exp);
 
+      if (pfile->cb.before_define)
+	pfile->cb.before_define (pfile);
+
       if (_cpp_create_definition (pfile, node))
 	if (pfile->cb.define)
 	  pfile->cb.define (pfile, pfile->directive_line, node);
+
+      node->flags &= ~NODE_USED;
     }
 }
 
@@ -573,6 +578,9 @@
 
   if (node)
     {
+      if (pfile->cb.before_define)
+	pfile->cb.before_define (pfile);
+
       if (pfile->cb.undef)
 	pfile->cb.undef (pfile, pfile->directive_line, node);
 
@@ -603,7 +611,7 @@
   /* Body of _cpp_free_definition inlined here for speed.
      Macros and assertions no longer have anything to free.  */
   h->type = NT_VOID;
-  h->flags &= ~(NODE_POISONED|NODE_BUILTIN|NODE_DISABLED);
+  h->flags &= ~(NODE_POISONED|NODE_BUILTIN|NODE_DISABLED|NODE_USED);
   return 1;
 }
 
@@ -1638,12 +1646,26 @@
 
   if (! pfile->state.skipping)
     {
-      const cpp_hashnode *node = lex_macro_node (pfile, false);
+      cpp_hashnode *node = lex_macro_node (pfile, false);
 
       if (node)
 	{
 	  skip = node->type != NT_MACRO;
 	  _cpp_mark_macro_used (node);
+	  if (!(node->flags & NODE_USED))
+	    {
+	      node->flags |= NODE_USED;
+	      if (node->type == NT_MACRO)
+		{
+		  if (pfile->cb.used_define)
+		    pfile->cb.used_define (pfile, pfile->directive_line, node);
+		}
+	      else
+		{
+		  if (pfile->cb.used_undef)
+		    pfile->cb.used_undef (pfile, pfile->directive_line, node);
+		}
+	    }
 	  check_eol (pfile);
 	}
     }
@@ -1656,7 +1678,7 @@
 do_ifndef (cpp_reader *pfile)
 {
   int skip = 1;
-  const cpp_hashnode *node = 0;
+  cpp_hashnode *node = 0;
 
   if (! pfile->state.skipping)
     {
@@ -1666,6 +1688,20 @@
 	{
 	  skip = node->type == NT_MACRO;
 	  _cpp_mark_macro_used (node);
+	  if (!(node->flags & NODE_USED))
+	    {
+	      node->flags |= NODE_USED;
+	      if (node->type == NT_MACRO)
+		{
+		  if (pfile->cb.used_define)
+		    pfile->cb.used_define (pfile, pfile->directive_line, node);
+		}
+	      else
+		{
+		  if (pfile->cb.used_undef)
+		    pfile->cb.used_undef (pfile, pfile->directive_line, node);
+		}
+	    }
 	  check_eol (pfile);
 	}
     }
@@ -2145,6 +2181,9 @@
   if (node == NULL)
     return;
 
+  if (pfile->cb.before_define)
+    pfile->cb.before_define (pfile);
+
   if (node->type == NT_MACRO)
     {
       if (pfile->cb.undef)
diff --git a/libcpp/expr.c b/libcpp/expr.c
index 9df7533..9e89dd9 100644
--- a/libcpp/expr.c
+++ b/libcpp/expr.c
@@ -637,6 +637,20 @@
 		   "this use of \"defined\" may not be portable");
 
       _cpp_mark_macro_used (node);
+      if (!(node->flags & NODE_USED))
+	{
+	  node->flags |= NODE_USED;
+	  if (node->type == NT_MACRO)
+	    {
+	      if (pfile->cb.used_define)
+		pfile->cb.used_define (pfile, pfile->directive_line, node);
+	    }
+	  else
+	    {
+	      if (pfile->cb.used_undef)
+		pfile->cb.used_undef (pfile, pfile->directive_line, node);
+	    }
+	}
 
       /* A possible controlling macro of the form #if !defined ().
 	 _cpp_parse_expr checks there was no other junk on the line.  */
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index e205be7..84de0e0 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -480,6 +480,14 @@
      This callback receives the translated message.  */
   void (*error) (cpp_reader *, int, const char *, va_list *)
        ATTRIBUTE_FPTR_PRINTF(3,0);
+
+  /* Callbacks for when a macro is expanded, or tested (whether
+     defined or not at the time) in #ifdef, #ifndef or "defined".  */
+  void (*used_define) (cpp_reader *, unsigned int, cpp_hashnode *);
+  void (*used_undef) (cpp_reader *, unsigned int, cpp_hashnode *);
+  /* Called before #define and #undef or other macro definition
+     changes are processed.  */
+  void (*before_define) (cpp_reader *);
 };
 
 /* Chain of directories to look for include files in.  */
@@ -537,6 +545,7 @@
 #define NODE_WARN	(1 << 4)	/* Warn if redefined or undefined.  */
 #define NODE_DISABLED	(1 << 5)	/* A disabled macro.  */
 #define NODE_MACRO_ARG	(1 << 6)	/* Used during #define processing.  */
+#define NODE_USED	(1 << 7)	/* Dumped with -dU.  */
 
 /* Different flavors of hash node.  */
 enum node_type
diff --git a/libcpp/macro.c b/libcpp/macro.c
index fd624b1..587b948 100644
--- a/libcpp/macro.c
+++ b/libcpp/macro.c
@@ -815,6 +815,13 @@
 
   pfile->state.angled_headers = false;
 
+  if ((node->flags & NODE_BUILTIN) && !(node->flags & NODE_USED))
+    {
+      node->flags |= NODE_USED;
+      if (pfile->cb.used_define)
+	pfile->cb.used_define (pfile, pfile->directive_line, node);
+    }
+
   /* Handle standard macros.  */
   if (! (node->flags & NODE_BUILTIN))
     {
@@ -854,6 +861,13 @@
       /* Disable the macro within its expansion.  */
       node->flags |= NODE_DISABLED;
 
+      if (!(node->flags & NODE_USED))
+	{
+	  node->flags |= NODE_USED;
+	  if (pfile->cb.used_define)
+	    pfile->cb.used_define (pfile, pfile->directive_line, node);
+	}
+
       macro->used = 1;
 
       if (macro->paramc == 0)
@@ -1393,7 +1407,7 @@
   /* Macros and assertions no longer have anything to free.  */
   h->type = NT_VOID;
   /* Clear builtin flag in case of redefinition.  */
-  h->flags &= ~(NODE_BUILTIN | NODE_DISABLED);
+  h->flags &= ~(NODE_BUILTIN | NODE_DISABLED | NODE_USED);
 }
 
 /* Save parameter NODE to the parameter list of macro MACRO.  Returns