aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog15
-rw-r--r--gcc/cpphash.c85
-rw-r--r--gcc/cpplex.c12
-rw-r--r--gcc/cpplib.h4
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/cpp/macsyntx.c72
6 files changed, 157 insertions, 35 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index decd31f..eaee6c8 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,18 @@
+2000-07-08 Neil Booth <NeilB@earthling.net>
+
+ * cpphash.c (is__va_args__): New function.
+ (count_params): Fix line reported in error messages. Use
+ is__va_args__. Don't return ')' on error. Flag GNU style
+ rest args macro definitions.
+ (parse_define): Check macro name is not __VA_ARGS__.
+ (save_expansion): Check identifier in non-varargs-macro is
+ not __VA_ARGS__. Don't flag GNU_VARARGS.
+ * cpplex.c (parse_args): Accept no argument iff GNU_REST_ARGS.
+ (maybe_paste_with_next): Use per-macro GNU_REST_ARGS rather
+ than per-token GNU_VARARGS.
+ * cpplib.h (GNU_VARARGS): Remove.
+ (GNU_REST_ARGS): New.
+
Sat Jul 8 01:38:25 MET DST 2000 Jan Hubicka <jh@suse.cz>
* i386.md (call_pop, call, call_value_pop): Do not set
diff --git a/gcc/cpphash.c b/gcc/cpphash.c
index 2007c52..ee0521b 100644
--- a/gcc/cpphash.c
+++ b/gcc/cpphash.c
@@ -52,6 +52,7 @@ static void dump_funlike_macro PARAMS ((cpp_reader *, cpp_hashnode *));
static const cpp_token *count_params PARAMS ((cpp_reader *,
const cpp_token *,
cpp_toklist *));
+static int is__va_args__ PARAMS ((cpp_reader *, const cpp_token *));
static cpp_toklist *parse_define PARAMS((cpp_reader *));
static int check_macro_redefinition PARAMS((cpp_reader *, cpp_hashnode *hp,
const cpp_toklist *));
@@ -197,6 +198,26 @@ find_param (first, token)
return 0;
}
+/* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the
+ replacement list of a variable-arguments macro. TOKEN is assumed
+ to be of type CPP_NAME. */
+static int
+is__va_args__ (pfile, token)
+ cpp_reader *pfile;
+ const cpp_token *token;
+{
+ if (!CPP_OPTION (pfile, pedantic)
+ || token->val.name.len != sizeof (var_args_str) - 1
+ || ustrncmp (token->val.name.text, var_args_str,
+ sizeof (var_args_str) - 1))
+ return 0;
+
+ cpp_pedwarn_with_line (pfile, token->line, token->col,
+ "\"%s\" is only valid in the replacement list of a function-like macro",
+ var_args_str);
+ return 1;
+}
+
/* Counts the parameters to a function like macro, and saves their
spellings if necessary. Returns the token that we stopped scanning
at; if it's type isn't CPP_CLOSE_PAREN there was an error, which
@@ -208,7 +229,6 @@ count_params (pfile, first, list)
cpp_toklist *list;
{
unsigned int params_len = 0, prev_ident = 0;
- unsigned int line = pfile->token_list.line;
const cpp_token *token, *temp;
list->paramc = 0;
@@ -217,7 +237,8 @@ count_params (pfile, first, list)
switch (token->type)
{
case CPP_EOF:
- cpp_error_with_line (pfile, line, token->col,
+ missing_paren:
+ cpp_error_with_line (pfile, token->line, token->col,
"missing ')' in macro parameter list");
goto out;
@@ -227,21 +248,14 @@ count_params (pfile, first, list)
case CPP_NAME:
if (prev_ident)
{
- cpp_error_with_line (pfile, line, token->col,
+ cpp_error_with_line (pfile, token->line, token->col,
"macro parameters must be comma-separated");
goto out;
}
/* Constraint 6.10.3.5 */
- if (token->val.name.len == sizeof (var_args_str) - 1
- && !ustrncmp (token->val.name.text, var_args_str,
- sizeof (var_args_str) - 1))
- {
- cpp_error_with_line (pfile, line, token->col,
- "\"%s\" is not a valid parameter name",
- var_args_str);
- goto out;
- }
+ if (is__va_args__ (pfile, token))
+ goto out;
params_len += token->val.name.len + 1;
prev_ident = 1;
@@ -250,7 +264,7 @@ count_params (pfile, first, list)
/* Constraint 6.10.3.6 - duplicate parameter names. */
if (find_param (first, token))
{
- cpp_error_with_line (pfile, line, token->col,
+ cpp_error_with_line (pfile, token->line, token->col,
"duplicate macro parameter \"%.*s\"",
(int) token->val.name.len,
token->val.name.text);
@@ -259,7 +273,7 @@ count_params (pfile, first, list)
break;
default:
- cpp_error_with_line (pfile, line, token->col,
+ cpp_error_with_line (pfile, token->line, token->col,
"illegal token in macro parameter list");
goto out;
@@ -271,8 +285,10 @@ count_params (pfile, first, list)
case CPP_COMMA:
if (!prev_ident)
{
- cpp_error_with_line (pfile, line, token->col,
- "missing parameter name");
+ cpp_error_with_line (pfile, token->line, token->col,
+ "parameter name expected");
+ if (token->type == CPP_CLOSE_PAREN)
+ token--; /* Return the ',' not ')'. */
goto out;
}
prev_ident = 0;
@@ -293,22 +309,24 @@ count_params (pfile, first, list)
tok->val.name.len = sizeof (var_args_str) - 1;
tok->val.name.text = var_args_str; /* Safe. */
list->paramc++;
-
+
if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, c99))
cpp_pedwarn (pfile,
"C89 does not permit anon varargs macros");
}
- else if (CPP_PEDANTIC (pfile))
- cpp_pedwarn (pfile,
- "ISO C does not permit named varargs parameters");
+ else
+ {
+ list->flags |= GNU_REST_ARGS;
+ if (CPP_PEDANTIC (pfile))
+ cpp_pedwarn (pfile,
+ "ISO C does not permit named varargs parameters");
+ }
list->flags |= VAR_ARGS;
token++;
if (token->type == CPP_CLOSE_PAREN)
goto scanned;
- cpp_error_with_line (pfile, line, token->col,
- "')' expected after \"...\"");
- goto out;
+ goto missing_paren;
}
}
@@ -345,8 +363,15 @@ parse_define (pfile)
cpp_toklist *list;
int prev_white = 0;
- while ((token = cpp_get_token (pfile))->type == CPP_COMMENT)
- prev_white = 1;
+ /* The first token after the macro's name. */
+ token = cpp_get_token (pfile);
+
+ /* Constraint 6.10.3.5 */
+ if (is__va_args__ (pfile, token - 1))
+ return 0;
+
+ while (token->type == CPP_COMMENT)
+ token++, prev_white = 1;
/* Allocate the expansion's list. It will go in the hash table. */
list = (cpp_toklist *) xmalloc (sizeof (cpp_toklist));
@@ -461,6 +486,12 @@ save_expansion (pfile, list, first, first_param)
}
}
}
+ else if (token->type == CPP_NAME)
+ {
+ /* Constraint 6.10.3.5 */
+ if (!(list->flags & VAR_ARGS) && is__va_args__ (pfile, token))
+ return 1;
+ }
ntokens++;
if (token_spellings[token->type].type > SPELL_NONE)
len += token->val.name.len;
@@ -497,10 +528,6 @@ save_expansion (pfile, list, first, first_param)
dest->flags = token[-1].flags | STRINGIFY_ARG;
else
dest->flags = token->flags; /* Particularly PREV_WHITE. */
-
- if ((int) param_no == list->paramc && list->flags & VAR_ARGS
- && dest != list->tokens && dest[-1].flags & PASTE_LEFT)
- dest[-1].flags |= GNU_VARARGS;
dest++;
continue;
diff --git a/gcc/cpplex.c b/gcc/cpplex.c
index 24e4712..03439fa 100644
--- a/gcc/cpplex.c
+++ b/gcc/cpplex.c
@@ -2222,9 +2222,9 @@ parse_args (pfile, hp, args)
e.g. #define debug(format, args...) ...
debug("string");
This is exactly the same as if the rest argument had received no
- tokens - debug("string",); */
+ tokens - debug("string",); This extension is deprecated. */
- if (argc + 1 == macro->paramc && (macro->flags & VAR_ARGS))
+ if (argc + 1 == macro->paramc && (macro->flags & GNU_REST_ARGS))
{
/* Duplicate the placemarker. Then we can set its flags and
position and safely be using more than one. */
@@ -2525,15 +2525,19 @@ maybe_paste_with_next (pfile, token)
second = cpp_get_token (pfile);
pfile->paste_level = 0;
- /* Ignore placemarker argument tokens. */
+ /* Ignore placemarker argument tokens (cannot be from an empty macro
+ since macros are not expanded). */
if (token->type == CPP_PLACEMARKER)
pasted = duplicate_token (pfile, second);
else if (second->type == CPP_PLACEMARKER)
{
+ cpp_context *mac_context = CURRENT_CONTEXT (pfile) - 1;
/* GCC has special extended semantics for a ## b where b is a
varargs parameter: a disappears if b consists of no tokens.
This extension is deprecated. */
- if (token->flags & GNU_VARARGS)
+ if ((mac_context->u.list->flags & GNU_REST_ARGS)
+ && (mac_context->u.list->tokens[mac_context->posn - 1].val.aux + 1
+ == (unsigned) mac_context->u.list->paramc))
{
cpp_warning (pfile, "deprecated GNU ## extension used");
pasted = duplicate_token (pfile, second);
diff --git a/gcc/cpplib.h b/gcc/cpplib.h
index 1c516a6..e9bb24f 100644
--- a/gcc/cpplib.h
+++ b/gcc/cpplib.h
@@ -158,7 +158,6 @@ struct cpp_name
#define STRINGIFY_ARG (1 << 3) /* If macro argument to be stringified. */
#define PASTE_LEFT (1 << 4) /* If on LHS of a ## operator. */
#define PASTED (1 << 5) /* The result of a ## operator. */
-#define GNU_VARARGS (1 << 6) /* GNU ## kludge. */
/* A preprocessing token. This has been carefully packed and should
occupy 16 bytes on 32-bit hosts and 24 bytes on 64-bit hosts. */
@@ -181,7 +180,8 @@ struct cpp_token
/* cpp_toklist flags. */
#define LIST_OFFSET (1 << 0)
#define VAR_ARGS (1 << 1)
-#define BEG_OF_FILE (1 << 2)
+#define GNU_REST_ARGS (1 << 2) /* Set in addition to VAR_ARGS. */
+#define BEG_OF_FILE (1 << 3)
struct directive; /* These are deliberately incomplete. */
struct answer;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 096cea1..4410e2e 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2000-07-08 Neil Booth <NeilB@earthling.net>
+
+ * gcc.dg/cpp/macsyntx.c: New tests.
+
2000-07-07 Jakub Jelinek <jakub@redhat.com>
* gcc.dg/20000707-1.c: New test.
diff --git a/gcc/testsuite/gcc.dg/cpp/macsyntx.c b/gcc/testsuite/gcc.dg/cpp/macsyntx.c
new file mode 100644
index 0000000..baa69d1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/macsyntx.c
@@ -0,0 +1,72 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc. */
+
+/* { dg-do preprocess } */
+/* { dg-options -pedantic } */
+
+/* Tests macro syntax, for both definition and invocation, including:-
+
+ o Full range of macro definition semantics.
+ o No. of arguments supplied to function-like macros.
+ o Odd GNU rest args behaviour.
+ o Macro arguments do not flow into the rest of the file. */
+
+
+/* Test basic macro definition syntax. The macros are all called
+ "foo" deliberately to provoke an (excess) redefinition warning in
+ case the macros succeed in being entered in the macro hash table
+ despite being an error.
+
+ Split a couple of the lines to check that the errors appear on the
+ right line (i.e. are associated with the correct token). */
+
+#define ; /* { dg-error "identifier" } */
+#define SEMI; /* { dg-warning "space" } */
+#define foo(X /* { dg-error "missing" } */
+#define foo\
+(X,) /* { dg-error "parameter name" } */
+#define foo(, X) /* { dg-error "parameter name" } */
+#define foo(X, X) /* { dg-error "duplicate" } */
+#define foo(X Y) /* { dg-error "comma" } */
+#define foo(() /* { dg-error "illegal token" } */
+#define foo(..., X) /* { dg-error "missing" } */
+#define foo \
+__VA_ARGS__ /* { dg-warning "__VA_ARGS__" } */
+#define foo(__VA_ARGS__) /* { dg-warning "__VA_ARGS__" } */
+#define foo(...) __VA_ARGS__ /* OK. */
+#define __VA_ARGS__ /* { dg-warning "__VA_ARGS__" } */
+
+/* test # of supplied arguments. */
+#define none()
+#define one(x)
+#define two(x, y)
+#define var0(...)
+#define var1(x, ...)
+none() /* OK. */
+none(ichi) /* { dg-error "too many" } */
+one() /* OK. */
+one(ichi) /* OK. */
+one(ichi\
+, ni) /* { dg-error "too many" } */
+two(ichi) /* { dg-error "insufficient" } */
+var0() /* OK. */
+var0(ichi) /* OK. */
+var1() /* { dg-error "insufficient" } */
+var1(ichi) /* { dg-error "insufficient" } */
+var1(ichi, ni) /* OK. */
+
+/* This tests two deprecated oddities of GNU rest args - omitting a
+ comma is OK, and backtracking a token on pasting an empty rest
+ args. */
+#define rest(x, y...) x ## y /* { dg-warning "ISO C" } */
+rest(ichi,) /* { dg-warning "deprecated" } */
+rest(ichi) /* { dg-warning "deprecated" } */
+#if 23 != rest(2, 3) /* OK, no warning. */
+#error 23 != 23 !!
+#endif
+
+/* Test that we don't allow arguments to flow into the rest of the
+ file. */
+#define half_invocation do_nowt(2
+#define do_nowt(x) x
+half_invocation ) /* OK. */
+do_nowt (half_invocation)) /* { dg-error "unterminated invocation" } */