Commit 6fee6033 by Zack Weinberg

cppmacro.c (CAN_PASTE_AFTER): New macro.

	* cppmacro.c (CAN_PASTE_AFTER): New macro.
	(count_params): Don't set GNU_REST_ARGS on anything.
	(save_expansion): Set PASTE_LEFT only on tokens for which
	CAN_PASTE_AFTER is true, or which are named operators.

	* cpplex.c (parse_args): Distinguish between a rest argument
	given one empty argument, and a rest argument given zero arguments.
	(maybe_paste_with_next): Look for VOID_REST tag, and trigger
	deletion of previous token based on that.
	(get_raw_token): Flatten some control structure.

	* cpplib.h (CPP_LAST_EQ): Correct.
	(VOID_REST): New token flag.
	(GNU_REST_ARGS): Delete.

	* gcc.dg/cpp/20000625-2.c, gcc.dg/cpp/macsyntx.c: Update error
	regexps.
	* gcc.dg/cpp/paste6.c: New test.

From-SVN: r35146
parent 1e18a243
2000-07-20 Zack Weinberg <zack@wolery.cumb.org>
* cppmacro.c (CAN_PASTE_AFTER): New macro.
(count_params): Don't set GNU_REST_ARGS on anything.
(save_expansion): Set PASTE_LEFT only on tokens for which
CAN_PASTE_AFTER is true, or which are named operators.
* cpplex.c (parse_args): Distinguish between a rest argument
given one empty argument, and a rest argument given zero arguments.
(maybe_paste_with_next): Look for VOID_REST tag, and trigger
deletion of previous token based on that.
(get_raw_token): Flatten some control structure.
* cpplib.h (CPP_LAST_EQ): Correct.
(VOID_REST): New token flag.
(GNU_REST_ARGS): Delete.
* tradcpp.c (main): Don't munge -D options.
(make_definition): Bring -D handling in line with cpplib.
(do_define): Strip all leading whitespace from macro definitions.
2000-07-20 David Billinghurst <David.Billinghurst@riotinto.com.au>
* Makefile.in (tradcpp): Depend on intl.o and version.o.
2000-07-20 Bruce Korb <bkorb@gnu.org> 2000-07-20 Bruce Korb <bkorb@gnu.org>
* fixincl/check.tpl: strip the platform specific types before testing * fixincl/check.tpl: strip the platform specific types before testing
......
...@@ -2399,13 +2399,19 @@ parse_args (pfile, hp, args) ...@@ -2399,13 +2399,19 @@ parse_args (pfile, hp, 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",); This extension is deprecated. */ tokens - debug("string",); This extension is deprecated. */
if (argc + 1 == macro->paramc && (macro->flags & GNU_REST_ARGS)) if (argc + 1 == macro->paramc && (macro->flags & VAR_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. */
save_token (args, duplicate_token (pfile, &placemarker_token)); cpp_token *pm = duplicate_token (pfile, &placemarker_token);
pm->flags = VOID_REST;
save_token (args, pm);
args->ends[argc] = total + 1; args->ends[argc] = total + 1;
if (CPP_OPTION (pfile, c99) && CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "ISO C99 requires rest arguments to be used");
return 0; return 0;
} }
else else
...@@ -2710,17 +2716,11 @@ maybe_paste_with_next (pfile, token) ...@@ -2710,17 +2716,11 @@ maybe_paste_with_next (pfile, token)
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 /* GCC has special extended semantics for a ## b where b is
a varargs parameter: a disappears if b consists of no a varargs parameter: a disappears if b was given no actual
tokens. This extension is deprecated. */ arguments (not merely if b is an empty argument). */
if ((mac_context->u.list->flags & GNU_REST_ARGS) if (second->flags & VOID_REST)
&& (mac_context->u.list->tokens[mac_context->posn-1].val.aux + 1 pasted = duplicate_token (pfile, second);
== (unsigned) mac_context->u.list->paramc))
{
cpp_warning (pfile, "deprecated GNU ## extension used");
pasted = duplicate_token (pfile, second);
}
else else
pasted = duplicate_token (pfile, token); pasted = duplicate_token (pfile, token);
} }
...@@ -3161,6 +3161,7 @@ get_raw_token (pfile) ...@@ -3161,6 +3161,7 @@ get_raw_token (pfile)
{ {
result = context->pushed_token; result = context->pushed_token;
context->pushed_token = 0; context->pushed_token = 0;
return result; /* Cannot be a CPP_MACRO_ARG */
} }
else if (context->posn == context->count) else if (context->posn == context->count)
{ {
...@@ -3168,21 +3169,19 @@ get_raw_token (pfile) ...@@ -3168,21 +3169,19 @@ get_raw_token (pfile)
return &eof_token; return &eof_token;
continue; continue;
} }
else else if (IS_ARG_CONTEXT (context))
{ {
if (IS_ARG_CONTEXT (context)) result = context->u.arg[context->posn++];
if (result == 0)
{ {
context->flags ^= CONTEXT_RAW;
result = context->u.arg[context->posn++]; result = context->u.arg[context->posn++];
if (result == 0)
{
context->flags ^= CONTEXT_RAW;
result = context->u.arg[context->posn++];
}
return result; /* Cannot be a CPP_MACRO_ARG */
} }
result = &context->u.list->tokens[context->posn++]; return result; /* Cannot be a CPP_MACRO_ARG */
} }
result = &context->u.list->tokens[context->posn++];
if (result->type != CPP_MACRO_ARG) if (result->type != CPP_MACRO_ARG)
return result; return result;
...@@ -3225,7 +3224,6 @@ lex_next (pfile, clear) ...@@ -3225,7 +3224,6 @@ lex_next (pfile, clear)
if (pfile->temp_used) if (pfile->temp_used)
release_temp_tokens (pfile); release_temp_tokens (pfile);
} }
lex_line (pfile, list); lex_line (pfile, list);
pfile->contexts[0].count = list->tokens_used; pfile->contexts[0].count = list->tokens_used;
......
...@@ -46,7 +46,7 @@ typedef struct cpp_hashnode cpp_hashnode; ...@@ -46,7 +46,7 @@ typedef struct cpp_hashnode cpp_hashnode;
the same order as their counterparts without the '=', like ">>". */ the same order as their counterparts without the '=', like ">>". */
/* Positions in the table. */ /* Positions in the table. */
#define CPP_LAST_EQ CPP_LSHIFT #define CPP_LAST_EQ CPP_MAX
#define CPP_FIRST_DIGRAPH CPP_HASH #define CPP_FIRST_DIGRAPH CPP_HASH
#define TTYPE_TABLE \ #define TTYPE_TABLE \
...@@ -154,7 +154,8 @@ struct cpp_string ...@@ -154,7 +154,8 @@ struct cpp_string
#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 NAMED_OP (1 << 6) /* C++ named operators, also defined */ #define NAMED_OP (1 << 6) /* C++ named operators, also "defined". */
#define VOID_REST (1 << 7) /* When a rest arg gets zero actual args. */
/* 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. */
...@@ -178,8 +179,7 @@ struct cpp_token ...@@ -178,8 +179,7 @@ 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 GNU_REST_ARGS (1 << 2) /* Set in addition to VAR_ARGS. */ #define BEG_OF_FILE (1 << 2)
#define BEG_OF_FILE (1 << 3)
struct directive; /* These are deliberately incomplete. */ struct directive; /* These are deliberately incomplete. */
struct answer; struct answer;
......
...@@ -53,6 +53,14 @@ static unsigned int find_param PARAMS ((const cpp_token *, ...@@ -53,6 +53,14 @@ static unsigned int find_param PARAMS ((const cpp_token *,
const cpp_token *)); const cpp_token *));
static cpp_toklist * alloc_macro PARAMS ((cpp_reader *, struct macro_info *)); static cpp_toklist * alloc_macro PARAMS ((cpp_reader *, struct macro_info *));
/* These are all the tokens that can have something pasted after them.
Comma is included in the list only to support the GNU varargs extension
(where you write a ## b and a disappears if b is an empty rest argument). */
#define CAN_PASTE_AFTER(type) \
((type) <= CPP_LAST_EQ || (type) == CPP_COLON || (type) == CPP_HASH \
|| (type) == CPP_DEREF || (type) == CPP_DOT || (type) == CPP_NAME \
|| (type) == CPP_INT || (type) == CPP_FLOAT || (type) == CPP_NUMBER \
|| (type) == CPP_MACRO_ARG || (type) == CPP_PLACEMARKER || (type) == CPP_COMMA)
/* Scans for a given token, returning the parameter number if found, /* Scans for a given token, returning the parameter number if found,
or 0 if not found. Scans from FIRST to TOKEN - 1 or the first or 0 if not found. Scans from FIRST to TOKEN - 1 or the first
...@@ -192,7 +200,6 @@ count_params (pfile, info) ...@@ -192,7 +200,6 @@ count_params (pfile, info)
} }
else else
{ {
info->flags |= GNU_REST_ARGS;
if (CPP_PEDANTIC (pfile)) if (CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, cpp_pedwarn (pfile,
"ISO C does not permit named varargs parameters"); "ISO C does not permit named varargs parameters");
...@@ -294,9 +301,6 @@ parse_define (pfile, info) ...@@ -294,9 +301,6 @@ parse_define (pfile, info)
/* Constraint 6.10.3.5 */ /* Constraint 6.10.3.5 */
if (!(info->flags & VAR_ARGS) && is__va_args__ (pfile, token)) if (!(info->flags & VAR_ARGS) && is__va_args__ (pfile, token))
return 1; return 1;
/* It might be worth doing a check here that we aren't a
macro argument, since we don't store the text of macro
arguments. This would reduce "len" and save space. */
} }
info->ntokens++; info->ntokens++;
if (TOKEN_SPELL (token) == SPELL_STRING) if (TOKEN_SPELL (token) == SPELL_STRING)
...@@ -463,7 +467,15 @@ save_expansion (pfile, info) ...@@ -463,7 +467,15 @@ save_expansion (pfile, info)
continue; continue;
case CPP_PASTE: case CPP_PASTE:
dest[-1].flags |= PASTE_LEFT; /* Set the paste flag on the token to our left, unless there
is no possible token to which it might be pasted. That
is critical for correct operation under some circumstances;
see gcc.dg/cpp/paste6.c. */
if (CAN_PASTE_AFTER (dest[-1].type) || (dest[-1].flags & NAMED_OP))
dest[-1].flags |= PASTE_LEFT;
else if (CPP_OPTION (pfile, warn_paste))
cpp_warning_with_line (pfile, dest[-1].line, dest[-1].col,
"nothing can be pasted after this token");
continue; continue;
case CPP_HASH: case CPP_HASH:
......
2000-07-20 Zack Weinberg <zack@wolery.cumb.org>
* gcc.dg/cpp/20000625-2.c, gcc.dg/cpp/macsyntx.c: Update error
regexps.
* gcc.dg/cpp/paste6.c: New test.
2000-07-19 Zack Weinberg <zack@wolery.cumb.org> 2000-07-19 Zack Weinberg <zack@wolery.cumb.org>
* gcc.dg/cpp/tr-direct.c: New test. * gcc.dg/cpp/tr-direct.c: New test.
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/* { dg-do run } */ /* { dg-do run } */
#define symbol_version(name, version) name##@##version #define symbol_version(name, version) name##@##version
/* { dg-warning "nothing can be pasted" "" { target *-*-* } 4 } */
#define str(x) xstr(x) #define str(x) xstr(x)
#define xstr(x) #x #define xstr(x) #x
......
...@@ -51,16 +51,15 @@ one(ichi\ ...@@ -51,16 +51,15 @@ one(ichi\
two(ichi) /* { dg-error "not enough" } */ two(ichi) /* { dg-error "not enough" } */
var0() /* OK. */ var0() /* OK. */
var0(ichi) /* OK. */ var0(ichi) /* OK. */
var1() /* { dg-error "not enough" } */ var1() /* { dg-warning "rest arguments to be used" } */
var1(ichi) /* { dg-error "not enough" } */ var1(ichi) /* { dg-warning "rest arguments to be used" } */
var1(ichi, ni) /* OK. */ var1(ichi, ni) /* OK. */
/* This tests two deprecated oddities of GNU rest args - omitting a /* This tests two oddities of GNU rest args - omitting a comma is OK,
comma is OK, and backtracking a token on pasting an empty rest and backtracking a token on pasting an empty rest args. */
args. */
#define rest(x, y...) x ## y /* { dg-warning "ISO C" } */ #define rest(x, y...) x ## y /* { dg-warning "ISO C" } */
rest(ichi,) /* { dg-warning "deprecated" } */ rest(ichi,) /* OK. */
rest(ichi) /* { dg-warning "deprecated" } */ rest(ichi) /* { dg-warning "rest arguments to be used" } */
#if 23 != rest(2, 3) /* OK, no warning. */ #if 23 != rest(2, 3) /* OK, no warning. */
#error 23 != 23 !! #error 23 != 23 !!
#endif #endif
......
/* Regression test for paste appearing at the beginning of a set of
actual arguments. Original bug exposed by Linux kernel. Problem
reported by Jakub Jelinek <jakub@redhat.com>. */
/* { dg-do compile } */
extern int foo(int x);
#define bar(x) foo(x)
#define baz(x) bar(##x) /* { dg-warning "nothing can be pasted" } */
int quux(int y) { return baz(y); }
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