summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorZack Weinberg <zack@wolery.cumb.org>2000-05-29 16:19:32 +0000
committerZack Weinberg <zack@gcc.gnu.org>2000-05-29 16:19:32 +0000
commitea4a453b8909eb0f3612bbf98fe2e6a2a8ee4114 (patch)
tree05d62231cd71e2302cbbf76f31135f52a6e77ba9 /gcc
parent1b50716d21794f2f69aa2939045fbf1489ff3c19 (diff)
downloadgcc-ea4a453b8909eb0f3612bbf98fe2e6a2a8ee4114.tar.gz
cpplib.h (cpp_reader): Remove if_stack.
* cpplib.h (cpp_reader): Remove if_stack. Change potential_control_macro to a cpp_hashnode *. Add skipping flag. * cpphash.h (struct ihash): Change control_macro to a cpp_hashnode * and shorten name to cmacro. Add NEVER_REINCLUDE constant. * cppfiles.c (redundant_include_p): Drop cpp_reader argument. Examine the cmacro node directly, no need to call cpp_defined. (_cpp_execute_include, read_include_file): Set cmacro to NEVER_REINCLUDE, not U"". * cpplex.c (cpp_push_buffer): Don't set new->if_stack. (cpp_get_token): If pfile->skipping is true, discard text and keep scanning until we hit a directive; don't expand macros. * cpplib.c (struct if_stack): Remove if_succeeded, add was_skipping. Change control_macro to a cpp_hashnode * and shorten name to cmacro. Remove typedef IF_STACK. (parse_ifdef), detect_if_not_defined): Return a cpp_hashnode *. (conditional_skip, skip_if_group, consider_directive_while_skipping): Delete. (push_conditional): New. (_cpp_handle_directive): Don't process directives other than conditionals if we are skipping. (do_ifdef, do_ifndef, do_if, do_else, do_elif, do_endif): Update to new scheme. (validate_else): Skip rest of line here, unconditionally. (_cpp_unwind_if_stack): The stack is per-buffer. Force pfile->skipping off. (all): Remove `scare quotes' from error messages. * gcc.dg/cpp-mi.c: Add another case, cpp-mix.h, where the guard macro is already defined when the header is first included. * gcc.dg/cpp-mix.h: New file. * gcc.dg/endif-label.c: Update patterns to match compiler. * g++.brendan/complex1.C: Declare abort. * g++.law/refs4.C: Remove XFAIL. * g++.oliva/expr2.C: Declare abort and exit. From-SVN: r34253
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog34
-rw-r--r--gcc/cppfiles.c32
-rw-r--r--gcc/cpphash.h3
-rw-r--r--gcc/cpplex.c49
-rw-r--r--gcc/cpplib.c501
-rw-r--r--gcc/cpplib.h6
-rw-r--r--gcc/testsuite/ChangeLog12
-rw-r--r--gcc/testsuite/g++.old-deja/g++.brendan/complex1.C1
-rw-r--r--gcc/testsuite/g++.old-deja/g++.law/refs4.C2
-rw-r--r--gcc/testsuite/g++.old-deja/g++.oliva/expr2.C3
-rw-r--r--gcc/testsuite/gcc.dg/cpp-mi.c6
-rw-r--r--gcc/testsuite/gcc.dg/cpp-mix.h9
-rw-r--r--gcc/testsuite/gcc.dg/endif-label.c4
13 files changed, 293 insertions, 369 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f425de924e2..6534ad18c18 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,37 @@
+2000-05-29 Zack Weinberg <zack@wolery.cumb.org>
+
+ * cpplib.h (cpp_reader): Remove if_stack. Change
+ potential_control_macro to a cpp_hashnode *. Add skipping flag.
+ * cpphash.h (struct ihash): Change control_macro to a
+ cpp_hashnode * and shorten name to cmacro.
+ Add NEVER_REINCLUDE constant.
+
+ * cppfiles.c (redundant_include_p): Drop cpp_reader argument.
+ Examine the cmacro node directly, no need to call cpp_defined.
+ (_cpp_execute_include, read_include_file): Set cmacro to
+ NEVER_REINCLUDE, not U"".
+ * cpplex.c (cpp_push_buffer): Don't set new->if_stack.
+ (cpp_get_token): If pfile->skipping is true, discard text and
+ keep scanning until we hit a directive; don't expand macros.
+
+ * cpplib.c (struct if_stack): Remove if_succeeded, add
+ was_skipping. Change control_macro to a cpp_hashnode * and
+ shorten name to cmacro. Remove typedef IF_STACK.
+ (parse_ifdef), detect_if_not_defined): Return a cpp_hashnode *.
+ (conditional_skip, skip_if_group,
+ consider_directive_while_skipping): Delete.
+ (push_conditional): New.
+ (_cpp_handle_directive): Don't process directives other than
+ conditionals if we are skipping.
+
+ (do_ifdef, do_ifndef, do_if, do_else, do_elif, do_endif):
+ Update to new scheme.
+ (validate_else): Skip rest of line here, unconditionally.
+ (_cpp_unwind_if_stack): The stack is per-buffer. Force
+ pfile->skipping off.
+
+ (all): Remove `scare quotes' from error messages.
+
2000-05-29 Richard Henderson <rth@cygnus.com>
* function.c (emit_return_into_block): New line_note arg; emit it.
diff --git a/gcc/cppfiles.c b/gcc/cppfiles.c
index 29559020396..676c9d56c4a 100644
--- a/gcc/cppfiles.c
+++ b/gcc/cppfiles.c
@@ -39,8 +39,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
# define MMAP_THRESHOLD 0
#endif
-static IHASH *redundant_include_p PARAMS ((cpp_reader *, IHASH *,
- struct file_name_list *));
+static IHASH *redundant_include_p PARAMS ((IHASH *, struct file_name_list *));
static IHASH *make_IHASH PARAMS ((const char *, const char *,
struct file_name_list *,
unsigned int, IHASH **));
@@ -124,8 +123,7 @@ _cpp_init_include_hash (pfile)
the directories are in fact the same. */
static IHASH *
-redundant_include_p (pfile, ihash, ilist)
- cpp_reader *pfile;
+redundant_include_p (ihash, ilist)
IHASH *ihash;
struct file_name_list *ilist;
{
@@ -138,14 +136,14 @@ redundant_include_p (pfile, ihash, ilist)
for (i = ihash; i; i = i->next_this_file)
for (l = ilist; l; l = l->next)
if (i->foundhere == l)
- /* The control_macro works like this: If it's NULL, the file
- is to be included again. If it's "", the file is never to
- be included again. If it's a string, the file is not to be
- included again if the string is the name of a defined macro. */
- return (i->control_macro
- && (i->control_macro[0] == '\0'
- || cpp_defined (pfile, i->control_macro,
- ustrlen (i->control_macro))))
+ /* The cmacro works like this: If it's NULL, the file is to
+ be included again. If it's NEVER_REINCLUDE, the file is
+ never to be included again. Otherwise it is a macro
+ hashnode, and the file is to be included again if the
+ macro is not defined. */
+ return (i->cmacro
+ && (i->cmacro == NEVER_REINCLUDE
+ || i->cmacro->type != T_VOID))
? (IHASH *)-1 : i;
return 0;
@@ -199,7 +197,7 @@ make_IHASH (name, fname, path, hash, slot)
}
strcpy ((char *)ih->name, name);
ih->foundhere = path;
- ih->control_macro = NULL;
+ ih->cmacro = NULL;
ih->hash = hash;
ih->next_this_file = *slot;
*slot = ih;
@@ -256,7 +254,7 @@ find_include_file (pfile, fname, search_start, ihash, before)
(const void *) &dummy,
dummy.hash, INSERT);
- if (*slot && (ih = redundant_include_p (pfile, *slot, path)))
+ if (*slot && (ih = redundant_include_p (*slot, path)))
{
if (ih == (IHASH *)-1)
return -2;
@@ -629,7 +627,7 @@ _cpp_execute_include (pfile, f, len, no_reinclude, search_start)
/* Actually process the file. */
if (no_reinclude)
- ihash->control_macro = U"";
+ ihash->cmacro = NEVER_REINCLUDE;
if (read_include_file (pfile, fd, ihash))
{
@@ -662,7 +660,7 @@ cpp_read_file (pfile, fname)
slot = (IHASH **) htab_find_slot_with_hash (pfile->all_include_files,
(const void *) &dummy,
dummy.hash, INSERT);
- if (*slot && (ih = redundant_include_p (pfile, *slot, ABSOLUTE_PATH)))
+ if (*slot && (ih = redundant_include_p (*slot, ABSOLUTE_PATH)))
{
if (ih == (IHASH *) -1)
return 1; /* Already included. */
@@ -759,7 +757,7 @@ read_include_file (pfile, fd, ihash)
fp->nominal_fname = ihash->name;
if (length == 0)
- ihash->control_macro = U""; /* never re-include */
+ ihash->cmacro = NEVER_REINCLUDE;
else
/* Temporary - I hope. */
length = _cpp_prescan (pfile, fp, length);
diff --git a/gcc/cpphash.h b/gcc/cpphash.h
index c590de68636..28761c71225 100644
--- a/gcc/cpphash.h
+++ b/gcc/cpphash.h
@@ -69,10 +69,11 @@ struct ihash
unsigned int hash; /* save hash value for future reference */
const char *nshort; /* name of file as referenced in #include;
points into name[] */
- const U_CHAR *control_macro; /* macro, if any, preventing reinclusion. */
+ const cpp_hashnode *cmacro; /* macro, if any, preventing reinclusion. */
const char name[1]; /* (partial) pathname of file */
};
typedef struct ihash IHASH;
+#define NEVER_REINCLUDE ((const cpp_hashnode *)-1)
/* Character classes.
If the definition of `numchar' looks odd to you, please look up the
diff --git a/gcc/cpplex.c b/gcc/cpplex.c
index 4708382d158..b35f2989786 100644
--- a/gcc/cpplex.c
+++ b/gcc/cpplex.c
@@ -193,7 +193,6 @@ cpp_push_buffer (pfile, buffer, length)
new = (cpp_buffer *) xcalloc (1, sizeof (cpp_buffer));
- new->if_stack = pfile->if_stack;
new->buf = new->cur = buffer;
new->rlimit = buffer + length;
new->prev = buf;
@@ -221,7 +220,7 @@ cpp_pop_buffer (pfile)
pfile->system_include_depth--;
if (pfile->potential_control_macro)
{
- buf->ihash->control_macro = pfile->potential_control_macro;
+ buf->ihash->cmacro = pfile->potential_control_macro;
pfile->potential_control_macro = 0;
}
pfile->input_stack_listing_current = 0;
@@ -1743,6 +1742,7 @@ cpp_get_token (pfile)
{
enum cpp_ttype token;
long written = CPP_WRITTEN (pfile);
+ int macro_buffer;
get_next:
token = _cpp_lex_token (pfile);
@@ -1750,24 +1750,26 @@ cpp_get_token (pfile)
switch (token)
{
default:
+ if (pfile->skipping)
+ break;
pfile->potential_control_macro = 0;
pfile->only_seen_white = 0;
- return token;
+ break;
+
+ case CPP_HSPACE:
+ case CPP_COMMENT:
+ break;
case CPP_VSPACE:
if (pfile->only_seen_white == 0)
pfile->only_seen_white = 1;
CPP_BUMP_LINE (pfile);
- return token;
-
- case CPP_HSPACE:
- case CPP_COMMENT:
- return token;
+ break;
case CPP_HASH:
pfile->potential_control_macro = 0;
if (!pfile->only_seen_white)
- return CPP_HASH;
+ break;
/* XXX shouldn't have to do this - remove the hash or %: from
the token buffer. */
if (CPP_PWRITTEN (pfile)[-1] == '#')
@@ -1776,30 +1778,43 @@ cpp_get_token (pfile)
CPP_ADJUST_WRITTEN (pfile, -2);
if (_cpp_handle_directive (pfile))
- return CPP_DIRECTIVE;
+ {
+ token = CPP_DIRECTIVE;
+ break;
+ }
pfile->only_seen_white = 0;
CPP_PUTC (pfile, '#');
- return CPP_HASH;
+ break;
case CPP_MACRO:
+ if (pfile->skipping)
+ break;
pfile->potential_control_macro = 0;
pfile->only_seen_white = 0;
if (! pfile->no_macro_expand
&& maybe_macroexpand (pfile, written))
goto get_next;
- return CPP_NAME;
+ token = CPP_NAME;
+ break;
+ /* Do not run this case through the 'skipping' logic. */
case CPP_EOF:
if (CPP_BUFFER (pfile) == NULL)
return CPP_EOF;
- if (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
- {
- cpp_pop_buffer (pfile);
- goto get_next;
- }
+ macro_buffer = CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile));
+
cpp_pop_buffer (pfile);
+ if (macro_buffer)
+ goto get_next;
return CPP_EOF;
}
+
+ if (pfile->skipping)
+ {
+ CPP_SET_WRITTEN (pfile, written);
+ goto get_next;
+ }
+ return token;
}
/* Like cpp_get_token, but skip spaces and comments. */
diff --git a/gcc/cpplib.c b/gcc/cpplib.c
index 6cc99ec7eaa..3bc882562e7 100644
--- a/gcc/cpplib.c
+++ b/gcc/cpplib.c
@@ -44,26 +44,22 @@ struct if_stack
{
struct if_stack *next;
int lineno; /* line number where condition started */
- int if_succeeded; /* truth of last condition in this group */
- const U_CHAR *control_macro; /* macro name for #ifndef around entire file */
+ int was_skipping; /* value of pfile->skipping before this if */
+ const cpp_hashnode *cmacro; /* macro name for #ifndef around entire file */
int type; /* type of last directive seen in this group */
};
-typedef struct if_stack IF_STACK;
/* Forward declarations. */
static void validate_else PARAMS ((cpp_reader *, const U_CHAR *));
-static int parse_ifdef PARAMS ((cpp_reader *, const U_CHAR *));
static unsigned int parse_include PARAMS ((cpp_reader *, const U_CHAR *));
-static int conditional_skip PARAMS ((cpp_reader *, int, int,
- U_CHAR *));
-static int skip_if_group PARAMS ((cpp_reader *));
+static void push_conditional PARAMS ((cpp_reader *, int, int,
+ const cpp_hashnode *));
static void pass_thru_directive PARAMS ((const U_CHAR *, size_t,
cpp_reader *, int));
static int read_line_number PARAMS ((cpp_reader *, int *));
-static U_CHAR *detect_if_not_defined PARAMS ((cpp_reader *));
-static int consider_directive_while_skipping
- PARAMS ((cpp_reader *, IF_STACK *));
+static const cpp_hashnode *parse_ifdef PARAMS ((cpp_reader *, const U_CHAR *));
+static const cpp_hashnode *detect_if_not_defined PARAMS ((cpp_reader *));
/* Values for the flags field of the table below. KANDR and COND
directives come from traditional (K&R) C. The difference is, if we
@@ -208,12 +204,13 @@ _cpp_handle_directive (pfile)
CPP_GOTO_MARK (pfile);
/* # followed by a number is equivalent to #line. Do not recognize
- this form in assembly language source files. Complain about this
- form if we're being pedantic, but not if this is regurgitated
- input (preprocessed or fed back in by the C++ frontend). */
+ this form in assembly language source files or skipped
+ conditional groups. Complain about this form if we're being
+ pedantic, but not if this is regurgitated input (preprocessed or
+ fed back in by the C++ frontend). */
if (tok == CPP_NUMBER)
{
- if (CPP_OPTION (pfile, lang_asm))
+ if (pfile->skipping || CPP_OPTION (pfile, lang_asm))
return 0;
if (CPP_PEDANTIC (pfile)
@@ -244,8 +241,9 @@ _cpp_handle_directive (pfile)
}
/* Don't complain about invalid directives in assembly source,
we don't know where the comments are, and # may introduce
- assembler pseudo-ops. */
- if (!CPP_OPTION (pfile, lang_asm))
+ assembler pseudo-ops. Don't complain about invalid directives
+ in skipped conditional groups (6.10 p4). */
+ if (!pfile->skipping && !CPP_OPTION (pfile, lang_asm))
cpp_error (pfile, "invalid preprocessing directive #%s", ident);
return 0;
}
@@ -255,6 +253,11 @@ _cpp_handle_directive (pfile)
real_directive:
+ /* If we are skipping a failed conditional group, all non-conditional
+ directives are ignored. */
+ if (pfile->skipping && ORIGIN (dtable[i].flags) != COND)
+ return 0;
+
/* In -traditional mode, a directive is ignored unless its # is in
column 1. */
if (CPP_TRADITIONAL (pfile) && !hash_at_bol)
@@ -302,11 +305,7 @@ _cpp_handle_directive (pfile)
CPP_SET_WRITTEN (pfile, old_written);
process_directive:
- /* Some directives (e.g. #if) may return a request to execute
- another directive handler immediately. No directive ever
- requests that #define be executed immediately, so it is safe for
- the loop to terminate when some function returns 0 (== T_DEFINE). */
- while ((i = dtable[i].func (pfile)));
+ (void) (*dtable[i].func) (pfile);
return 1;
}
@@ -434,7 +433,7 @@ parse_include (pfile, name)
#endif
else
{
- cpp_error (pfile, "`#%s' expects \"FILENAME\" or <FILENAME>", name);
+ cpp_error (pfile, "#%s expects \"FILENAME\" or <FILENAME>", name);
CPP_SET_WRITTEN (pfile, old_written);
_cpp_skip_rest_of_line (pfile);
return 0;
@@ -442,14 +441,14 @@ parse_include (pfile, name)
if (_cpp_get_directive_token (pfile) != CPP_VSPACE)
{
- cpp_error (pfile, "junk at end of `#%s'", name);
+ cpp_error (pfile, "junk at end of #%s", name);
_cpp_skip_rest_of_line (pfile);
}
CPP_SET_WRITTEN (pfile, old_written);
if (len == 0)
- cpp_error (pfile, "empty file name in `#%s'", name);
+ cpp_error (pfile, "empty file name in #%s", name);
return len;
}
@@ -563,7 +562,7 @@ read_line_number (pfile, num)
else
{
if (token != CPP_VSPACE && token != CPP_EOF)
- cpp_error (pfile, "invalid format `#line' command");
+ cpp_error (pfile, "invalid format #line");
CPP_SET_WRITTEN (pfile, save_written);
return 0;
}
@@ -587,7 +586,7 @@ do_line (pfile)
if (token != CPP_NUMBER)
{
- cpp_error (pfile, "token after `#line' is not an integer");
+ cpp_error (pfile, "token after #line is not an integer");
goto bad_line_directive;
}
@@ -596,13 +595,13 @@ do_line (pfile)
&x, 10);
if (x[0] != '\0')
{
- cpp_error (pfile, "token after `#line' is not an integer");
+ cpp_error (pfile, "token after #line is not an integer");
goto bad_line_directive;
}
CPP_SET_WRITTEN (pfile, old_written);
if (CPP_PEDANTIC (pfile) && (new_lineno <= 0 || new_lineno > 32767))
- cpp_pedwarn (pfile, "line number out of range in `#line' command");
+ cpp_pedwarn (pfile, "line number out of range in #line");
token = _cpp_get_directive_token (pfile);
@@ -615,7 +614,7 @@ do_line (pfile)
if (read_line_number (pfile, &action_number))
{
if (CPP_PEDANTIC (pfile))
- cpp_pedwarn (pfile, "garbage at end of `#line' command");
+ cpp_pedwarn (pfile, "garbage at end of #line");
/* This is somewhat questionable: change the buffer stack
depth so that output_line_command thinks we've stacked
@@ -656,7 +655,7 @@ do_line (pfile)
}
else if (token != CPP_VSPACE && token != CPP_EOF)
{
- cpp_error (pfile, "token after `#line %d' is not a string", new_lineno);
+ cpp_error (pfile, "second token after #line is not a string");
goto bad_line_directive;
}
@@ -889,12 +888,12 @@ do_pragma_once (pfile)
/* Allow #pragma once in system headers, since that's not the user's
fault. */
if (!ip->system_header_p)
- cpp_warning (pfile, "`#pragma once' is obsolete");
+ cpp_warning (pfile, "#pragma once is obsolete");
if (CPP_PREV_BUFFER (ip) == NULL)
- cpp_warning (pfile, "`#pragma once' outside include file");
+ cpp_warning (pfile, "#pragma once outside include file");
else
- ip->ihash->control_macro = U""; /* never repeat */
+ ip->ihash->cmacro = NEVER_REINCLUDE;
return 1;
}
@@ -929,7 +928,7 @@ do_pragma_implementation (pfile)
if (cpp_included (pfile, copy))
cpp_warning (pfile,
- "`#pragma implementation' for `%s' appears after file is included",
+ "#pragma implementation for %s appears after file is included",
copy);
return 0;
}
@@ -1018,21 +1017,21 @@ do_sccs (pfile)
this file is white space, and if it is of the form
`#if ! defined SYMBOL', then SYMBOL is a possible controlling macro
for inclusion of this file. (See redundant_include_p in cppfiles.c
- for an explanation of controlling macros.) If so, return a
- malloced copy of SYMBOL. Otherwise, return NULL. */
+ for an explanation of controlling macros.) If so, return the
+ hash node for SYMBOL. Otherwise, return NULL. */
-static U_CHAR *
+static const cpp_hashnode *
detect_if_not_defined (pfile)
cpp_reader *pfile;
{
- U_CHAR *control_macro = 0;
+ const cpp_hashnode *cmacro = 0;
enum cpp_ttype token;
unsigned int base_offset;
unsigned int token_offset;
unsigned int need_rparen = 0;
unsigned int token_len;
- if (pfile->only_seen_white != 2)
+ if (pfile->skipping || pfile->only_seen_white != 2)
return NULL;
/* Save state required for restore. */
@@ -1077,82 +1076,21 @@ detect_if_not_defined (pfile)
goto restore;
/* We have a legitimate controlling macro for this header. */
- control_macro = (U_CHAR *) xmalloc (token_len + 1);
- memcpy (control_macro, pfile->token_buffer + token_offset, token_len);
- control_macro[token_len] = '\0';
+ cmacro = cpp_lookup (pfile, pfile->token_buffer + token_offset, token_len);
restore:
CPP_SET_WRITTEN (pfile, base_offset);
pfile->no_macro_expand--;
CPP_GOTO_MARK (pfile);
- return control_macro;
-}
-
-/*
- * #if is straightforward; just call _cpp_parse_expr, then conditional_skip.
- * Also, check for a reinclude preventer of the form #if !defined (MACRO).
- */
-
-static int
-do_if (pfile)
- cpp_reader *pfile;
-{
- U_CHAR *control_macro;
- int value;
- int save_only_seen_white = pfile->only_seen_white;
-
- control_macro = detect_if_not_defined (pfile);
-
- pfile->only_seen_white = 0;
- value = _cpp_parse_expr (pfile);
- pfile->only_seen_white = save_only_seen_white;
-
- return conditional_skip (pfile, value == 0, T_IF, control_macro);
-}
-
-/*
- * handle a #elif directive by not changing if_stack either.
- * see the comment above do_else.
- */
-
-static int
-do_elif (pfile)
- cpp_reader *pfile;
-{
- if (pfile->if_stack == CPP_BUFFER (pfile)->if_stack)
- {
- cpp_error (pfile, "`#elif' not within a conditional");
- return 0;
- }
- else
- {
- if (pfile->if_stack->type == T_ELSE)
- {
- cpp_error (pfile, "`#elif' after `#else'");
- cpp_error_with_line (pfile, pfile->if_stack->lineno, 0,
- "the conditional began here");
- }
- pfile->if_stack->type = T_ELIF;
- }
-
- if (pfile->if_stack->if_succeeded)
- {
- _cpp_skip_rest_of_line (pfile);
- return skip_if_group (pfile);
- }
- if (_cpp_parse_expr (pfile) == 0)
- return skip_if_group (pfile);
-
- ++pfile->if_stack->if_succeeded; /* continue processing input */
- return 0;
+ return cmacro;
}
/* Parse an #ifdef or #ifndef directive. Returns 1 for defined, 0 for
not defined; the macro tested is left in the token buffer (but
popped). */
-static int
+static const cpp_hashnode *
parse_ifdef (pfile, name)
cpp_reader *pfile;
const U_CHAR *name;
@@ -1161,7 +1099,7 @@ parse_ifdef (pfile, name)
unsigned int len;
enum cpp_ttype token;
long old_written = CPP_WRITTEN (pfile);
- int defined;
+ const cpp_hashnode *node = 0;
pfile->no_macro_expand++;
token = _cpp_get_directive_token (pfile);
@@ -1173,20 +1111,17 @@ parse_ifdef (pfile, name)
if (token == CPP_VSPACE)
{
if (! CPP_TRADITIONAL (pfile))
- cpp_pedwarn (pfile, "`#%s' with no argument", name);
- defined = 0;
+ cpp_pedwarn (pfile, "#%s with no argument", name);
goto done;
}
else if (token == CPP_NAME)
{
- defined = cpp_defined (pfile, ident, len);
- CPP_PUTC (pfile, '\0'); /* so it can be copied with xstrdup */
+ node = cpp_lookup (pfile, ident, len);
}
else
{
- defined = 0;
if (! CPP_TRADITIONAL (pfile))
- cpp_error (pfile, "`#%s' with invalid argument", name);
+ cpp_error (pfile, "#%s with invalid argument", name);
}
if (!CPP_TRADITIONAL (pfile))
@@ -1194,13 +1129,13 @@ parse_ifdef (pfile, name)
if (_cpp_get_directive_token (pfile) == CPP_VSPACE)
goto done;
- cpp_pedwarn (pfile, "garbage at end of `#%s' argument", name);
+ cpp_pedwarn (pfile, "garbage at end of #%s", name);
}
_cpp_skip_rest_of_line (pfile);
done:
CPP_SET_WRITTEN (pfile, old_written); /* Pop */
- return defined;
+ return node;
}
/* #ifdef is dead simple. */
@@ -1209,8 +1144,14 @@ static int
do_ifdef (pfile)
cpp_reader *pfile;
{
- int skip = ! parse_ifdef (pfile, dtable[T_IFDEF].name);
- return conditional_skip (pfile, skip, T_IFDEF, 0);
+ int def = 0;
+ const cpp_hashnode *node = parse_ifdef (pfile, dtable[T_IFDEF].name);
+ if (node->type == T_POISON)
+ cpp_error (pfile, "attempt to use poisoned `%s'", node->name);
+ else
+ def = (node->type != T_VOID);
+ push_conditional (pfile, !def, T_IFDEF, 0);
+ return 0;
}
/* #ifndef is a tad more complex, because we need to check for a
@@ -1220,283 +1161,191 @@ static int
do_ifndef (pfile)
cpp_reader *pfile;
{
- int start_of_file, skip;
- U_CHAR *control_macro = 0;
+ int start_of_file;
+ int def = 0;
+ const cpp_hashnode *cmacro;
start_of_file = pfile->only_seen_white == 2;
- skip = parse_ifdef (pfile, dtable[T_IFNDEF].name);
-
- if (start_of_file && !skip)
- control_macro = uxstrdup (CPP_PWRITTEN (pfile));
+ cmacro = parse_ifdef (pfile, dtable[T_IFNDEF].name);
+ if (cmacro->type == T_POISON)
+ cpp_error (pfile, "attempt to use poisoned `%s'", cmacro->name);
+ else
+ def = (cmacro->type != T_VOID);
- return conditional_skip (pfile, skip, T_IFNDEF, control_macro);
+ push_conditional (pfile, def, T_IFNDEF,
+ start_of_file ? cmacro : 0);
+ return 0;
}
-/* Push TYPE on stack; then, if SKIP is nonzero, skip ahead.
- If this is a #ifndef starting at the beginning of a file,
- CONTROL_MACRO is the macro name tested by the #ifndef.
- Otherwise, CONTROL_MACRO is 0. */
+/* #if is straightforward; just call _cpp_parse_expr, then conditional_skip.
+ Also, check for a reinclude preventer of the form #if !defined (MACRO). */
static int
-conditional_skip (pfile, skip, type, control_macro)
+do_if (pfile)
cpp_reader *pfile;
- int skip;
- int type;
- U_CHAR *control_macro;
{
- IF_STACK *temp;
-
- temp = (IF_STACK *) xcalloc (1, sizeof (IF_STACK));
- temp->lineno = CPP_BUFFER (pfile)->lineno;
- temp->next = pfile->if_stack;
- temp->control_macro = control_macro;
- pfile->if_stack = temp;
-
- pfile->if_stack->type = type;
+ const cpp_hashnode *cmacro = 0;
+ int value = 0;
+ int save_only_seen_white = pfile->only_seen_white;
- if (skip != 0)
- return skip_if_group (pfile);
+ if (! pfile->skipping)
+ {
+ cmacro = detect_if_not_defined (pfile);
- ++pfile->if_stack->if_succeeded;
+ pfile->only_seen_white = 0;
+ value = _cpp_parse_expr (pfile);
+ pfile->only_seen_white = save_only_seen_white;
+ }
+ push_conditional (pfile, value == 0, T_IF, cmacro);
return 0;
}
-/* Subroutine of skip_if_group. Examine one preprocessing directive
- and return 0 if skipping should continue, or the directive number
- of the directive that ends the block if it should halt.
-
- Also adjusts the if_stack as appropriate. The `#' has been read,
- but not the identifier. */
+/* #else flips pfile->skipping and continues without changing
+ if_stack; this is so that the error message for missing #endif's
+ etc. will point to the original #if. */
static int
-consider_directive_while_skipping (pfile, stack)
- cpp_reader *pfile;
- IF_STACK *stack;
+do_else (pfile)
+ cpp_reader *pfile;
{
- long ident;
- int i, hash_at_bol;
- unsigned int len;
- IF_STACK *temp;
-
- /* -traditional directives are recognized only with the # in column 1. */
- hash_at_bol = CPP_IN_COLUMN_1 (pfile);
-
- ident = CPP_WRITTEN (pfile);
- if (_cpp_get_directive_token (pfile) != CPP_NAME)
- return 0;
- len = CPP_WRITTEN (pfile) - ident;
+ struct if_stack *ifs = CPP_BUFFER (pfile)->if_stack;
- for (i = 0; i < N_DIRECTIVES; i++)
- {
- if (dtable[i].length == len
- && !ustrncmp (dtable[i].name, pfile->token_buffer + ident, len))
- goto real_directive;
- }
- return 0;
-
- real_directive:
-
- /* If it's not a directive of interest to us, return now. */
- if (ORIGIN (dtable[i].flags) != COND)
- return 0;
-
- /* First, deal with -traditional and -Wtraditional.
- All COND directives are from K+R. */
+ validate_else (pfile, dtable[T_ELSE].name);
- if (! hash_at_bol)
+ if (ifs == NULL)
{
- if (CPP_TRADITIONAL (pfile))
- {
- if (CPP_WTRADITIONAL (pfile))
- cpp_warning (pfile, "ignoring #%s because of its indented #",
- dtable[i].name);
- return 0;
- }
- if (CPP_WTRADITIONAL (pfile))
- cpp_warning (pfile, "traditional C ignores %s with the # indented",
- dtable[i].name);
+ cpp_error (pfile, "#else without #if");
+ return 0;
}
-
- switch (i)
+ if (ifs->type == T_ELSE)
{
- default:
- cpp_ice (pfile, "non COND directive in switch in c_d_w_s");
- return 0;
-
- case T_IF:
- case T_IFDEF:
- case T_IFNDEF:
- temp = (IF_STACK *) xcalloc (1, sizeof (IF_STACK));
- temp->lineno = CPP_BUFFER (pfile)->lineno;
- temp->next = pfile->if_stack;
- temp->type = i;
- pfile->if_stack = temp;
- return 0;
-
- case T_ELSE:
- if (pfile->if_stack != stack)
- validate_else (pfile, dtable[i].name);
- /* fall through */
- case T_ELIF:
- if (pfile->if_stack == stack)
- return i;
-
- pfile->if_stack->type = i;
- return 0;
-
- case T_ENDIF:
- if (pfile->if_stack != stack)
- validate_else (pfile, dtable[i].name);
-
- if (pfile->if_stack == stack)
- return i;
-
- temp = pfile->if_stack;
- pfile->if_stack = temp->next;
- free (temp);
- return 0;
+ cpp_error (pfile, "#else after #else");
+ cpp_error_with_line (pfile, ifs->lineno, 1, "the conditional began here");
}
-}
-
-/* Skip to #endif, #else, or #elif. Consumes the directive that
- causes it to stop, but not its argument. Returns the number of
- that directive, which must be passed back up to
- _cpp_handle_directive, which will execute it. */
-static int
-skip_if_group (pfile)
- cpp_reader *pfile;
-{
- enum cpp_ttype token;
- IF_STACK *save_if_stack = pfile->if_stack; /* don't pop past here */
- long old_written;
- int ret = 0;
- /* We are no longer at the start of the file. */
- pfile->only_seen_white = 0;
+ /* #ifndef can't have its special treatment for containing the whole file
+ if it has a #else clause. */
+ ifs->cmacro = 0;
- old_written = CPP_WRITTEN (pfile);
- pfile->no_macro_expand++;
- for (;;)
+ ifs->type = T_ELSE;
+ if (! ifs->was_skipping)
{
- /* We are at the end of a line.
- XXX Serious layering violation here. */
- int c = CPP_BUF_PEEK (CPP_BUFFER (pfile));
- if (c == EOF)
- break; /* Caller will issue error. */
- else if (c != '\n')
- cpp_ice (pfile, "character %c at end of line in skip_if_group", c);
- CPP_BUFFER (pfile)->cur++;
- CPP_BUMP_LINE (pfile);
- CPP_SET_WRITTEN (pfile, old_written);
- pfile->only_seen_white = 1;
-
- token = _cpp_get_directive_token (pfile);
-
- if (token == CPP_HASH)
- {
- ret = consider_directive_while_skipping (pfile, save_if_stack);
- if (ret)
- break;
- }
-
- if (token != CPP_VSPACE)
- _cpp_skip_rest_of_line (pfile);
+ /* If pfile->skipping is 2, one of the blocks in an #if/#elif/... chain
+ succeeded, so we mustn't do the else block. */
+ if (pfile->skipping < 2)
+ pfile->skipping = ! pfile->skipping;
}
- CPP_SET_WRITTEN (pfile, old_written);
- pfile->no_macro_expand--;
- return ret;
+ return 0;
}
/*
- * handle a #else directive. Do this by just continuing processing
- * without changing if_stack ; this is so that the error message
- * for missing #endif's etc. will point to the original #if. It
- * is possible that something different would be better.
+ * handle a #elif directive by not changing if_stack either.
+ * see the comment above do_else.
*/
static int
-do_else (pfile)
+do_elif (pfile)
cpp_reader *pfile;
{
- validate_else (pfile, dtable[T_ELSE].name);
- _cpp_skip_rest_of_line (pfile);
+ struct if_stack *ifs = CPP_BUFFER (pfile)->if_stack;
- if (pfile->if_stack == CPP_BUFFER (pfile)->if_stack)
+ if (ifs == NULL)
{
- cpp_error (pfile, "`#else' not within a conditional");
+ cpp_error (pfile, "#elif without #if");
return 0;
}
- else
+ if (ifs->type == T_ELSE)
{
- /* #ifndef can't have its special treatment for containing the whole file
- if it has a #else clause. */
- pfile->if_stack->control_macro = 0;
+ cpp_error (pfile, "#elif after #else");
+ cpp_error_with_line (pfile, ifs->lineno, 1, "the conditional began here");
+ }
- if (pfile->if_stack->type == T_ELSE)
- {
- cpp_error (pfile, "`#else' after `#else'");
- cpp_error_with_line (pfile, pfile->if_stack->lineno, 0,
- "the conditional began here");
- }
- pfile->if_stack->type = T_ELSE;
+ ifs->type = T_ELIF;
+ if (ifs->was_skipping)
+ _cpp_skip_rest_of_line (pfile);
+ else if (pfile->skipping != 1)
+ {
+ _cpp_skip_rest_of_line (pfile);
+ pfile->skipping = 2; /* one block succeeded, so don't do any others */
}
+ else
+ pfile->skipping = ! _cpp_parse_expr (pfile);
- if (pfile->if_stack->if_succeeded)
- return skip_if_group (pfile);
-
- ++pfile->if_stack->if_succeeded; /* continue processing input */
return 0;
}
-/*
- * unstack after #endif command
- */
+
+/* #endif pops the if stack and resets pfile->skipping. */
static int
do_endif (pfile)
cpp_reader *pfile;
{
+ struct if_stack *ifs = CPP_BUFFER (pfile)->if_stack;
+
validate_else (pfile, dtable[T_ENDIF].name);
- _cpp_skip_rest_of_line (pfile);
- if (pfile->if_stack == CPP_BUFFER (pfile)->if_stack)
- cpp_error (pfile, "`#endif' not within a conditional");
+ if (ifs == NULL)
+ cpp_error (pfile, "#endif without #if");
else
{
- IF_STACK *temp = pfile->if_stack;
- pfile->if_stack = temp->next;
- if (temp->control_macro != 0)
- pfile->potential_control_macro = temp->control_macro;
- free (temp);
+ CPP_BUFFER (pfile)->if_stack = ifs->next;
+ pfile->skipping = ifs->was_skipping;
+ pfile->potential_control_macro = ifs->cmacro;
+ free (ifs);
}
return 0;
}
+/* Push an if_stack entry and set pfile->skipping accordingly.
+ If this is a #ifndef starting at the beginning of a file,
+ CMACRO is the macro name tested by the #ifndef. */
+
+static void
+push_conditional (pfile, skip, type, cmacro)
+ cpp_reader *pfile;
+ int skip;
+ int type;
+ const cpp_hashnode *cmacro;
+{
+ struct if_stack *ifs;
+
+ ifs = (struct if_stack *) xmalloc (sizeof (struct if_stack));
+ ifs->lineno = CPP_BUFFER (pfile)->lineno;
+ ifs->next = CPP_BUFFER (pfile)->if_stack;
+ ifs->cmacro = cmacro;
+ ifs->was_skipping = pfile->skipping;
+ ifs->type = type;
+
+ if (!pfile->skipping)
+ pfile->skipping = skip;
+
+ CPP_BUFFER (pfile)->if_stack = ifs;
+}
+
/* Issue -pedantic warning for text which is not a comment following
- an #else or #endif. Do not warn in system headers, as this is harmless
- and very common on old systems. */
+ an #else or #endif. */
static void
validate_else (pfile, directive)
cpp_reader *pfile;
const U_CHAR *directive;
{
- long old_written;
- if (! CPP_PEDANTIC (pfile))
- return;
-
- old_written = CPP_WRITTEN (pfile);
- pfile->no_macro_expand++;
- if (_cpp_get_directive_token (pfile) != CPP_VSPACE)
- cpp_pedwarn (pfile,
- "text following `#%s' violates ANSI standard", directive);
- CPP_SET_WRITTEN (pfile, old_written);
- pfile->no_macro_expand--;
+ if (CPP_PEDANTIC (pfile))
+ {
+ long old_written = CPP_WRITTEN (pfile);
+ pfile->no_macro_expand++;
+ if (_cpp_get_directive_token (pfile) != CPP_VSPACE)
+ cpp_pedwarn (pfile, "ISO C forbids text after #%s", directive);
+ CPP_SET_WRITTEN (pfile, old_written);
+ pfile->no_macro_expand--;
+ }
+ _cpp_skip_rest_of_line (pfile);
}
/* Called when we reach the end of a macro buffer. Walk back up the
conditional stack till we reach its level at entry to this file,
- issuing error messages. */
+ issuing error messages. Then force skipping off. */
void
_cpp_unwind_if_stack (pfile, pbuf)
cpp_reader *pfile;
@@ -1504,18 +1353,14 @@ _cpp_unwind_if_stack (pfile, pbuf)
{
struct if_stack *ifs, *nifs;
- for (ifs = pfile->if_stack;
- ifs != pbuf->if_stack;
- ifs = nifs)
+ for (ifs = pbuf->if_stack; ifs; ifs = nifs)
{
- cpp_error_with_line (pfile, ifs->lineno, 0,
- "unterminated `#%s' conditional",
+ cpp_error_with_line (pfile, ifs->lineno, 1, "unterminated #%s",
dtable[ifs->type].name);
-
nifs = ifs->next;
free (ifs);
}
- pfile->if_stack = ifs;
+ pfile->skipping = 0;
}
#define WARNING(msgid) do { cpp_warning(pfile, msgid); goto error; } while (0)
diff --git a/gcc/cpplib.h b/gcc/cpplib.h
index 0ac5c271ea6..c2f95f526dd 100644
--- a/gcc/cpplib.h
+++ b/gcc/cpplib.h
@@ -509,8 +509,7 @@ struct cpp_reader
for include files. (Altered as we get more of them.) */
unsigned int max_include_len;
- struct if_stack *if_stack;
- const unsigned char *potential_control_macro;
+ const cpp_hashnode *potential_control_macro;
/* Token column position adjustment owing to tabs in whitespace. */
unsigned int col_adjust;
@@ -555,6 +554,9 @@ struct cpp_reader
/* True after cpp_start_read completes. Used to inhibit some
warnings while parsing the command line. */
unsigned char done_initializing;
+
+ /* True if we are skipping a failed conditional group. */
+ unsigned char skipping;
};
/* struct cpp_printer encapsulates state used to convert the stream of
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index f9d89e984e9..c963207532c 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,15 @@
+2000-05-29 Zack Weinberg <zack@wolery.cumb.org>
+
+ * gcc.dg/cpp-mi.c: Add another case, cpp-mix.h, where the
+ guard macro is already defined when the header is first
+ included.
+ * gcc.dg/cpp-mix.h: New file.
+ * gcc.dg/endif-label.c: Update patterns to match compiler.
+
+ * g++.brendan/complex1.C: Declare abort.
+ * g++.law/refs4.C: Remove XFAIL.
+ * g++.oliva/expr2.C: Declare abort and exit.
+
2000-05-28 Alexandre Oliva <aoliva@cygnus.com>
* gcc.c-torture/execute/20000528-1.c: New test.
diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/complex1.C b/gcc/testsuite/g++.old-deja/g++.brendan/complex1.C
index 1c9c4d2fa42..a2378bedf73 100644
--- a/gcc/testsuite/g++.old-deja/g++.brendan/complex1.C
+++ b/gcc/testsuite/g++.old-deja/g++.brendan/complex1.C
@@ -8,6 +8,7 @@
extern "C" {
int printf (const char *, ...);
void exit (int);
+void abort (void);
};
__complex__ double cd;
diff --git a/gcc/testsuite/g++.old-deja/g++.law/refs4.C b/gcc/testsuite/g++.old-deja/g++.law/refs4.C
index a227f23d78d..13349ef1365 100644
--- a/gcc/testsuite/g++.old-deja/g++.law/refs4.C
+++ b/gcc/testsuite/g++.old-deja/g++.law/refs4.C
@@ -1,6 +1,6 @@
// GROUPS passed references
-// execution test - XFAIL *-*-*
+// execution test
#include <stdio.h>
#include <stdlib.h>
diff --git a/gcc/testsuite/g++.old-deja/g++.oliva/expr2.C b/gcc/testsuite/g++.old-deja/g++.oliva/expr2.C
index c1994349acd..20285937b78 100644
--- a/gcc/testsuite/g++.old-deja/g++.oliva/expr2.C
+++ b/gcc/testsuite/g++.old-deja/g++.oliva/expr2.C
@@ -4,6 +4,9 @@
// execution test - XFAIL *-*-*
+extern "C" void abort (void);
+extern "C" void exit (int);
+
int i, j;
const int &f(const int& I, const int& J) {
diff --git a/gcc/testsuite/gcc.dg/cpp-mi.c b/gcc/testsuite/gcc.dg/cpp-mi.c
index a05b279558b..f83a64d5871 100644
--- a/gcc/testsuite/gcc.dg/cpp-mi.c
+++ b/gcc/testsuite/gcc.dg/cpp-mi.c
@@ -17,6 +17,10 @@
#include "cpp-mindp.h"
#include "cpp-mindp.h"
+#define CPP_MIX_H
+#include "cpp-mix.h"
+#include "cpp-mix.h"
+
int
main (void)
{
@@ -28,7 +32,7 @@ main (void)
{ dg-final { set tmp [grep cpp-mi.i {cpp-mi.*\.h} line] } }
{ dg-final { # send_user "$tmp\n" } }
- { dg-final { if [regexp "^{\[0-9\]+ cpp-mic\.h} {\[0-9\]+ cpp-micc\.h} {\[0-9\]+ cpp-mind\.h} {\[0-9\]+ cpp-mindp\.h}$" $tmp] \{ } }
+ { dg-final { if [regexp "^{\[0-9\]+ cpp-mic\.h} {\[0-9\]+ cpp-micc\.h} {\[0-9\]+ cpp-mind\.h} {\[0-9\]+ cpp-mindp\.h} {\[0-9]+ cpp-mix\.h}$" $tmp] \{ } }
{ dg-final { pass "cpp-mi.c: redundant include check" } }
{ dg-final { \} else \{ } }
{ dg-final { fail "cpp-mi.c: redundant include check" } }
diff --git a/gcc/testsuite/gcc.dg/cpp-mix.h b/gcc/testsuite/gcc.dg/cpp-mix.h
new file mode 100644
index 00000000000..ce0e76435d7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp-mix.h
@@ -0,0 +1,9 @@
+/* This header is never to have its contents visible, but it should
+ still receive the optimization. */
+
+#ifndef CPP_MIX_H
+#define CPP_MIX_H
+
+#define main wibble
+
+#endif
diff --git a/gcc/testsuite/gcc.dg/endif-label.c b/gcc/testsuite/gcc.dg/endif-label.c
index 95bd05d51a7..c12662cd52b 100644
--- a/gcc/testsuite/gcc.dg/endif-label.c
+++ b/gcc/testsuite/gcc.dg/endif-label.c
@@ -4,7 +4,7 @@
/* You can't get away with this in your own code... */
#ifdef KERNEL
#define foo
-#endif KERNEL /* { dg-warning "text following" "good warning" } */
+#endif KERNEL /* { dg-warning "forbids text after" "good warning" } */
/* This will provoke a warning because the '3' is an extension. */
#line 10 "endif-label.c" 3 /* { dg-warning "garbage at end" "#line extension" } */
@@ -12,4 +12,4 @@
/* ... but in a system header, it's acceptable. */
#ifdef KERNEL
#define foo
-#endif KERNEL /* { dg-bogus "text following" "bad warning" } */
+#endif KERNEL /* { dg-bogus "forbids text after" "bad warning" } */