Commit 563dd08a by Neil Booth Committed by Neil Booth

cpphash.c (is__va_args__): New function.

	* 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.

	* gcc.dg/cpp/macsyntx.c: New tests.

From-SVN: r34919
parent 0828a0bd
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> 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 * i386.md (call_pop, call, call_value_pop): Do not set
......
...@@ -52,6 +52,7 @@ static void dump_funlike_macro PARAMS ((cpp_reader *, cpp_hashnode *)); ...@@ -52,6 +52,7 @@ static void dump_funlike_macro PARAMS ((cpp_reader *, cpp_hashnode *));
static const cpp_token *count_params PARAMS ((cpp_reader *, static const cpp_token *count_params PARAMS ((cpp_reader *,
const cpp_token *, const cpp_token *,
cpp_toklist *)); cpp_toklist *));
static int is__va_args__ PARAMS ((cpp_reader *, const cpp_token *));
static cpp_toklist *parse_define PARAMS((cpp_reader *)); static cpp_toklist *parse_define PARAMS((cpp_reader *));
static int check_macro_redefinition PARAMS((cpp_reader *, cpp_hashnode *hp, static int check_macro_redefinition PARAMS((cpp_reader *, cpp_hashnode *hp,
const cpp_toklist *)); const cpp_toklist *));
...@@ -197,6 +198,26 @@ find_param (first, token) ...@@ -197,6 +198,26 @@ find_param (first, token)
return 0; 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 /* Counts the parameters to a function like macro, and saves their
spellings if necessary. Returns the token that we stopped scanning 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 at; if it's type isn't CPP_CLOSE_PAREN there was an error, which
...@@ -208,7 +229,6 @@ count_params (pfile, first, list) ...@@ -208,7 +229,6 @@ count_params (pfile, first, list)
cpp_toklist *list; cpp_toklist *list;
{ {
unsigned int params_len = 0, prev_ident = 0; unsigned int params_len = 0, prev_ident = 0;
unsigned int line = pfile->token_list.line;
const cpp_token *token, *temp; const cpp_token *token, *temp;
list->paramc = 0; list->paramc = 0;
...@@ -217,7 +237,8 @@ count_params (pfile, first, list) ...@@ -217,7 +237,8 @@ count_params (pfile, first, list)
switch (token->type) switch (token->type)
{ {
case CPP_EOF: 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"); "missing ')' in macro parameter list");
goto out; goto out;
...@@ -227,21 +248,14 @@ count_params (pfile, first, list) ...@@ -227,21 +248,14 @@ count_params (pfile, first, list)
case CPP_NAME: case CPP_NAME:
if (prev_ident) 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"); "macro parameters must be comma-separated");
goto out; goto out;
} }
/* Constraint 6.10.3.5 */ /* Constraint 6.10.3.5 */
if (token->val.name.len == sizeof (var_args_str) - 1 if (is__va_args__ (pfile, token))
&& !ustrncmp (token->val.name.text, var_args_str, goto out;
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;
}
params_len += token->val.name.len + 1; params_len += token->val.name.len + 1;
prev_ident = 1; prev_ident = 1;
...@@ -250,7 +264,7 @@ count_params (pfile, first, list) ...@@ -250,7 +264,7 @@ count_params (pfile, first, list)
/* Constraint 6.10.3.6 - duplicate parameter names. */ /* Constraint 6.10.3.6 - duplicate parameter names. */
if (find_param (first, token)) 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\"", "duplicate macro parameter \"%.*s\"",
(int) token->val.name.len, (int) token->val.name.len,
token->val.name.text); token->val.name.text);
...@@ -259,7 +273,7 @@ count_params (pfile, first, list) ...@@ -259,7 +273,7 @@ count_params (pfile, first, list)
break; break;
default: default:
cpp_error_with_line (pfile, line, token->col, cpp_error_with_line (pfile, token->line, token->col,
"illegal token in macro parameter list"); "illegal token in macro parameter list");
goto out; goto out;
...@@ -271,8 +285,10 @@ count_params (pfile, first, list) ...@@ -271,8 +285,10 @@ count_params (pfile, first, list)
case CPP_COMMA: case CPP_COMMA:
if (!prev_ident) if (!prev_ident)
{ {
cpp_error_with_line (pfile, line, token->col, cpp_error_with_line (pfile, token->line, token->col,
"missing parameter name"); "parameter name expected");
if (token->type == CPP_CLOSE_PAREN)
token--; /* Return the ',' not ')'. */
goto out; goto out;
} }
prev_ident = 0; prev_ident = 0;
...@@ -293,22 +309,24 @@ count_params (pfile, first, list) ...@@ -293,22 +309,24 @@ count_params (pfile, first, list)
tok->val.name.len = sizeof (var_args_str) - 1; tok->val.name.len = sizeof (var_args_str) - 1;
tok->val.name.text = var_args_str; /* Safe. */ tok->val.name.text = var_args_str; /* Safe. */
list->paramc++; list->paramc++;
if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, c99)) if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, c99))
cpp_pedwarn (pfile, cpp_pedwarn (pfile,
"C89 does not permit anon varargs macros"); "C89 does not permit anon varargs macros");
} }
else if (CPP_PEDANTIC (pfile)) else
cpp_pedwarn (pfile, {
"ISO C does not permit named varargs parameters"); list->flags |= GNU_REST_ARGS;
if (CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile,
"ISO C does not permit named varargs parameters");
}
list->flags |= VAR_ARGS; list->flags |= VAR_ARGS;
token++; token++;
if (token->type == CPP_CLOSE_PAREN) if (token->type == CPP_CLOSE_PAREN)
goto scanned; goto scanned;
cpp_error_with_line (pfile, line, token->col, goto missing_paren;
"')' expected after \"...\"");
goto out;
} }
} }
...@@ -345,8 +363,15 @@ parse_define (pfile) ...@@ -345,8 +363,15 @@ parse_define (pfile)
cpp_toklist *list; cpp_toklist *list;
int prev_white = 0; int prev_white = 0;
while ((token = cpp_get_token (pfile))->type == CPP_COMMENT) /* The first token after the macro's name. */
prev_white = 1; 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. */ /* Allocate the expansion's list. It will go in the hash table. */
list = (cpp_toklist *) xmalloc (sizeof (cpp_toklist)); list = (cpp_toklist *) xmalloc (sizeof (cpp_toklist));
...@@ -461,6 +486,12 @@ save_expansion (pfile, list, first, first_param) ...@@ -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++; ntokens++;
if (token_spellings[token->type].type > SPELL_NONE) if (token_spellings[token->type].type > SPELL_NONE)
len += token->val.name.len; len += token->val.name.len;
...@@ -497,10 +528,6 @@ save_expansion (pfile, list, first, first_param) ...@@ -497,10 +528,6 @@ save_expansion (pfile, list, first, first_param)
dest->flags = token[-1].flags | STRINGIFY_ARG; dest->flags = token[-1].flags | STRINGIFY_ARG;
else else
dest->flags = token->flags; /* Particularly PREV_WHITE. */ 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++; dest++;
continue; continue;
......
...@@ -2222,9 +2222,9 @@ parse_args (pfile, hp, args) ...@@ -2222,9 +2222,9 @@ parse_args (pfile, hp, args)
e.g. #define debug(format, args...) ... e.g. #define debug(format, args...) ...
debug("string"); debug("string");
This is exactly the same as if the rest argument had received no 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 /* Duplicate the placemarker. Then we can set its flags and
position and safely be using more than one. */ position and safely be using more than one. */
...@@ -2525,15 +2525,19 @@ maybe_paste_with_next (pfile, token) ...@@ -2525,15 +2525,19 @@ maybe_paste_with_next (pfile, token)
second = cpp_get_token (pfile); second = cpp_get_token (pfile);
pfile->paste_level = 0; 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) if (token->type == CPP_PLACEMARKER)
pasted = duplicate_token (pfile, second); pasted = duplicate_token (pfile, second);
else if (second->type == CPP_PLACEMARKER) 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 /* GCC has special extended semantics for a ## b where b is a
varargs parameter: a disappears if b consists of no tokens. varargs parameter: a disappears if b consists of no tokens.
This extension is deprecated. */ 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"); cpp_warning (pfile, "deprecated GNU ## extension used");
pasted = duplicate_token (pfile, second); pasted = duplicate_token (pfile, second);
......
...@@ -158,7 +158,6 @@ struct cpp_name ...@@ -158,7 +158,6 @@ struct cpp_name
#define STRINGIFY_ARG (1 << 3) /* If macro argument to be stringified. */ #define STRINGIFY_ARG (1 << 3) /* If macro argument to be stringified. */
#define PASTE_LEFT (1 << 4) /* If on LHS of a ## operator. */ #define PASTE_LEFT (1 << 4) /* If on LHS of a ## operator. */
#define PASTED (1 << 5) /* The result 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 /* A preprocessing token. This has been carefully packed and should
occupy 16 bytes on 32-bit hosts and 24 bytes on 64-bit hosts. */ occupy 16 bytes on 32-bit hosts and 24 bytes on 64-bit hosts. */
...@@ -181,7 +180,8 @@ struct cpp_token ...@@ -181,7 +180,8 @@ struct cpp_token
/* cpp_toklist flags. */ /* cpp_toklist flags. */
#define LIST_OFFSET (1 << 0) #define LIST_OFFSET (1 << 0)
#define VAR_ARGS (1 << 1) #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 directive; /* These are deliberately incomplete. */
struct answer; struct answer;
......
2000-07-08 Neil Booth <NeilB@earthling.net>
* gcc.dg/cpp/macsyntx.c: New tests.
2000-07-07 Jakub Jelinek <jakub@redhat.com> 2000-07-07 Jakub Jelinek <jakub@redhat.com>
* gcc.dg/20000707-1.c: New test. * gcc.dg/20000707-1.c: New test.
......
/* 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" } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment