From: Neil Booth Date: Sun, 9 Jul 2000 09:19:44 +0000 (+0000) Subject: cpphash.h: ISvspace, is_vspace, is_nvspace: New. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=91fcd1584b47b95f35043b1ac1c4f8ca92a6e16f;p=gcc.git cpphash.h: ISvspace, is_vspace, is_nvspace: New. * cpphash.h: ISvspace, is_vspace, is_nvspace: New. IShspace, ISspace: Update. * cppinit.c: ISTABLE: Update. V: New. * cpplex.c (IS_HSPACE, S_NEWLINE): Remove. (IS_DIRECTIVE): Rename KNOWN_DIRECTIVE. (skip_block_comment, skip_line_comment, parse_string, lex_line): Use is_vspace rather than IS_NEWLINE. (skip_whitespace, lex_line): Clean up to use is_nvspace. (lex_line): Use KNOWN_DIRECTIVE. Any kind of directive gets a BOL flag. (lex_next): Unconditionally stop if within a directive. Treat directives within macro invocations as directives (after parse_args emits error), not as the argument. * testsuite/gcc.dg/cpp/directiv.c: New tests. * testsuite/gcc.dg/cpp/undef1.c: Update. From-SVN: r34933 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 75a21427217..db794f73679 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2000-07-09 Neil Booth + + * cpphash.h: ISvspace, is_vspace, is_nvspace: New. + IShspace, ISspace: Update. + + * cppinit.c: ISTABLE: Update. + V: New. + + * cpplex.c (IS_HSPACE, S_NEWLINE): Remove. + (IS_DIRECTIVE): Rename KNOWN_DIRECTIVE. + (skip_block_comment, skip_line_comment, parse_string, + lex_line): Use is_vspace rather than IS_NEWLINE. + (skip_whitespace, lex_line): Clean up to use is_nvspace. + (lex_line): Use KNOWN_DIRECTIVE. Any kind of directive + gets a BOL flag. + (lex_next): Unconditionally stop if within a directive. + Treat directives within macro invocations as directives + (after parse_args emits error), not as the argument. + 2000-07-09 Gabriel Dos Reis * diagnostic.c (diagnostic_args): New macro. diff --git a/gcc/cpphash.h b/gcc/cpphash.h index 22481639a67..5cfd5a335f0 100644 --- a/gcc/cpphash.h +++ b/gcc/cpphash.h @@ -141,12 +141,17 @@ struct spec_nodes /* Character classes. If the definition of `numchar' looks odd to you, please look up the - definition of a pp-number in the C standard [section 6.4.8 of C99] */ + definition of a pp-number in the C standard [section 6.4.8 of C99]. + + In the unlikely event that characters other than \r and \n enter + the set is_vspace, the macro handle_newline() in cpplex.c must be + updated. */ #define ISidnum 0x01 /* a-zA-Z0-9_ */ #define ISidstart 0x02 /* _a-zA-Z */ #define ISnumstart 0x04 /* 0-9 */ -#define IShspace 0x08 /* ' ' \t \f \v */ -#define ISspace 0x10 /* ' ' \t \f \v \n */ +#define IShspace 0x08 /* ' ' \t */ +#define ISvspace 0x10 /* \r \n */ +#define ISspace 0x20 /* ' ' \t \r \n \f \v \0 */ #define _dollar_ok(x) ((x) == '$' && CPP_OPTION (pfile, dollars_in_ident)) @@ -155,6 +160,8 @@ struct spec_nodes #define is_numchar(x) (_cpp_IStable[x] & ISidnum) #define is_numstart(x) (_cpp_IStable[x] & ISnumstart) #define is_hspace(x) (_cpp_IStable[x] & IShspace) +#define is_vspace(x) (_cpp_IStable[x] & ISvspace) +#define is_nvspace(x) ((_cpp_IStable[x] & (ISspace | ISvspace)) == ISspace) #define is_space(x) (_cpp_IStable[x] & ISspace) /* This table is constant if it can be initialized at compile time, diff --git a/gcc/cppinit.c b/gcc/cppinit.c index 0882634b90d..88a3e8ccaf8 100644 --- a/gcc/cppinit.c +++ b/gcc/cppinit.c @@ -138,6 +138,7 @@ enum { QUOTE = 0, BRACKET, SYSTEM, AFTER }; #define A(x) s(x, ISidnum|ISidstart) #define N(x) s(x, ISidnum|ISnumstart) #define H(x) s(x, IShspace|ISspace) +#define V(x) s(x, ISvspace|ISspace) #define S(x) s(x, ISspace) ISTABLE @@ -153,14 +154,17 @@ ISTABLE N('1') N('2') N('3') N('4') N('5') N('6') N('7') N('8') N('9') N('0') - H('\0') H(' ') H('\t') H('\v') H('\f') + H(' ') H('\t') - S('\n') + V('\n') V('\r') + + S('\0') S('\v') S('\f') END #undef A #undef N #undef H +#undef V #undef S #undef s #undef ISTABLE diff --git a/gcc/cpplex.c b/gcc/cpplex.c index 5b22627c461..951f633b2a4 100644 --- a/gcc/cpplex.c +++ b/gcc/cpplex.c @@ -24,22 +24,17 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ Cleanups to do:- -o Fix ISTABLE to flag the parts we want for IS_HSPACE and IS_NEWLINE. o Get use of digraphs in sync with the standard reqd on the command line. o -dM and with _cpp_dump_list: too many \n output. o Put a printer object in cpp_reader? o Check line numbers assigned to all errors. o Replace strncmp with memcmp almost everywhere. o lex_line's use of cur_token, flags and list->token_used is a bit opaque. -o Get rid of cpp_get_directive_token. o Convert do_ functions to return void. Kaveh thinks its OK; and said he'll give it a run when we've got some code. -o _cpp_parse_expr updated to new lexer. o Distinguish integers, floats, and 'other' pp-numbers. o Store ints and char constants as binary values. o New command-line assertion syntax. -o Merge hash table text pointer and token list text pointer for identifiers. -o Have _cpp_parse_expr use all the information the new lexer provides. o Work towards functions in cpperror.c taking a message level parameter. If we do this, merge the common code of do_warning and do_error. o Comment all functions, and describe macro expansion algorithm. @@ -122,10 +117,6 @@ static void process_directive PARAMS ((cpp_reader *, const cpp_token *)); ((prevc) == 'e' || (prevc) == 'E' \ || (((prevc) == 'p' || (prevc) == 'P') && !CPP_OPTION (pfile, c89)))) -/* Maybe put these in the ISTABLE eventually. */ -#define IS_HSPACE(c) ((c) == ' ' || (c) == '\t') -#define IS_NEWLINE(c) ((c) == '\n' || (c) == '\r') - /* Handle LF, CR, CR-LF and LF-CR style newlines. Assumes next character, if any, is in buffer. */ @@ -863,7 +854,7 @@ skip_block_comment (pfile) cpp_warning (pfile, "'/*' within comment"); } } - else if (IS_NEWLINE(c)) + else if (is_vspace (c)) { const unsigned char* bslash = backslash_start (pfile, cur - 2); @@ -897,7 +888,7 @@ skip_line_comment (pfile) { unsigned char c = *cur++; - if (IS_NEWLINE (c)) + if (is_vspace (c)) { /* Check for a (trigaph?) backslash escaping the newline. */ if (!backslash_start (pfile, cur - 2)) @@ -922,37 +913,38 @@ skip_whitespace (pfile, in_directive) int in_directive; { cpp_buffer *buffer = pfile->buffer; - register const unsigned char *cur = buffer->cur; - unsigned short null_count = 0; + unsigned short warned = 0; - for (; cur < buffer->rlimit; ) + /* We only want non-vertical space, i.e. ' ' \t \f \v \0. */ + while (buffer->cur < buffer->rlimit) { - unsigned char c = *cur++; + unsigned char c = *buffer->cur; - if (c == '\t') + if (!is_nvspace (c)) + break; + + buffer->cur++; + /* Horizontal space always OK. */ + if (c == ' ') + continue; + else if (c == '\t') + pfile->col_adjust += CPP_OPTION (pfile, tabstop) - 1 + - (CPP_BUF_COL (buffer) - 1) % CPP_OPTION(pfile, tabstop); + /* Must be \f \v or \0. */ + else if (c == '\0') { - unsigned int col = CPP_BUF_COLUMN (buffer, cur - 1); - pfile->col_adjust += (CPP_OPTION (pfile, tabstop) - 1 - - col % CPP_OPTION(pfile, tabstop)); + if (!warned) + cpp_warning_with_line (pfile, CPP_BUF_LINE (buffer), + CPP_BUF_COL (buffer), + "embedded null character ignored"); + warned = 1; } - if (IS_HSPACE(c)) /* FIXME: Fix ISTABLE. */ - continue; - if (!is_space(c) || IS_NEWLINE (c)) /* Main loop handles newlines. */ - goto out; - if (c == '\0') - null_count++; - /* Mut be '\f' or '\v' */ else if (in_directive && CPP_PEDANTIC (pfile)) - cpp_pedwarn (pfile, "%s in preprocessing directive", - c == '\f' ? "formfeed" : "vertical tab"); + cpp_pedwarn_with_line (pfile, CPP_BUF_LINE (buffer), + CPP_BUF_COL (buffer), + "%s in preprocessing directive", + c == '\f' ? "form feed" : "vertical tab"); } - cur++; - - out: - buffer->cur = cur - 1; - if (null_count) - cpp_warning (pfile, null_count > 1 ? "embedded null characters ignored" - : "embedded null character ignored"); } /* Parse (append) an identifier. */ @@ -1073,7 +1065,7 @@ parse_string (pfile, list, token, terminator) if (c == '\0') null_count++; - else if (c == terminator || IS_NEWLINE (c)) + else if (c == terminator || is_vspace (c)) { /* Needed for trigraph_replace and multiline string warning. */ buffer->cur = cur; @@ -1090,7 +1082,7 @@ parse_string (pfile, list, token, terminator) } namebuf--; /* Drop the newline / terminator from the name. */ - if (IS_NEWLINE (c)) + if (is_vspace (c)) { /* Drop a backslash newline, and continue. */ if (namebuf[-1] == '\\') @@ -1159,7 +1151,7 @@ parse_string (pfile, list, token, terminator) /* We may not have trigraph-replaced the input for this code path, but as the input is in error by being unterminated we don't bother. Prevent warnings about no newlines at EOF. */ - if (IS_NEWLINE(cur[-1])) + if (is_vspace (cur[-1])) cur--; unterminated: @@ -1240,7 +1232,7 @@ save_comment (list, token, from, len, type) * even when enabled. */ -#define IS_DIRECTIVE() (list->directive != 0) +#define KNOWN_DIRECTIVE() (list->directive != 0) #define MIGHT_BE_DIRECTIVE() \ (cur_token == &list->tokens[first_token + 1] && cur_token[-1].type == CPP_HASH) @@ -1273,21 +1265,22 @@ lex_line (pfile, list) { unsigned char c; - /* Optimize whitespace skipping, as most tokens are probably - separated by whitespace. (' ' '\t' '\v' '\f' '\0'). */ - c = *cur++; - if (is_hspace (c)) + /* Optimize non-vertical whitespace skipping; most tokens are + probably separated by whitespace. (' ' '\t' '\v' '\f' '\0'). */ + c = *cur; + if (is_nvspace (c)) { - /* Step back to get the null warning and tab correction. */ - buffer->cur = cur - 1; - skip_whitespace (pfile, IS_DIRECTIVE ()); + buffer->cur = cur; + skip_whitespace (pfile, (list->tokens[first_token].type == CPP_HASH + && cur_token > &list->tokens[first_token])); cur = buffer->cur; flags = PREV_WHITE; if (cur == buffer->rlimit) break; - c = *cur++; + c = *cur; } + cur++; /* Initialize current token. CPP_EOF will not be fixed up by expand_name_space. */ @@ -1428,7 +1421,7 @@ lex_line (pfile, list) /* Back-up to first '-' or '/'. */ cur_token--; if (!CPP_OPTION (pfile, discard_comments) - && (!IS_DIRECTIVE() + && (!KNOWN_DIRECTIVE() || (list->directive->flags & COMMENTS))) save_comment (list, cur_token++, cur, buffer->cur - cur, c); @@ -1466,7 +1459,7 @@ lex_line (pfile, list) /* Back up to opening '/'. */ cur_token--; if (!CPP_OPTION (pfile, discard_comments) - && (!IS_DIRECTIVE() + && (!KNOWN_DIRECTIVE() || (list->directive->flags & COMMENTS))) save_comment (list, cur_token++, cur, buffer->cur - cur, c); @@ -1647,7 +1640,7 @@ lex_line (pfile, list) break; } /* Is this the beginning of a header name? */ - if (IS_DIRECTIVE () && (list->directive->flags & INCL)) + if (KNOWN_DIRECTIVE () && (list->directive->flags & INCL)) { c = '>'; /* Terminator. */ cur_token->type = CPP_HEADER_NAME; @@ -1755,7 +1748,7 @@ lex_line (pfile, list) cur_token->flags = flags; if (cur_token == &list->tokens[first_token] && pfile->done_initializing) { - if (cur > buffer->buf && !IS_NEWLINE (cur[-1])) + if (cur > buffer->buf && !is_vspace (cur[-1])) cpp_pedwarn_with_line (pfile, CPP_BUF_LINE (buffer), CPP_BUF_COLUMN (buffer, cur), "no newline at end of file"); @@ -1780,16 +1773,16 @@ lex_line (pfile, list) cpp_error (pfile, "invalid preprocessing directive"); } - /* Put EOF at end of directives. This covers "directives do not - extend beyond the end of the line (description 6.10 part 2)". */ - if (IS_DIRECTIVE () || !pfile->done_initializing) + /* Put EOF at end of known directives. This covers "directives do + not extend beyond the end of the line (description 6.10 part 2)". */ + if (KNOWN_DIRECTIVE () || !pfile->done_initializing) { pfile->first_directive_token = first; cur_token++->type = CPP_EOF; } - if (first_token == 0 || IS_DIRECTIVE ()) - /* Set beginning of line flag. */ + /* Directives, known or not, always start a new line. */ + if (first_token == 0 || list->tokens[first_token].type == CPP_HASH) first->flags |= BOL; else /* 6.10.3.10: Within the sequence of preprocessing tokens making @@ -2968,6 +2961,16 @@ lex_next (pfile, clear) const cpp_token *old_list = list->tokens; unsigned int old_used = list->tokens_used; + /* If we are currently processing a directive, do not advance. 6.10 + paragraph 2: A new-line character ends the directive even if it + occurs within what would otherwise be an invocation of a + function-like macro. + + It is possible that clear == 1 too; e.g. "#if funlike_macro (" + since parse_args swallowed the directive's EOF. */ + if (list->directive) + return 1; + if (clear) { /* Release all temporary tokens. */ @@ -2976,15 +2979,6 @@ lex_next (pfile, clear) if (pfile->temp_used) release_temp_tokens (pfile); } - else - { - /* If we are currently processing a directive, do not advance. - (6.10 paragraph 2: A new-line character ends the directive - even if it occurs within what would otherwise be an - invocation of a function-like macro.) */ - if (list->directive) - return 1; - } lex_line (pfile, list); pfile->contexts[0].count = list->tokens_used; @@ -3021,11 +3015,7 @@ lex_next (pfile, clear) list->tokens[old_used].col, "#%s may not be used inside a macro argument", list->directive->name); - /* Don't treat as a directive: clear list->directive, - prune the final EOF from the list. */ - list->directive = 0; - list->tokens_used--; - pfile->contexts[0].count--; + return 1; } } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 08a68bbb016..63cac60285b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2000-07-09 Neil Booth + + * testsuite/gcc.dg/cpp/directiv.c: New tests. + * testsuite/gcc.dg/cpp/undef1.c: Update. + 2000-07-08 Angela Marie Thomas * lib/c-torture.exp: Make compiler_conditional_xfail_data global. diff --git a/gcc/testsuite/gcc.dg/cpp/directiv.c b/gcc/testsuite/gcc.dg/cpp/directiv.c new file mode 100644 index 00000000000..8c27d0f76a7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/directiv.c @@ -0,0 +1,47 @@ +/* Copyright (C) 2000 Free Software Foundation, Inc. */ + +/* { dg-do preprocess } */ +/* { dg-options -pedantic } */ + +/* Tests general directive syntax, and directive error recovery. */ + + +/* Test directive name is not expanded. */ +#define foo define +#foo EMPTY /* { dg-error "invalid" } */ + +/* Test # must be first on line. */ +EMPTY #define bar +#ifdef bar +#error bar is defined +#endif + +/* Test form feed and vertical tab warn pedantically, see 6.10 + paragraph 5. Tab is OK. */ +# define something /* { dg-warning "form feed" } */ +#define something_else /* { dg-warning "vertical tab" } */ + #define some thing /* Tab OK, as is form feed before #. */ + +/* Our friend the null directive OK? */ +# + +/* Check that directives always start a line, even if in middle of + macro expansion. */ +#define func(x) x +func (2 /* { dg-error "unterminated invocation" } */ +#define foobar /* { dg-error "may not be used inside" } */ + +/* For tidiness, I think the directive should still be processed + above. Certainly, continuing to try to find the closing ')' can + lead to some really confusing error messages. Hence this test. */ +#ifndef foobar +#error It is nice if the directive is processed! +#endif + +/* Check newlines end directives, even in function-like macro + invocations. 6.10 paragraph 1. + + Note that the #if is still treated as a conditional, so there + should be no errors about #endif without #if. */ +#if func ( /* { dg-error "unterminated invocation" } */ +#endif diff --git a/gcc/testsuite/gcc.dg/cpp/undef1.c b/gcc/testsuite/gcc.dg/cpp/undef1.c index 024efcede65..995d679b0ec 100644 --- a/gcc/testsuite/gcc.dg/cpp/undef1.c +++ b/gcc/testsuite/gcc.dg/cpp/undef1.c @@ -9,6 +9,6 @@ #define foo(bar) bar -foo( blah +foo( blah /* { dg-error "unterminated invocation" } */ #undef foo /* { dg-error "may not be used inside" "foo(#undef foo)" } */ blah )