diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 79dd06e583e..626b0cbdda2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2002-06-13 Neil Booth + + * cpplib.c (end_directive): Handle line skipping. Only remove + the rest of the line if the directive was valid. + * cppmacro.c (_cpp_push_text_context): Set NODE_DISABLED when + expanding a traditional macro. + * cpptrad.c (recursive_macro): New. + (read_logical_line_trad): Handle skipping. + (scan_out_logical_line): Continue after a successful directive. + Don't expand macros whilst skipping, or if recursing. + (_cpp_create_trad_definition): scan_out_logical_line now sets + the output current position. + 2002-06-12 Eric Christopher From Chris Demetriou diff --git a/gcc/cpplib.c b/gcc/cpplib.c index 73e12b7d8d5..acc71e7120a 100644 --- a/gcc/cpplib.c +++ b/gcc/cpplib.c @@ -256,7 +256,7 @@ end_directive (pfile, skip_line) { if (CPP_OPTION (pfile, traditional)) { - if (pfile->directive == &dtable[T_DEFINE]) + if (!pfile->directive || pfile->directive == &dtable[T_DEFINE]) skip_line = false; else _cpp_remove_overlay (pfile); @@ -290,12 +290,15 @@ prepare_directive_trad (pfile) else { bool no_expand = ! (pfile->directive->flags & EXPAND); + bool was_skipping = pfile->state.skipping; + pfile->state.skipping = false; if (no_expand) pfile->state.prevent_expansion++; _cpp_read_logical_line_trad (pfile); if (no_expand) pfile->state.prevent_expansion--; + pfile->state.skipping = was_skipping; _cpp_overlay_buffer (pfile, pfile->out.base, pfile->out.cur - pfile->out.base); } diff --git a/gcc/cppmacro.c b/gcc/cppmacro.c index a9ca6cf2dbf..20149ec9b33 100644 --- a/gcc/cppmacro.c +++ b/gcc/cppmacro.c @@ -947,6 +947,7 @@ _cpp_push_text_context (pfile, macro, start, len) context->buff = NULL; CUR (context) = start; RLIMIT (context) = start + len; + macro->flags |= NODE_DISABLED; } /* Expand an argument ARG before replacing parameters in a diff --git a/gcc/cpptrad.c b/gcc/cpptrad.c index 33e4575cf95..03ee0e893a6 100644 --- a/gcc/cpptrad.c +++ b/gcc/cpptrad.c @@ -82,6 +82,7 @@ static void scan_out_logical_line PARAMS ((cpp_reader *pfile, cpp_macro *)); static void check_output_buffer PARAMS ((cpp_reader *, size_t)); static void push_replacement_text PARAMS ((cpp_reader *, cpp_hashnode *)); static bool scan_parameters PARAMS ((cpp_reader *, cpp_macro *)); +static bool recursive_macro PARAMS ((cpp_reader *, cpp_hashnode *)); static void save_replacement_text PARAMS ((cpp_reader *, cpp_macro *, unsigned int)); static void maybe_start_funlike PARAMS ((cpp_reader *, cpp_hashnode *, @@ -304,30 +305,31 @@ bool _cpp_read_logical_line_trad (pfile) cpp_reader *pfile; { - cpp_buffer *buffer; + cpp_buffer *buffer = pfile->buffer; - buffer = pfile->buffer; - if (buffer->cur == buffer->rlimit) + do { - bool stop = true; - - /* Don't pop the last buffer. */ - if (buffer->prev) + if (buffer->cur == buffer->rlimit) { - stop = buffer->return_at_eof; - _cpp_pop_buffer (pfile); + bool stop = true; + + /* Don't pop the last buffer. */ + if (buffer->prev) + { + stop = buffer->return_at_eof; + _cpp_pop_buffer (pfile); + } + + if (stop) + return false; } - if (stop) - return false; + CUR (pfile->context) = buffer->cur; + RLIMIT (pfile->context) = buffer->rlimit; + scan_out_logical_line (pfile, NULL); + buffer->cur = CUR (pfile->context); } - - CUR (pfile->context) = buffer->cur; - RLIMIT (pfile->context) = buffer->rlimit; - pfile->out.cur = pfile->out.base; - pfile->out.first_line = pfile->line; - scan_out_logical_line (pfile, NULL); - buffer->cur = CUR (pfile->context); + while (pfile->state.skipping); return true; } @@ -384,6 +386,10 @@ scan_out_logical_line (pfile, macro) struct fun_macro fmacro; fmacro.buff = NULL; + + start_logical_line: + pfile->out.cur = pfile->out.base; + pfile->out.first_line = pfile->line; new_context: context = pfile->context; cur = CUR (context); @@ -483,8 +489,10 @@ scan_out_logical_line (pfile, macro) node = lex_identifier (pfile, cur - 1); if (node->type == NT_MACRO + && !pfile->state.skipping && pfile->state.parsing_args != 2 - && !pfile->state.prevent_expansion) + && !pfile->state.prevent_expansion + && !recursive_macro (pfile, node)) { if (node->value.macro->fun_like) maybe_start_funlike (pfile, node, out, &fmacro); @@ -582,10 +590,7 @@ scan_out_logical_line (pfile, macro) preprocessor lex the next token. */ pfile->buffer->cur = cur; if (_cpp_handle_directive (pfile, false /* indented */)) - { - cur = CUR (context); - goto done; - } + goto start_logical_line; } break; @@ -615,6 +620,48 @@ push_replacement_text (pfile, node) _cpp_push_text_context (pfile, node, macro->exp.text, macro->count); } +/* Returns TRUE if traditional macro recursion is detected. */ +static bool +recursive_macro (pfile, node) + cpp_reader *pfile; + cpp_hashnode *node; +{ + bool recursing = node->flags & NODE_DISABLED; + + /* Object-like macros that are already expanding are necessarily + recursive. + + However, it is possible to have traditional function-like macros + that are not infinitely recursive but recurse to any given depth. + Further, it is easy to construct examples that get ever longer + until the point they stop recursing. So there is no easy way to + 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) + { + size_t depth = 0; + cpp_context *context = pfile->context; + + do + { + depth++; + if (context->macro == node && depth > 20) + break; + context = context->prev; + } + while (context); + recursing = context != NULL; + } + + if (recursing) + cpp_error (pfile, DL_ERROR, + "detected recursion whilst expanding macro \"%s\"", + NODE_NAME (node)); + + return recursing; +} + /* Push a context holding the replacement text of the macro NODE on the context stack. NODE is either object-like, or a function-like macro with no arguments. */ @@ -804,7 +851,6 @@ _cpp_create_trad_definition (pfile, macro) /* Skip leading whitespace in the replacement text. */ CUR (pfile->context) = skip_whitespace (pfile, CUR (pfile->context)); - pfile->out.cur = pfile->out.base; pfile->state.prevent_expansion++; scan_out_logical_line (pfile, macro); pfile->state.prevent_expansion--;