From a5c3cccda43ddeaa0e90df75f74c230dea0ad579 Mon Sep 17 00:00:00 2001 From: Neil Booth Date: Mon, 30 Oct 2000 22:29:00 +0000 Subject: [PATCH] cppfiles.c (stack_include_file): Check for stacked contexts here. * cppfiles.c (stack_include_file): Check for stacked contexts here. * cpphash.h (_cpp_do__Pragma): New prototype. * cppinit.c (cpp_reader_init): Add _Pragma keyword to hash table. * cpplex.c (skip_escaped_newlines): Only process trigraphs and escaped newlines if !(buffer->from_stage3). (_cpp_lex_token): Warn about missing newlines iff !buffer->from_stage3. * cpplib.c (get__Pragma_string, destringize, _cpp_do__Pragma): New functions. (run_directive): Set output_line for _Pragma to avoid line markers in output. Set from_stage3 and prevent macro expansion for _Pragma and command-line options. Check buffer exhaustion. (cpp_push_buffer): Don't check for stacked macro contexts, as this is perfectly legitimate for _Pragma. Move the check to stack_include_file instead. Set from_stage3 iff buffer is preprocessed input. * cpplib.h (struct cpp_buffer): Make warned_cplusplus_comments unsigned. New boolean from_stage3. (struct spec_nodes): Add n__Pragma. * cppmacro.c (enter_macro_context): Flip sense of return value. (_cpp_get_token): Handle _Pragma operator. From-SVN: r37147 --- gcc/ChangeLog | 29 ++++++++++++++++ gcc/cppfiles.c | 3 ++ gcc/cpphash.h | 1 + gcc/cppinit.c | 1 + gcc/cpplex.c | 104 ++++++++++++++++++++++++++++++--------------------------- gcc/cpplib.c | 89 +++++++++++++++++++++++++++++++++++++++++++----- gcc/cpplib.h | 8 ++++- gcc/cppmacro.c | 44 +++++++++++++++--------- 8 files changed, 206 insertions(+), 73 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 70b9172..0cc78db 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,32 @@ +2000-10-30 Neil Booth + + * cppfiles.c (stack_include_file): Check for stacked contexts + here. + * cpphash.h (_cpp_do__Pragma): New prototype. + * cppinit.c (cpp_reader_init): Add _Pragma keyword to hash table. + + * cpplex.c (skip_escaped_newlines): Only process trigraphs and + escaped newlines if !(buffer->from_stage3). + (_cpp_lex_token): Warn about missing newlines iff + !buffer->from_stage3. + + * cpplib.c (get__Pragma_string, destringize, + _cpp_do__Pragma): New functions. + (run_directive): Set output_line for _Pragma to avoid line + markers in output. Set from_stage3 and prevent macro expansion + for _Pragma and command-line options. Check buffer exhaustion. + (cpp_push_buffer): Don't check for stacked macro contexts, as + this is perfectly legitimate for _Pragma. Move the check to + stack_include_file instead. Set from_stage3 iff buffer is + preprocessed input. + + * cpplib.h (struct cpp_buffer): Make warned_cplusplus_comments + unsigned. New boolean from_stage3. + (struct spec_nodes): Add n__Pragma. + + * cppmacro.c (enter_macro_context): Flip sense of return value. + (_cpp_get_token): Handle _Pragma operator. + 2000-10-30 Phil Edwards * gcc.texi: The C++ standard isn't "draft" anymore. diff --git a/gcc/cppfiles.c b/gcc/cppfiles.c index f54fe8a..1009fa7 100644 --- a/gcc/cppfiles.c +++ b/gcc/cppfiles.c @@ -206,6 +206,9 @@ stack_include_file (pfile, inc) { cpp_buffer *fp; + if (pfile->context->prev) + cpp_ice (pfile, "attempt to push file buffer with contexts stacked"); + if (DO_NOT_REREAD (inc)) return 0; diff --git a/gcc/cpphash.h b/gcc/cpphash.h index bba1ba9..a1c859d 100644 --- a/gcc/cpphash.h +++ b/gcc/cpphash.h @@ -203,6 +203,7 @@ extern void _cpp_unlock_pool PARAMS ((cpp_pool *)); extern int _cpp_test_assertion PARAMS ((cpp_reader *, int *)); extern int _cpp_handle_directive PARAMS ((cpp_reader *, int)); extern void _cpp_define_builtin PARAMS ((cpp_reader *, const char *)); +extern void _cpp_do__Pragma PARAMS ((cpp_reader *)); extern void _cpp_init_stacks PARAMS ((cpp_reader *)); extern void _cpp_cleanup_stacks PARAMS ((cpp_reader *)); extern void _cpp_init_internal_pragmas PARAMS ((cpp_reader *)); diff --git a/gcc/cppinit.c b/gcc/cppinit.c index 20dfc63..512a0ff 100644 --- a/gcc/cppinit.c +++ b/gcc/cppinit.c @@ -487,6 +487,7 @@ cpp_reader_init (pfile) s = &pfile->spec_nodes; s->n_L = cpp_lookup (pfile, DSC("L")); s->n_defined = cpp_lookup (pfile, DSC("defined")); + s->n__Pragma = cpp_lookup (pfile, DSC("_Pragma")); s->n__STRICT_ANSI__ = cpp_lookup (pfile, DSC("__STRICT_ANSI__")); s->n__CHAR_UNSIGNED__ = cpp_lookup (pfile, DSC("__CHAR_UNSIGNED__")); s->n__VA_ARGS__ = cpp_lookup (pfile, DSC("__VA_ARGS__")); diff --git a/gcc/cpplex.c b/gcc/cpplex.c index ac8c3c4..43e090b 100644 --- a/gcc/cpplex.c +++ b/gcc/cpplex.c @@ -181,71 +181,77 @@ trigraph_ok (pfile, from_char) /* Skips any escaped newlines introduced by NEXT, which is either a '?' or a '\\'. Returns the next character, which will also have - been placed in buffer->read_ahead. */ + been placed in buffer->read_ahead. This routine performs + preprocessing stages 1 and 2 of the ISO C standard. */ static cppchar_t skip_escaped_newlines (buffer, next) cpp_buffer *buffer; cppchar_t next; { - cppchar_t next1; - const unsigned char *saved_cur; - int space; - - do + /* Only do this if we apply stages 1 and 2. */ + if (!buffer->from_stage3) { - if (buffer->cur == buffer->rlimit) - break; - - SAVE_STATE (); - if (next == '?') + cppchar_t next1; + const unsigned char *saved_cur; + int space; + + do { - next1 = *buffer->cur++; - if (next1 != '?' || buffer->cur == buffer->rlimit) + if (buffer->cur == buffer->rlimit) + break; + + SAVE_STATE (); + if (next == '?') { - RESTORE_STATE (); - break; + next1 = *buffer->cur++; + if (next1 != '?' || buffer->cur == buffer->rlimit) + { + RESTORE_STATE (); + break; + } + + next1 = *buffer->cur++; + if (!_cpp_trigraph_map[next1] + || !trigraph_ok (buffer->pfile, next1)) + { + RESTORE_STATE (); + break; + } + + /* We have a full trigraph here. */ + next = _cpp_trigraph_map[next1]; + if (next != '\\' || buffer->cur == buffer->rlimit) + break; + SAVE_STATE (); + } + + /* We have a backslash, and room for at least one more character. */ + space = 0; + do + { + next1 = *buffer->cur++; + if (!is_nvspace (next1)) + break; + space = 1; } + while (buffer->cur < buffer->rlimit); - next1 = *buffer->cur++; - if (!_cpp_trigraph_map[next1] || !trigraph_ok (buffer->pfile, next1)) + if (!is_vspace (next1)) { RESTORE_STATE (); break; } - /* We have a full trigraph here. */ - next = _cpp_trigraph_map[next1]; - if (next != '\\' || buffer->cur == buffer->rlimit) - break; - SAVE_STATE (); - } + if (space) + cpp_warning (buffer->pfile, + "backslash and newline separated by space"); - /* We have a backslash, and room for at least one more character. */ - space = 0; - do - { - next1 = *buffer->cur++; - if (!is_nvspace (next1)) - break; - space = 1; - } - while (buffer->cur < buffer->rlimit); - - if (!is_vspace (next1)) - { - RESTORE_STATE (); - break; + next = handle_newline (buffer, next1); + if (next == EOF) + cpp_pedwarn (buffer->pfile, "backslash-newline at end of file"); } - - if (space) - cpp_warning (buffer->pfile, - "backslash and newline separated by space"); - - next = handle_newline (buffer, next1); - if (next == EOF) - cpp_pedwarn (buffer->pfile, "backslash-newline at end of file"); + while (next == '\\' || next == '?'); } - while (next == '\\' || next == '?'); buffer->read_ahead = next; return next; @@ -863,8 +869,8 @@ _cpp_lex_token (pfile, result) { case EOF: /* Non-empty files should end in a newline. Ignore for command - line - we get e.g. -A options with no trailing \n. */ - if (pfile->lexer_pos.col != 0 && pfile->done_initializing) + line and _Pragma buffers. */ + if (pfile->lexer_pos.col != 0 && !buffer->from_stage3) cpp_pedwarn (pfile, "no newline at end of file"); pfile->state.skip_newlines = 1; result->type = CPP_EOF; diff --git a/gcc/cpplib.c b/gcc/cpplib.c index 18b44be..12fa982 100644 --- a/gcc/cpplib.c +++ b/gcc/cpplib.c @@ -99,6 +99,9 @@ static void do_pragma_once PARAMS ((cpp_reader *)); static void do_pragma_poison PARAMS ((cpp_reader *)); static void do_pragma_system_header PARAMS ((cpp_reader *)); static void do_pragma_dependency PARAMS ((cpp_reader *)); +static int get__Pragma_string PARAMS ((cpp_reader *, cpp_token *)); +static unsigned char *destringize PARAMS ((const cpp_string *, + unsigned int *)); static int parse_answer PARAMS ((cpp_reader *, struct answer **, int)); static cpp_hashnode *parse_assertion PARAMS ((cpp_reader *, struct answer **, int)); @@ -345,7 +348,7 @@ run_directive (pfile, dir_no, buf, count, name) size_t count; const char *name; { - if (cpp_push_buffer (pfile, (const U_CHAR *)buf, count) != NULL) + if (cpp_push_buffer (pfile, (const U_CHAR *) buf, count) != NULL) { const struct directive *dir = &dtable[dir_no]; @@ -353,15 +356,27 @@ run_directive (pfile, dir_no, buf, count, name) CPP_BUFFER (pfile)->nominal_fname = name; else CPP_BUFFER (pfile)->nominal_fname = _(""); - CPP_BUFFER (pfile)->lineno = (unsigned int)-1; + /* A kludge to avoid line markers for _Pragma. */ + if (dir_no == T_PRAGMA) + pfile->lexer_pos.output_line = CPP_BUFFER (pfile)->prev->lineno; + + /* For _Pragma, the text is passed through preprocessing stage 3 + only, i.e. no trigraphs, no escaped newline removal, and no + macro expansion. Do the same for command-line directives. */ + pfile->buffer->from_stage3 = 1; pfile->state.in_directive = 1; pfile->directive = dir; + pfile->state.prevent_expansion++; (void) (*dir->handler) (pfile); + pfile->state.prevent_expansion--; pfile->directive = 0; pfile->state.in_directive = 0; skip_rest_of_line (pfile); + if (pfile->buffer->cur != pfile->buffer->rlimit) + cpp_error (pfile, "extra text after end of #%s directive", + dtable[dir_no].name); cpp_pop_buffer (pfile); } } @@ -1069,6 +1084,68 @@ do_pragma_dependency (pfile) } } +/* Check syntax is "(string-literal)". Returns 0 on success. */ +static int +get__Pragma_string (pfile, string) + cpp_reader *pfile; + cpp_token *string; +{ + cpp_token paren; + + cpp_get_token (pfile, &paren); + if (paren.type != CPP_OPEN_PAREN) + return 1; + + cpp_get_token (pfile, string); + if (string->type != CPP_STRING && string->type != CPP_WSTRING) + return 1; + + cpp_get_token (pfile, &paren); + return paren.type != CPP_CLOSE_PAREN; +} + +/* Returns a malloced buffer containing a destringized cpp_string by + removing the first \ of \" and \\ sequences. */ +static unsigned char * +destringize (in, len) + const cpp_string *in; + unsigned int *len; +{ + const unsigned char *src, *limit; + unsigned char *dest, *result; + + dest = result = (unsigned char *) xmalloc (in->len); + for (src = in->text, limit = src + in->len; src < limit;) + { + /* We know there is a character following the backslash. */ + if (*src == '\\' && (src[1] == '\\' || src[1] == '"')) + src++; + *dest++ = *src++; + } + + *len = dest - result; + return result; +} + +void +_cpp_do__Pragma (pfile) + cpp_reader *pfile; +{ + cpp_token string; + unsigned char *buffer; + unsigned int len; + + if (get__Pragma_string (pfile, &string)) + { + cpp_error (pfile, "_Pragma takes a parenthesized string literal"); + return; + } + + buffer = destringize (&string.val.str, &len); + run_directive (pfile, T_PRAGMA, (char *) buffer, len, _("<_Pragma>")); + free ((PTR) buffer); +} + /* Just ignore #sccs, on systems where we define it at all. */ #ifdef SCCS_DIRECTIVE static void @@ -1626,12 +1703,6 @@ cpp_push_buffer (pfile, buffer, length) return NULL; } - if (pfile->context->prev) - { - cpp_ice (pfile, "buffer pushed with contexts stacked"); - skip_rest_of_line (pfile); - } - new = xobnew (pfile->buffer_ob, cpp_buffer); /* Clears, amongst other things, if_stack and mi_cmacro. */ memset (new, 0, sizeof (cpp_buffer)); @@ -1641,6 +1712,8 @@ cpp_push_buffer (pfile, buffer, length) new->rlimit = buffer + length; new->prev = buf; new->pfile = pfile; + /* Preprocessed files don't do trigraph and escaped newline processing. */ + new->from_stage3 = CPP_OPTION (pfile, preprocessed); /* No read ahead or extra char initially. */ new->read_ahead = EOF; new->extra_char = EOF; diff --git a/gcc/cpplib.h b/gcc/cpplib.h index 747ff18..de7a1a5 100644 --- a/gcc/cpplib.h +++ b/gcc/cpplib.h @@ -287,7 +287,12 @@ struct cpp_buffer The warning happens only for C89 extended mode with -pedantic on, or for -Wtraditional, and only once per file (otherwise it would be far too noisy). */ - char warned_cplusplus_comments; + unsigned char warned_cplusplus_comments; + + /* True if we don't process trigraphs and escaped newlines. True + for preprocessed input, command line directives, and _Pragma + buffers. */ + unsigned char from_stage3; }; /* Maximum nesting of cpp_buffers. We use a static limit, partly for @@ -509,6 +514,7 @@ struct spec_nodes { cpp_hashnode *n_L; /* L"str" */ cpp_hashnode *n_defined; /* defined operator */ + cpp_hashnode *n__Pragma; /* _Pragma operator */ cpp_hashnode *n__STRICT_ANSI__; /* STDC_0_IN_SYSTEM_HEADERS */ cpp_hashnode *n__CHAR_UNSIGNED__; /* plain char is unsigned */ cpp_hashnode *n__VA_ARGS__; /* C99 vararg macros */ diff --git a/gcc/cppmacro.c b/gcc/cppmacro.c index 9bd8884..484ce03 100644 --- a/gcc/cppmacro.c +++ b/gcc/cppmacro.c @@ -689,7 +689,8 @@ funlike_invocation_p (pfile, node, list) /* Push the context of a macro onto the context stack. TOKEN is the macro name. If we can successfully start expanding the macro, - TOKEN is replaced with the first token of the expansion. */ + TOKEN is replaced with the first token of the expansion, and we + return non-zero. */ static int enter_macro_context (pfile, token) cpp_reader *pfile; @@ -704,7 +705,7 @@ enter_macro_context (pfile, token) if (macro->disabled) { token->flags |= NO_EXPAND; - return 1; + return 0; } /* Save the position of the outermost macro invocation. */ @@ -718,7 +719,7 @@ enter_macro_context (pfile, token) { if (!pfile->context->prev) unlock_pools (pfile); - return 1; + return 0; } /* Now push its context. */ @@ -740,7 +741,7 @@ enter_macro_context (pfile, token) /* Disable the macro within its expansion. */ macro->disabled = 1; - return 0; + return 1; } /* Move to the next context. Create one if there is none. */ @@ -922,6 +923,7 @@ _cpp_get_token (pfile, token) cpp_reader *pfile; cpp_token *token; { + next_token: for (;;) { cpp_context *context = pfile->context; @@ -959,22 +961,34 @@ _cpp_get_token (pfile, token) if (token->flags & PASTE_LEFT) paste_all_tokens (pfile, token); - if (token->type != CPP_NAME - || token->val.node->type != NT_MACRO - || pfile->state.prevent_expansion - || token->flags & NO_EXPAND) + if (token->type != CPP_NAME) break; - /* Macros, built-in or not, invalidate controlling macros. */ - pfile->mi_state = MI_FAILED; - - if (token->val.node->flags & NODE_BUILTIN) + /* Handle macros and the _Pragma operator. */ + if (token->val.node->type == NT_MACRO + && !pfile->state.prevent_expansion + && !(token->flags & NO_EXPAND)) { - builtin_macro (pfile, token); - break; + /* Macros invalidate controlling macros. */ + pfile->mi_state = MI_FAILED; + + if (token->val.node->flags & NODE_BUILTIN) + { + builtin_macro (pfile, token); + break; + } + + if (enter_macro_context (pfile, token)) + continue; } - else if (enter_macro_context (pfile, token)) + + if (token->val.node != pfile->spec_nodes.n__Pragma) break; + + /* Invalidate controlling macros. */ + pfile->mi_state = MI_FAILED; + _cpp_do__Pragma (pfile); + goto next_token; } } -- 2.7.4