cppfiles.c (stack_include_file): Check for stacked contexts here.

* cppfiles.c (stack_include_file): Check for stacked contexts
	here.
	* cpphash.h (_cpp_do__Pragma): New prototype.
	* cppinit.c (cpp_reader_init): Add _Pragma keyword to hash table.

	* cpplex.c (skip_escaped_newlines): Only process trigraphs and
	escaped newlines if !(buffer->from_stage3).
	(_cpp_lex_token): Warn about missing newlines iff
	!buffer->from_stage3.

	* cpplib.c (get__Pragma_string, destringize,
	_cpp_do__Pragma): New functions.
	(run_directive): Set output_line for _Pragma to avoid line
	markers in output.  Set from_stage3 and prevent macro expansion
	for _Pragma and command-line options.  Check buffer exhaustion.
	(cpp_push_buffer): Don't check for stacked macro contexts, as
	this is perfectly legitimate for _Pragma.  Move the check to
	stack_include_file instead. Set from_stage3 iff buffer is
	preprocessed input.

	* cpplib.h (struct cpp_buffer): Make warned_cplusplus_comments
	unsigned. New boolean from_stage3.
	(struct spec_nodes): Add n__Pragma.

	* cppmacro.c (enter_macro_context): Flip sense of return value.
	(_cpp_get_token): Handle _Pragma operator.

From-SVN: r37147
This commit is contained in:
Neil Booth 2000-10-30 22:29:00 +00:00 committed by Neil Booth
parent dbdaea4110
commit a5c3cccda4
8 changed files with 212 additions and 79 deletions

View File

@ -1,3 +1,32 @@
2000-10-30 Neil Booth <neilb@earthling.net>
* cppfiles.c (stack_include_file): Check for stacked contexts
here.
* cpphash.h (_cpp_do__Pragma): New prototype.
* cppinit.c (cpp_reader_init): Add _Pragma keyword to hash table.
* cpplex.c (skip_escaped_newlines): Only process trigraphs and
escaped newlines if !(buffer->from_stage3).
(_cpp_lex_token): Warn about missing newlines iff
!buffer->from_stage3.
* cpplib.c (get__Pragma_string, destringize,
_cpp_do__Pragma): New functions.
(run_directive): Set output_line for _Pragma to avoid line
markers in output. Set from_stage3 and prevent macro expansion
for _Pragma and command-line options. Check buffer exhaustion.
(cpp_push_buffer): Don't check for stacked macro contexts, as
this is perfectly legitimate for _Pragma. Move the check to
stack_include_file instead. Set from_stage3 iff buffer is
preprocessed input.
* cpplib.h (struct cpp_buffer): Make warned_cplusplus_comments
unsigned. New boolean from_stage3.
(struct spec_nodes): Add n__Pragma.
* cppmacro.c (enter_macro_context): Flip sense of return value.
(_cpp_get_token): Handle _Pragma operator.
2000-10-30 Phil Edwards <pme@sources.redhat.com> 2000-10-30 Phil Edwards <pme@sources.redhat.com>
* gcc.texi: The C++ standard isn't "draft" anymore. * gcc.texi: The C++ standard isn't "draft" anymore.

View File

@ -206,6 +206,9 @@ stack_include_file (pfile, inc)
{ {
cpp_buffer *fp; cpp_buffer *fp;
if (pfile->context->prev)
cpp_ice (pfile, "attempt to push file buffer with contexts stacked");
if (DO_NOT_REREAD (inc)) if (DO_NOT_REREAD (inc))
return 0; return 0;

View File

@ -203,6 +203,7 @@ extern void _cpp_unlock_pool PARAMS ((cpp_pool *));
extern int _cpp_test_assertion PARAMS ((cpp_reader *, int *)); extern int _cpp_test_assertion PARAMS ((cpp_reader *, int *));
extern int _cpp_handle_directive PARAMS ((cpp_reader *, int)); extern int _cpp_handle_directive PARAMS ((cpp_reader *, int));
extern void _cpp_define_builtin PARAMS ((cpp_reader *, const char *)); extern void _cpp_define_builtin PARAMS ((cpp_reader *, const char *));
extern void _cpp_do__Pragma PARAMS ((cpp_reader *));
extern void _cpp_init_stacks PARAMS ((cpp_reader *)); extern void _cpp_init_stacks PARAMS ((cpp_reader *));
extern void _cpp_cleanup_stacks PARAMS ((cpp_reader *)); extern void _cpp_cleanup_stacks PARAMS ((cpp_reader *));
extern void _cpp_init_internal_pragmas PARAMS ((cpp_reader *)); extern void _cpp_init_internal_pragmas PARAMS ((cpp_reader *));

View File

@ -487,6 +487,7 @@ cpp_reader_init (pfile)
s = &pfile->spec_nodes; s = &pfile->spec_nodes;
s->n_L = cpp_lookup (pfile, DSC("L")); s->n_L = cpp_lookup (pfile, DSC("L"));
s->n_defined = cpp_lookup (pfile, DSC("defined")); s->n_defined = cpp_lookup (pfile, DSC("defined"));
s->n__Pragma = cpp_lookup (pfile, DSC("_Pragma"));
s->n__STRICT_ANSI__ = cpp_lookup (pfile, DSC("__STRICT_ANSI__")); s->n__STRICT_ANSI__ = cpp_lookup (pfile, DSC("__STRICT_ANSI__"));
s->n__CHAR_UNSIGNED__ = cpp_lookup (pfile, DSC("__CHAR_UNSIGNED__")); s->n__CHAR_UNSIGNED__ = cpp_lookup (pfile, DSC("__CHAR_UNSIGNED__"));
s->n__VA_ARGS__ = cpp_lookup (pfile, DSC("__VA_ARGS__")); s->n__VA_ARGS__ = cpp_lookup (pfile, DSC("__VA_ARGS__"));

View File

@ -181,71 +181,77 @@ trigraph_ok (pfile, from_char)
/* Skips any escaped newlines introduced by NEXT, which is either a /* Skips any escaped newlines introduced by NEXT, which is either a
'?' or a '\\'. Returns the next character, which will also have '?' or a '\\'. Returns the next character, which will also have
been placed in buffer->read_ahead. */ been placed in buffer->read_ahead. This routine performs
preprocessing stages 1 and 2 of the ISO C standard. */
static cppchar_t static cppchar_t
skip_escaped_newlines (buffer, next) skip_escaped_newlines (buffer, next)
cpp_buffer *buffer; cpp_buffer *buffer;
cppchar_t next; cppchar_t next;
{ {
cppchar_t next1; /* Only do this if we apply stages 1 and 2. */
const unsigned char *saved_cur; if (!buffer->from_stage3)
int space;
do
{ {
if (buffer->cur == buffer->rlimit) cppchar_t next1;
break; const unsigned char *saved_cur;
int space;
SAVE_STATE ();
if (next == '?')
{
next1 = *buffer->cur++;
if (next1 != '?' || buffer->cur == buffer->rlimit)
{
RESTORE_STATE ();
break;
}
next1 = *buffer->cur++;
if (!_cpp_trigraph_map[next1] || !trigraph_ok (buffer->pfile, next1))
{
RESTORE_STATE ();
break;
}
/* We have a full trigraph here. */
next = _cpp_trigraph_map[next1];
if (next != '\\' || buffer->cur == buffer->rlimit)
break;
SAVE_STATE ();
}
/* We have a backslash, and room for at least one more character. */
space = 0;
do do
{ {
next1 = *buffer->cur++; if (buffer->cur == buffer->rlimit)
if (!is_nvspace (next1))
break; break;
space = 1;
SAVE_STATE ();
if (next == '?')
{
next1 = *buffer->cur++;
if (next1 != '?' || buffer->cur == buffer->rlimit)
{
RESTORE_STATE ();
break;
}
next1 = *buffer->cur++;
if (!_cpp_trigraph_map[next1]
|| !trigraph_ok (buffer->pfile, next1))
{
RESTORE_STATE ();
break;
}
/* We have a full trigraph here. */
next = _cpp_trigraph_map[next1];
if (next != '\\' || buffer->cur == buffer->rlimit)
break;
SAVE_STATE ();
}
/* We have a backslash, and room for at least one more character. */
space = 0;
do
{
next1 = *buffer->cur++;
if (!is_nvspace (next1))
break;
space = 1;
}
while (buffer->cur < buffer->rlimit);
if (!is_vspace (next1))
{
RESTORE_STATE ();
break;
}
if (space)
cpp_warning (buffer->pfile,
"backslash and newline separated by space");
next = handle_newline (buffer, next1);
if (next == EOF)
cpp_pedwarn (buffer->pfile, "backslash-newline at end of file");
} }
while (buffer->cur < buffer->rlimit); while (next == '\\' || next == '?');
if (!is_vspace (next1))
{
RESTORE_STATE ();
break;
}
if (space)
cpp_warning (buffer->pfile,
"backslash and newline separated by space");
next = handle_newline (buffer, next1);
if (next == EOF)
cpp_pedwarn (buffer->pfile, "backslash-newline at end of file");
} }
while (next == '\\' || next == '?');
buffer->read_ahead = next; buffer->read_ahead = next;
return next; return next;
@ -863,8 +869,8 @@ _cpp_lex_token (pfile, result)
{ {
case EOF: case EOF:
/* Non-empty files should end in a newline. Ignore for command /* Non-empty files should end in a newline. Ignore for command
line - we get e.g. -A options with no trailing \n. */ line and _Pragma buffers. */
if (pfile->lexer_pos.col != 0 && pfile->done_initializing) if (pfile->lexer_pos.col != 0 && !buffer->from_stage3)
cpp_pedwarn (pfile, "no newline at end of file"); cpp_pedwarn (pfile, "no newline at end of file");
pfile->state.skip_newlines = 1; pfile->state.skip_newlines = 1;
result->type = CPP_EOF; result->type = CPP_EOF;

View File

@ -99,6 +99,9 @@ static void do_pragma_once PARAMS ((cpp_reader *));
static void do_pragma_poison PARAMS ((cpp_reader *)); static void do_pragma_poison PARAMS ((cpp_reader *));
static void do_pragma_system_header PARAMS ((cpp_reader *)); static void do_pragma_system_header PARAMS ((cpp_reader *));
static void do_pragma_dependency PARAMS ((cpp_reader *)); static void do_pragma_dependency PARAMS ((cpp_reader *));
static int get__Pragma_string PARAMS ((cpp_reader *, cpp_token *));
static unsigned char *destringize PARAMS ((const cpp_string *,
unsigned int *));
static int parse_answer PARAMS ((cpp_reader *, struct answer **, int)); static int parse_answer PARAMS ((cpp_reader *, struct answer **, int));
static cpp_hashnode *parse_assertion PARAMS ((cpp_reader *, struct answer **, static cpp_hashnode *parse_assertion PARAMS ((cpp_reader *, struct answer **,
int)); int));
@ -345,7 +348,7 @@ run_directive (pfile, dir_no, buf, count, name)
size_t count; size_t count;
const char *name; const char *name;
{ {
if (cpp_push_buffer (pfile, (const U_CHAR *)buf, count) != NULL) if (cpp_push_buffer (pfile, (const U_CHAR *) buf, count) != NULL)
{ {
const struct directive *dir = &dtable[dir_no]; const struct directive *dir = &dtable[dir_no];
@ -353,15 +356,27 @@ run_directive (pfile, dir_no, buf, count, name)
CPP_BUFFER (pfile)->nominal_fname = name; CPP_BUFFER (pfile)->nominal_fname = name;
else else
CPP_BUFFER (pfile)->nominal_fname = _("<command line>"); CPP_BUFFER (pfile)->nominal_fname = _("<command line>");
CPP_BUFFER (pfile)->lineno = (unsigned int)-1;
/* A kludge to avoid line markers for _Pragma. */
if (dir_no == T_PRAGMA)
pfile->lexer_pos.output_line = CPP_BUFFER (pfile)->prev->lineno;
/* For _Pragma, the text is passed through preprocessing stage 3
only, i.e. no trigraphs, no escaped newline removal, and no
macro expansion. Do the same for command-line directives. */
pfile->buffer->from_stage3 = 1;
pfile->state.in_directive = 1; pfile->state.in_directive = 1;
pfile->directive = dir; pfile->directive = dir;
pfile->state.prevent_expansion++;
(void) (*dir->handler) (pfile); (void) (*dir->handler) (pfile);
pfile->state.prevent_expansion--;
pfile->directive = 0; pfile->directive = 0;
pfile->state.in_directive = 0; pfile->state.in_directive = 0;
skip_rest_of_line (pfile); skip_rest_of_line (pfile);
if (pfile->buffer->cur != pfile->buffer->rlimit)
cpp_error (pfile, "extra text after end of #%s directive",
dtable[dir_no].name);
cpp_pop_buffer (pfile); cpp_pop_buffer (pfile);
} }
} }
@ -1069,6 +1084,68 @@ do_pragma_dependency (pfile)
} }
} }
/* Check syntax is "(string-literal)". Returns 0 on success. */
static int
get__Pragma_string (pfile, string)
cpp_reader *pfile;
cpp_token *string;
{
cpp_token paren;
cpp_get_token (pfile, &paren);
if (paren.type != CPP_OPEN_PAREN)
return 1;
cpp_get_token (pfile, string);
if (string->type != CPP_STRING && string->type != CPP_WSTRING)
return 1;
cpp_get_token (pfile, &paren);
return paren.type != CPP_CLOSE_PAREN;
}
/* Returns a malloced buffer containing a destringized cpp_string by
removing the first \ of \" and \\ sequences. */
static unsigned char *
destringize (in, len)
const cpp_string *in;
unsigned int *len;
{
const unsigned char *src, *limit;
unsigned char *dest, *result;
dest = result = (unsigned char *) xmalloc (in->len);
for (src = in->text, limit = src + in->len; src < limit;)
{
/* We know there is a character following the backslash. */
if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
src++;
*dest++ = *src++;
}
*len = dest - result;
return result;
}
void
_cpp_do__Pragma (pfile)
cpp_reader *pfile;
{
cpp_token string;
unsigned char *buffer;
unsigned int len;
if (get__Pragma_string (pfile, &string))
{
cpp_error (pfile, "_Pragma takes a parenthesized string literal");
return;
}
buffer = destringize (&string.val.str, &len);
run_directive (pfile, T_PRAGMA, (char *) buffer, len, _("<_Pragma>"));
free ((PTR) buffer);
}
/* Just ignore #sccs, on systems where we define it at all. */ /* Just ignore #sccs, on systems where we define it at all. */
#ifdef SCCS_DIRECTIVE #ifdef SCCS_DIRECTIVE
static void static void
@ -1626,12 +1703,6 @@ cpp_push_buffer (pfile, buffer, length)
return NULL; return NULL;
} }
if (pfile->context->prev)
{
cpp_ice (pfile, "buffer pushed with contexts stacked");
skip_rest_of_line (pfile);
}
new = xobnew (pfile->buffer_ob, cpp_buffer); new = xobnew (pfile->buffer_ob, cpp_buffer);
/* Clears, amongst other things, if_stack and mi_cmacro. */ /* Clears, amongst other things, if_stack and mi_cmacro. */
memset (new, 0, sizeof (cpp_buffer)); memset (new, 0, sizeof (cpp_buffer));
@ -1641,6 +1712,8 @@ cpp_push_buffer (pfile, buffer, length)
new->rlimit = buffer + length; new->rlimit = buffer + length;
new->prev = buf; new->prev = buf;
new->pfile = pfile; new->pfile = pfile;
/* Preprocessed files don't do trigraph and escaped newline processing. */
new->from_stage3 = CPP_OPTION (pfile, preprocessed);
/* No read ahead or extra char initially. */ /* No read ahead or extra char initially. */
new->read_ahead = EOF; new->read_ahead = EOF;
new->extra_char = EOF; new->extra_char = EOF;

View File

@ -287,7 +287,12 @@ struct cpp_buffer
The warning happens only for C89 extended mode with -pedantic on, The warning happens only for C89 extended mode with -pedantic on,
or for -Wtraditional, and only once per file (otherwise it would or for -Wtraditional, and only once per file (otherwise it would
be far too noisy). */ be far too noisy). */
char warned_cplusplus_comments; unsigned char warned_cplusplus_comments;
/* True if we don't process trigraphs and escaped newlines. True
for preprocessed input, command line directives, and _Pragma
buffers. */
unsigned char from_stage3;
}; };
/* Maximum nesting of cpp_buffers. We use a static limit, partly for /* Maximum nesting of cpp_buffers. We use a static limit, partly for
@ -509,6 +514,7 @@ struct spec_nodes
{ {
cpp_hashnode *n_L; /* L"str" */ cpp_hashnode *n_L; /* L"str" */
cpp_hashnode *n_defined; /* defined operator */ cpp_hashnode *n_defined; /* defined operator */
cpp_hashnode *n__Pragma; /* _Pragma operator */
cpp_hashnode *n__STRICT_ANSI__; /* STDC_0_IN_SYSTEM_HEADERS */ cpp_hashnode *n__STRICT_ANSI__; /* STDC_0_IN_SYSTEM_HEADERS */
cpp_hashnode *n__CHAR_UNSIGNED__; /* plain char is unsigned */ cpp_hashnode *n__CHAR_UNSIGNED__; /* plain char is unsigned */
cpp_hashnode *n__VA_ARGS__; /* C99 vararg macros */ cpp_hashnode *n__VA_ARGS__; /* C99 vararg macros */

View File

@ -689,7 +689,8 @@ funlike_invocation_p (pfile, node, list)
/* Push the context of a macro onto the context stack. TOKEN is the /* Push the context of a macro onto the context stack. TOKEN is the
macro name. If we can successfully start expanding the macro, macro name. If we can successfully start expanding the macro,
TOKEN is replaced with the first token of the expansion. */ TOKEN is replaced with the first token of the expansion, and we
return non-zero. */
static int static int
enter_macro_context (pfile, token) enter_macro_context (pfile, token)
cpp_reader *pfile; cpp_reader *pfile;
@ -704,7 +705,7 @@ enter_macro_context (pfile, token)
if (macro->disabled) if (macro->disabled)
{ {
token->flags |= NO_EXPAND; token->flags |= NO_EXPAND;
return 1; return 0;
} }
/* Save the position of the outermost macro invocation. */ /* Save the position of the outermost macro invocation. */
@ -718,7 +719,7 @@ enter_macro_context (pfile, token)
{ {
if (!pfile->context->prev) if (!pfile->context->prev)
unlock_pools (pfile); unlock_pools (pfile);
return 1; return 0;
} }
/* Now push its context. */ /* Now push its context. */
@ -740,7 +741,7 @@ enter_macro_context (pfile, token)
/* Disable the macro within its expansion. */ /* Disable the macro within its expansion. */
macro->disabled = 1; macro->disabled = 1;
return 0; return 1;
} }
/* Move to the next context. Create one if there is none. */ /* Move to the next context. Create one if there is none. */
@ -922,6 +923,7 @@ _cpp_get_token (pfile, token)
cpp_reader *pfile; cpp_reader *pfile;
cpp_token *token; cpp_token *token;
{ {
next_token:
for (;;) for (;;)
{ {
cpp_context *context = pfile->context; cpp_context *context = pfile->context;
@ -959,22 +961,34 @@ _cpp_get_token (pfile, token)
if (token->flags & PASTE_LEFT) if (token->flags & PASTE_LEFT)
paste_all_tokens (pfile, token); paste_all_tokens (pfile, token);
if (token->type != CPP_NAME if (token->type != CPP_NAME)
|| token->val.node->type != NT_MACRO
|| pfile->state.prevent_expansion
|| token->flags & NO_EXPAND)
break; break;
/* Macros, built-in or not, invalidate controlling macros. */ /* Handle macros and the _Pragma operator. */
pfile->mi_state = MI_FAILED; if (token->val.node->type == NT_MACRO
&& !pfile->state.prevent_expansion
if (token->val.node->flags & NODE_BUILTIN) && !(token->flags & NO_EXPAND))
{ {
builtin_macro (pfile, token); /* Macros invalidate controlling macros. */
break; pfile->mi_state = MI_FAILED;
if (token->val.node->flags & NODE_BUILTIN)
{
builtin_macro (pfile, token);
break;
}
if (enter_macro_context (pfile, token))
continue;
} }
else if (enter_macro_context (pfile, token))
if (token->val.node != pfile->spec_nodes.n__Pragma)
break; break;
/* Invalidate controlling macros. */
pfile->mi_state = MI_FAILED;
_cpp_do__Pragma (pfile);
goto next_token;
} }
} }