* 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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@133847
138bc75d-0d04-0410-961f-
82ee72b054a4
+2008-04-02 Joseph Myers <joseph@codesourcery.com>
+
+ * 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.
+
2008-04-02 Anatoly Sokolov <aesok@post.ru>
* config/avr/predicates.md (io_address_operand): New predicate.
extern char flag_no_output;
-/* Nonzero means dump macros in some fashion; contains the 'D', 'M' or
- 'N' of the command line switch. */
+/* Nonzero means dump macros in some fashion; contains the 'D', 'M',
+ 'N' or 'U' of the command line switch. */
extern char flag_dump_macros;
case 'M': /* Dump macros only. */
case 'N': /* Dump names. */
case 'D': /* Dump definitions. */
+ case 'U': /* Dump used macros. */
flag_dump_macros = c;
break;
bool first_time; /* pp_file_change hasn't been called yet. */
} print;
+/* Defined and undefined macros being queued for output with -dU at
+ the next newline. */
+typedef struct macro_queue
+{
+ struct macro_queue *next; /* Next macro in the list. */
+ char *macro; /* The name of the macro if not
+ defined, the full definition if
+ defined. */
+} macro_queue;
+static macro_queue *define_queue, *undef_queue;
+
/* General output routines. */
static void scan_translation_unit (cpp_reader *);
static void print_lines_directives_only (int, const void *, size_t);
static void scan_translation_unit_trad (cpp_reader *);
static void account_for_newlines (const unsigned char *, size_t);
static int dump_macro (cpp_reader *, cpp_hashnode *, void *);
+static void dump_queued_macros (cpp_reader *);
static void print_line (source_location, const char *);
static void maybe_print_line (source_location);
static void cb_line_change (cpp_reader *, const cpp_token *, int);
static void cb_define (cpp_reader *, source_location, cpp_hashnode *);
static void cb_undef (cpp_reader *, source_location, cpp_hashnode *);
+static void cb_used_define (cpp_reader *, source_location, cpp_hashnode *);
+static void cb_used_undef (cpp_reader *, source_location, cpp_hashnode *);
static void cb_include (cpp_reader *, source_location, const unsigned char *,
const char *, int, const cpp_token **);
static void cb_ident (cpp_reader *, source_location, const cpp_string *);
cb->undef = cb_undef;
}
+ if (flag_dump_macros == 'U')
+ {
+ cb->before_define = dump_queued_macros;
+ cb->used_define = cb_used_define;
+ cb->used_undef = cb_used_undef;
+ }
+
/* Initialize the print structure. Setting print.src_line to -1 here is
a trick to guarantee that the first token of the file will cause
a linemarker to be output by maybe_print_line. */
{
source_location src_loc = token->src_loc;
+ if (define_queue || undef_queue)
+ dump_queued_macros (pfile);
+
if (token->type == CPP_EOF || parsing_args)
return;
}
static void
+cb_used_define (cpp_reader *pfile, source_location line ATTRIBUTE_UNUSED,
+ cpp_hashnode *node)
+{
+ macro_queue *q;
+ q = XNEW (macro_queue);
+ q->macro = xstrdup ((const char *) cpp_macro_definition (pfile, node));
+ q->next = define_queue;
+ define_queue = q;
+}
+
+static void
+cb_used_undef (cpp_reader *pfile ATTRIBUTE_UNUSED,
+ source_location line ATTRIBUTE_UNUSED,
+ cpp_hashnode *node)
+{
+ macro_queue *q;
+ q = XNEW (macro_queue);
+ q->macro = xstrdup ((const char *) NODE_NAME (node));
+ q->next = undef_queue;
+ undef_queue = q;
+}
+
+static void
+dump_queued_macros (cpp_reader *pfile ATTRIBUTE_UNUSED)
+{
+ macro_queue *q;
+
+ /* End the previous line of text. */
+ if (print.printed)
+ {
+ putc ('\n', print.outf);
+ print.src_line++;
+ print.printed = 0;
+ }
+
+ for (q = define_queue; q;)
+ {
+ macro_queue *oq;
+ fputs ("#define ", print.outf);
+ fputs (q->macro, print.outf);
+ putc ('\n', print.outf);
+ print.src_line++;
+ oq = q;
+ q = q->next;
+ free (oq->macro);
+ free (oq);
+ }
+ define_queue = NULL;
+ for (q = undef_queue; q;)
+ {
+ macro_queue *oq;
+ fprintf (print.outf, "#undef %s\n", q->macro);
+ print.src_line++;
+ oq = q;
+ q = q->next;
+ free (oq->macro);
+ free (oq);
+ }
+ undef_queue = NULL;
+}
+
+static void
cb_include (cpp_reader *pfile ATTRIBUTE_UNUSED, source_location line,
const unsigned char *dir, const char *header, int angle_brackets,
const cpp_token **comments)
@opindex dI
Output @samp{#include} directives in addition to the result of
preprocessing.
+
+@item U
+@opindex dU
+Like @samp{D} except that only macros that are expanded, or whose
+definedness is tested in preprocessor directives, are output; the
+output is delayed until the use or test of the macro; and
+@samp{#undef} directives are also output for macros tested but
+undefined at the time.
@end table
@item -P
+2008-04-02 Joseph Myers <joseph@codesourcery.com>
+
+ * 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.
+
2008-04-02 Richard Guenther <rguenther@suse.de>
PR tree-optimization/14495
--- /dev/null
+/* { dg-do preprocess } */
+/* { dg-options "-P -dU" } */
+/* { dg-final { scan-file cmdlne-dU-1.i "^\n*#undef A\n*$" } } */
+#ifdef A
+#endif
--- /dev/null
+/* { dg-do preprocess } */
+/* { dg-options "-P -dU" } */
+/* { dg-final { scan-file cmdlne-dU-10.i "^\n*C\n+#define B C\n+#define A B\n*$" } } */
+/* This file deliberately has no final newline. */
+#define A B
+#define B C
+A
\ No newline at end of file
--- /dev/null
+/* { dg-do preprocess } */
+/* { dg-options "-P -dU" } */
+/* { dg-final { scan-file cmdlne-dU-11.i "^\n*\n*$" } } */
+#define A B
+#if 0
+A
+#endif
--- /dev/null
+/* { dg-do preprocess } */
+/* { dg-options "-P -dU" } */
+/* { dg-final { scan-file cmdlne-dU-12.i "^\n*#define A 1\n*$" } } */
+#define A 1
+#if A
+#endif
--- /dev/null
+/* { dg-do preprocess } */
+/* { dg-options "-P -dU" } */
+/* { dg-final { scan-file cmdlne-dU-13.i "^\n*#undef A\n*$" } } */
+#ifdef A
+#endif
+#ifdef A
+#endif
--- /dev/null
+/* { dg-do preprocess } */
+/* { dg-options "-P -dU" } */
+/* { dg-final { scan-file cmdlne-dU-14.i "^\n*B\n+#define A B\n+B\n*$" } } */
+#define A B
+A
+A
--- /dev/null
+/* { dg-do preprocess } */
+/* { dg-options "-P -dU" } */
+/* { dg-final { scan-file cmdlne-dU-15.i "^\n*\n*$" } } */
+#if A
+#endif
--- /dev/null
+/* { dg-do preprocess } */
+/* { dg-options "-P -dU" } */
+/* { dg-final { scan-file cmdlne-dU-16.i "^\n*#define __STDC__ 1\n*$" } } */
+#ifdef __STDC__
+#endif
--- /dev/null
+/* { dg-do preprocess } */
+/* { dg-options "-P -dU" } */
+/* { dg-final { scan-file cmdlne-dU-17.i "^\n*1\n+#define __STDC__ 1\n*$" } } */
+__STDC__
--- /dev/null
+/* { dg-do preprocess } */
+/* { dg-options "-P -dU" } */
+/* { dg-final { scan-file cmdlne-dU-18.i "^\n*x 1 y\n+#define A 1\n*$" } } */
+#define A 1
+x A y
--- /dev/null
+/* { dg-do preprocess } */
+/* { dg-options "-P -dU" } */
+/* { dg-final { scan-file cmdlne-dU-19.i "^\n*B\n+#define A B\n+#undef A\n*$" } } */
+#define A B
+A
+#undef A
+#ifdef A
+#endif
--- /dev/null
+/* { dg-do preprocess } */
+/* { dg-options "-P -dU" } */
+/* { dg-final { scan-file cmdlne-dU-2.i "^\n*#define A *\n*$" } } */
+#define A
+#ifdef A
+#endif
--- /dev/null
+/* { dg-do preprocess } */
+/* { dg-options "-P -dU" } */
+/* { dg-final { scan-file cmdlne-dU-20.i "^\n*A B\n*$" } } */
+#define A(x) x
+A B
--- /dev/null
+/* { dg-do preprocess } */
+/* { dg-options "-P -dU" } */
+/* { dg-final { scan-file cmdlne-dU-21.i "^\n*hello There\n+#define ASTRING There\n+#define MACROARGS\\(A\\) A\n+#undef BSTRING\n*$" } } */
+#define ASTRING There
+#define MACROARGS(A) A
+MACROARGS(hello) ASTRING
+#ifdef BSTRING
+bye
+#endif
--- /dev/null
+/* { dg-do preprocess } */
+/* { dg-options "-P -dU" } */
+/* { dg-final { scan-file cmdlne-dU-22.i "^\n*#undef AAA\n+AAA is undefined\n+#undef BBB\n+BBB is undefined\n+#undef CCC\n+CCC is undefined\n*$" } } */
+#ifndef AAA
+AAA is undefined
+#endif
+
+#ifndef BBB
+BBB is undefined
+#endif
+
+#ifndef CCC
+CCC is undefined
+#endif
--- /dev/null
+/* { dg-do preprocess } */
+/* { dg-options "-P -dU" } */
+/* { dg-final { scan-file cmdlne-dU-3.i "^\n*#define A B\n*$" } } */
+#define A B
+#ifndef A
+#endif
--- /dev/null
+/* { dg-do preprocess } */
+/* { dg-options "-P -dU" } */
+/* { dg-final { scan-file cmdlne-dU-4.i "^\n*#undef A\n*$" } } */
+#if defined(A)
+#endif
--- /dev/null
+/* { dg-do preprocess } */
+/* { dg-options "-P -dU" } */
+/* { dg-final { scan-file cmdlne-dU-5.i "^\n*#undef A\n*$" } } */
+#ifdef A
+#ifdef B
+#endif
+#endif
--- /dev/null
+/* { dg-do preprocess } */
+/* { dg-options "-P -dU" } */
+/* { dg-final { scan-file cmdlne-dU-6.i "^\n*#undef A\n+#define A *\n*$" } } */
+#ifdef A
+#endif
+#define A
+#ifdef A
+#endif
--- /dev/null
+/* { dg-do preprocess } */
+/* { dg-options "-P -dU" } */
+/* { dg-final { scan-file cmdlne-dU-7.i "^\n*B\n+#define A B\n+C\n+#define A C\n*$" } } */
+#define A B
+A
+#undef A
+#define A C
+A
--- /dev/null
+/* { dg-do preprocess } */
+/* { dg-options "-P -dU" } */
+/* { dg-final { scan-file cmdlne-dU-8.i "^\n*B D\n+#define A\\(x\\) B x\n+#define C D\n*$" } } */
+#define A(x) B x
+#define C D
+A(C)
--- /dev/null
+/* { dg-do preprocess } */
+/* { dg-options "-P -dU" } */
+/* { dg-final { scan-file cmdlne-dU-9.i "^\n*C\n+#define B C\n+#define A B\n*$" } } */
+#define A B
+#define B C
+A
case 'I':
case 'M':
case 'N':
+ case 'U':
break;
case 'H':
setup_core_dumping();
+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
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;
}
}
if (node)
{
+ if (pfile->cb.before_define)
+ pfile->cb.before_define (pfile);
+
if (pfile->cb.undef)
pfile->cb.undef (pfile, pfile->directive_line, node);
/* 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;
}
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);
}
}
do_ifndef (cpp_reader *pfile)
{
int skip = 1;
- const cpp_hashnode *node = 0;
+ cpp_hashnode *node = 0;
if (! pfile->state.skipping)
{
{
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);
}
}
if (node == NULL)
return;
+ if (pfile->cb.before_define)
+ pfile->cb.before_define (pfile);
+
if (node->type == NT_MACRO)
{
if (pfile->cb.undef)
"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. */
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. */
#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
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))
{
/* 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)
/* 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