directives.c (struct pragma_entry): Add is_deferred.

libcpp/
	* directives.c (struct pragma_entry): Add is_deferred.  Add ident
	entry to value union.
	(end_directive): Don't eat the line if in_deferred_pragma.
	(run_directive): Remove pragma hacks.
	(insert_pragma_entry): Remove.
	(new_pragma_entry): New.
	(register_pragma_1): Split out of register_pragma.  Only handle
	the lookup tree and return the new entry.
	(cpp_register_pragma): Fill in the pragma entry here.
	(cpp_register_deferred_pragma): New.
	(register_pragma_internal): New.
	(_cpp_init_internal_pragmas): Use register_pragma_internal.
	(do_pragma): Allow pragma expansion after namespace.  For deferred
	pragmas, don't slurp the line into a string.
	(destringize_and_run): Save tokens for deferred pragmas.
	(cpp_handle_deferred_pragma): Remove.
	* macro.c (builtin_macro): Remove pragma token hack.
	(_cpp_push_token_context): Rename from push_token_context and export.
	* internal.h (struct lexer_state): Add pragma_allow_expansion.
	(_cpp_push_token_context): Declare.
	* lex.c (_cpp_lex_token): Allow _cpp_handle_directive to return
	a token.  Update the line number correctly if so.
	(_cpp_lex_direct): Emit CPP_PRAGMA_EOL tokens.
	(cpp_token_val_index): Return CPP_TOKEN_FLD_PRAGMA for pragmas.
	* include/cpplib.h (PRAGMA_EOL): New.
	(CPP_TOKEN_FLD_PRAGMA): New.
	(struct cpp_token): Add val.pragma.
	(struct cpp_options): Remove defer_pragmas.
	(cpp_handle_deferred_pragma): Remove.
	(cpp_register_deferred_pragma): Declare.

gcc/
	* c-lex.c (c_lex_with_flags) <CPP_PRAGMA>: Smuggle pragma id
	via integer constant.
	(pragma_lex): Remove.
	* c-pch.c (c_common_pch_pragma): Accept the name as an argument,
	rather than parsing it.
	* c-pragma.c (handle_pragma_weak, handle_pragma_redefine_extname,
	handle_pragma_extern_prefix): Add %< %> quotes.
	(registered_pragmas): New.
	(c_register_pragma_1): New.
	(c_register_pragma): Use it.
	(c_register_pragma_with_expansion): Likewise.
	(c_invoke_pragma_handler): New.
	(init_pragma): Use cpp_register_deferred_pragma directly for
	pch_preprocess.
	* c-pragma.h (enum pragma_kind): New.
	(pragma_handler): New.
	(c_invoke_pragma_handler): Declare.
	* c-common.c (c_parse_error): Pretty print CPP_PRAGMA and
	CPP_PRAGMA_EOL.
	* c-common.h (c_common_pch_pragma): Update decl.
	* Makefile.in (c-parser.o): Update dependencies.
	(GTFILES): Add c-pragma.h.
	* c-parser.c (struct c_token): Add pragma_kind.
	(struct c_parser): Add in_pragma.
	(c_lex_one_token): Always initialize keyword and pragma_kind.
	Extract data for CPP_PRAGMA.
	(c_parser_peek_2nd_token): Deny CPP_PRAGMA_EOL.
	(c_parser_consume_token): Don't allow CPP_PRAGMA unless errors.
	Don't allow CPP_PRAGMA_EOL if in_pragma.
	(c_parser_consume_pragma): New.
	(c_parser_skip_until_found): Stop on CPP_PRAGMA_EOL.
	(c_parser_skip_to_end_of_parameter): Likewise.
	(c_parser_skip_to_end_of_block_or_statement): Likewise.
	(c_parser_skip_to_pragma_eol): New.
	(c_parser_external_declaration): Handle CPP_PRAGMA.
	(c_parser_compound_statement_nostart): Likewise.
	(c_parser_statement_after_labels): Likewise.
	(c_parser_pragma): New.
	(pragma_lex): Likewise.
	(c_parser_pragma_pch_preprocess): New.
	(c_parser_new): Merge into ...
	(c_parse_file): ... here.  Call c_parser_pragma_pch_preprocess.

gcc/cp/
	* lex.c (handle_pragma_java_exceptions): Fix whitespace.
	* parser.c (struct cp_token): Add pragma_kind.
	(eof_token): Update to match.
	(struct cp_lexer): Add in_pragma; rearrange next for better packing.
	(cp_parser_initial_pragma): New.
	(cp_lexer_new_main): Use it.  Don't bother clearing
	c_lex_return_raw_strings.
	(cp_lexer_get_preprocessor_token): Always initialize keyword
	and pragma_kind fields.  Handle CPP_PRAGMA.
	(cp_lexer_consume_token): Don't allow CPP_PRAGMA_EOL when 
	in_pragma is set.
	(cp_lexer_handle_pragma): Remove.  Update callers to cp_parser_pragma.
	(cp_lexer_print_token) <CPP_PRAGMA>: Don't print as a string.
	(cp_parser_skip_to_pragma_eol): New.
	(cp_parser_error): Use it.
	(cp_parser_skip_to_closing_parenthesis): Stop at CPP_PRAGMA_EOL;
	rearrange with switch statement.
	(cp_parser_skip_to_end_of_statement): Likewise.
	(cp_parser_skip_to_end_of_block_or_statement): Likewise.
	(cp_parser_skip_to_closing_brace): Likewise.
	(cp_parser_skip_until_found): Likewise.
	(cp_parser_statement): Add in_compound argument; update callers.
	Use it to decide how to handle pragma parsing.
	(cp_parser_labeled_statement): Add in_compound argument; pass
	it on to cp_parser_statement.
	(cp_parser_statement_seq_opt): Stop at CPP_PRAGMA_EOL.
	(cp_parser_declaration_seq_opt): Likewise.
	(cp_parser_parameter_declaration): Likewise.
	(cp_parser_member_specification_opt): Likewise.
	(cp_parser_function_definition_after_decl): Likewise.
	(cp_parser_cache_group): Handle CPP_PRAGMA/CPP_PRAGMA_EOL pairs.
	(cp_parser_pragma): New.
	(pragma_lex): New.

gcc/testsuite/
	* g++.dg/parse/pragma2.C: Update expected error lines.

From-SVN: r109336
This commit is contained in:
Richard Henderson 2006-01-04 08:33:38 -08:00
parent 59bb84ef39
commit bc4071dd66
20 changed files with 992 additions and 498 deletions

View File

@ -1,3 +1,49 @@
2006-01-04 Richard Henderson <rth@redhat.com>
Merge from gomp branch:
* c-lex.c (c_lex_with_flags) <CPP_PRAGMA>: Smuggle pragma id
via integer constant.
(pragma_lex): Remove.
* c-pch.c (c_common_pch_pragma): Accept the name as an argument,
rather than parsing it.
* c-pragma.c (handle_pragma_weak, handle_pragma_redefine_extname,
handle_pragma_extern_prefix): Add %< %> quotes.
(registered_pragmas): New.
(c_register_pragma_1): New.
(c_register_pragma): Use it.
(c_register_pragma_with_expansion): Likewise.
(c_invoke_pragma_handler): New.
(init_pragma): Use cpp_register_deferred_pragma directly for
pch_preprocess.
* c-pragma.h (enum pragma_kind): New.
(pragma_handler): New.
(c_invoke_pragma_handler): Declare.
* c-common.c (c_parse_error): Pretty print CPP_PRAGMA and
CPP_PRAGMA_EOL.
* c-common.h (c_common_pch_pragma): Update decl.
* Makefile.in (c-parser.o): Update dependencies.
(GTFILES): Add c-pragma.h.
* c-parser.c (struct c_token): Add pragma_kind.
(struct c_parser): Add in_pragma.
(c_lex_one_token): Always initialize keyword and pragma_kind.
Extract data for CPP_PRAGMA.
(c_parser_peek_2nd_token): Deny CPP_PRAGMA_EOL.
(c_parser_consume_token): Don't allow CPP_PRAGMA unless errors.
Don't allow CPP_PRAGMA_EOL if in_pragma.
(c_parser_consume_pragma): New.
(c_parser_skip_until_found): Stop on CPP_PRAGMA_EOL.
(c_parser_skip_to_end_of_parameter): Likewise.
(c_parser_skip_to_end_of_block_or_statement): Likewise.
(c_parser_skip_to_pragma_eol): New.
(c_parser_external_declaration): Handle CPP_PRAGMA.
(c_parser_compound_statement_nostart): Likewise.
(c_parser_statement_after_labels): Likewise.
(c_parser_pragma): New.
(pragma_lex): Likewise.
(c_parser_pragma_pch_preprocess): New.
(c_parser_new): Merge into ...
(c_parse_file): ... here. Call c_parser_pragma_pch_preprocess.
2005-01-04 Jeff Law <law@redhat.com> 2005-01-04 Jeff Law <law@redhat.com>
PR ada/24994 PR ada/24994

View File

@ -1516,7 +1516,8 @@ c-errors.o: c-errors.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
$(C_TREE_H) $(FLAGS_H) $(DIAGNOSTIC_H) $(TM_P_H) $(C_TREE_H) $(FLAGS_H) $(DIAGNOSTIC_H) $(TM_P_H)
c-parser.o : c-parser.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ c-parser.o : c-parser.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
$(GGC_H) $(TIMEVAR_H) $(C_TREE_H) input.h $(FLAGS_H) toplev.h output.h \ $(GGC_H) $(TIMEVAR_H) $(C_TREE_H) input.h $(FLAGS_H) toplev.h output.h \
$(CPPLIB_H) gt-c-parser.h langhooks.h $(C_COMMON_H) $(C_PRAGMA_H) $(CPPLIB_H) gt-c-parser.h langhooks.h $(C_COMMON_H) $(C_PRAGMA_H) \
vec.h $(TARGET_H)
srcextra: gcc.srcextra lang.srcextra srcextra: gcc.srcextra lang.srcextra
@ -2811,6 +2812,7 @@ GTFILES = $(srcdir)/input.h $(srcdir)/coretypes.h \
$(srcdir)/tree-profile.c $(srcdir)/tree-nested.c \ $(srcdir)/tree-profile.c $(srcdir)/tree-nested.c \
$(srcdir)/ipa-reference.c $(srcdir)/tree-ssa-structalias.h \ $(srcdir)/ipa-reference.c $(srcdir)/tree-ssa-structalias.h \
$(srcdir)/tree-ssa-structalias.c \ $(srcdir)/tree-ssa-structalias.c \
$(srcdir)/c-pragma.h \
$(srcdir)/targhooks.c $(out_file) \ $(srcdir)/targhooks.c $(out_file) \
@all_gtfiles@ @all_gtfiles@

View File

@ -5803,6 +5803,10 @@ c_parse_error (const char *gmsgid, enum cpp_ttype token, tree value)
free (message); free (message);
message = NULL; message = NULL;
} }
else if (token == CPP_PRAGMA)
message = catenate_messages (gmsgid, " before %<#pragma%>");
else if (token == CPP_PRAGMA_EOL)
message = catenate_messages (gmsgid, " before end of line");
else if (token < N_TTYPES) else if (token < N_TTYPES)
{ {
message = catenate_messages (gmsgid, " before %qs token"); message = catenate_messages (gmsgid, " before %qs token");

View File

@ -854,7 +854,7 @@ extern void c_common_read_pch (cpp_reader *pfile, const char *name, int fd,
const char *orig); const char *orig);
extern void c_common_write_pch (void); extern void c_common_write_pch (void);
extern void c_common_no_more_pch (void); extern void c_common_no_more_pch (void);
extern void c_common_pch_pragma (cpp_reader *pfile); extern void c_common_pch_pragma (cpp_reader *pfile, const char *);
extern void c_common_print_pch_checksum (FILE *f); extern void c_common_print_pch_checksum (FILE *f);
/* In *-checksum.c */ /* In *-checksum.c */

View File

@ -458,11 +458,11 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags)
type = lex_string (tok, value, false); type = lex_string (tok, value, false);
break; break;
} }
*value = build_string (tok->val.str.len, (char *) tok->val.str.text);
/* FALLTHROUGH */ break;
case CPP_PRAGMA: case CPP_PRAGMA:
*value = build_string (tok->val.str.len, (char *) tok->val.str.text); *value = build_int_cst (NULL, tok->val.pragma);
break; break;
/* These tokens should not be visible outside cpplib. */ /* These tokens should not be visible outside cpplib. */
@ -490,13 +490,6 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags)
return type; return type;
} }
enum cpp_ttype
pragma_lex (tree *value)
{
location_t loc;
return c_lex_with_flags (value, &loc, NULL);
}
/* Returns the narrowest C-visible unsigned type, starting with the /* Returns the narrowest C-visible unsigned type, starting with the
minimum specified by FLAGS, that can fit HIGH:LOW, or itk_none if minimum specified by FLAGS, that can fit HIGH:LOW, or itk_none if
there isn't one. */ there isn't one. */

View File

@ -42,6 +42,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#include "coretypes.h" #include "coretypes.h"
#include "tm.h" #include "tm.h"
#include "tree.h" #include "tree.h"
#include "rtl.h"
#include "langhooks.h" #include "langhooks.h"
#include "input.h" #include "input.h"
#include "cpplib.h" #include "cpplib.h"
@ -53,6 +54,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#include "toplev.h" #include "toplev.h"
#include "ggc.h" #include "ggc.h"
#include "c-common.h" #include "c-common.h"
#include "vec.h"
#include "target.h"
/* Miscellaneous data and functions needed for the parser. */ /* Miscellaneous data and functions needed for the parser. */
@ -266,6 +269,9 @@ typedef struct c_token GTY (())
/* If this token is a keyword, this value indicates which keyword. /* If this token is a keyword, this value indicates which keyword.
Otherwise, this value is RID_MAX. */ Otherwise, this value is RID_MAX. */
ENUM_BITFIELD (rid) keyword : 8; ENUM_BITFIELD (rid) keyword : 8;
/* If this token is a CPP_PRAGMA, this indicates the pragma that
was seen. Otherwise it is PRAGMA_NONE. */
ENUM_BITFIELD (pragma_kind) pragma_kind : 7;
/* True if this token is from a system header. */ /* True if this token is from a system header. */
BOOL_BITFIELD in_system_header : 1; BOOL_BITFIELD in_system_header : 1;
/* The value associated with this token, if any. */ /* The value associated with this token, if any. */
@ -287,21 +293,34 @@ typedef struct c_parser GTY(())
c_parser_error sets this flag. It should clear this flag when c_parser_error sets this flag. It should clear this flag when
enough tokens have been consumed to recover from the error. */ enough tokens have been consumed to recover from the error. */
BOOL_BITFIELD error : 1; BOOL_BITFIELD error : 1;
/* True if we're processing a pragma, and shouldn't automatically
consume CPP_PRAGMA_EOL. */
BOOL_BITFIELD in_pragma : 1;
} c_parser; } c_parser;
/* The actual parser and external interface. ??? Does this need to be
garbage-collected? */
static GTY (()) c_parser *the_parser;
/* Read in and lex a single token, storing it in *TOKEN. */ /* Read in and lex a single token, storing it in *TOKEN. */
static void static void
c_lex_one_token (c_token *token) c_lex_one_token (c_token *token)
{ {
timevar_push (TV_LEX); timevar_push (TV_LEX);
token->type = c_lex_with_flags (&token->value, &token->location, NULL); token->type = c_lex_with_flags (&token->value, &token->location, NULL);
token->id_kind = C_ID_NONE;
token->keyword = RID_MAX;
token->pragma_kind = PRAGMA_NONE;
token->in_system_header = in_system_header; token->in_system_header = in_system_header;
switch (token->type) switch (token->type)
{ {
case CPP_NAME: case CPP_NAME:
token->id_kind = C_ID_NONE;
token->keyword = RID_MAX;
{ {
tree decl; tree decl;
@ -358,13 +377,12 @@ c_lex_one_token (c_token *token)
break; break;
} }
} }
token->id_kind = C_ID_ID;
} }
token->id_kind = C_ID_ID;
break; break;
case CPP_AT_NAME: case CPP_AT_NAME:
/* This only happens in Objective-C; it must be a keyword. */ /* This only happens in Objective-C; it must be a keyword. */
token->type = CPP_KEYWORD; token->type = CPP_KEYWORD;
token->id_kind = C_ID_NONE;
token->keyword = C_RID_CODE (token->value); token->keyword = C_RID_CODE (token->value);
break; break;
case CPP_COLON: case CPP_COLON:
@ -374,12 +392,13 @@ c_lex_one_token (c_token *token)
/* These tokens may affect the interpretation of any identifiers /* These tokens may affect the interpretation of any identifiers
following, if doing Objective-C. */ following, if doing Objective-C. */
OBJC_NEED_RAW_IDENTIFIER (0); OBJC_NEED_RAW_IDENTIFIER (0);
token->id_kind = C_ID_NONE; break;
token->keyword = RID_MAX; case CPP_PRAGMA:
/* We smuggled the cpp_token->u.pragma value in an INTEGER_CST. */
token->pragma_kind = TREE_INT_CST_LOW (token->value);
token->value = NULL;
break; break;
default: default:
token->id_kind = C_ID_NONE;
token->keyword = RID_MAX;
break; break;
} }
timevar_pop (TV_LEX); timevar_pop (TV_LEX);
@ -582,6 +601,7 @@ c_parser_peek_2nd_token (c_parser *parser)
return &parser->tokens[1]; return &parser->tokens[1];
gcc_assert (parser->tokens_avail == 1); gcc_assert (parser->tokens_avail == 1);
gcc_assert (parser->tokens[0].type != CPP_EOF); gcc_assert (parser->tokens[0].type != CPP_EOF);
gcc_assert (parser->tokens[0].type != CPP_PRAGMA_EOL);
c_lex_one_token (&parser->tokens[1]); c_lex_one_token (&parser->tokens[1]);
parser->tokens_avail = 2; parser->tokens_avail = 2;
return &parser->tokens[1]; return &parser->tokens[1];
@ -592,16 +612,30 @@ c_parser_peek_2nd_token (c_parser *parser)
static void static void
c_parser_consume_token (c_parser *parser) c_parser_consume_token (c_parser *parser)
{ {
gcc_assert (parser->tokens_avail >= 1);
gcc_assert (parser->tokens[0].type != CPP_EOF);
gcc_assert (!parser->in_pragma || parser->tokens[0].type != CPP_PRAGMA_EOL);
gcc_assert (parser->error || parser->tokens[0].type != CPP_PRAGMA);
if (parser->tokens_avail == 2) if (parser->tokens_avail == 2)
parser->tokens[0] = parser->tokens[1]; parser->tokens[0] = parser->tokens[1];
else
{
gcc_assert (parser->tokens_avail == 1);
gcc_assert (parser->tokens[0].type != CPP_EOF);
}
parser->tokens_avail--; parser->tokens_avail--;
} }
/* Expect the current token to be a #pragma. Consume it and remember
that we've begun parsing a pragma. */
static void
c_parser_consume_pragma (c_parser *parser)
{
gcc_assert (!parser->in_pragma);
gcc_assert (parser->tokens_avail >= 1);
gcc_assert (parser->tokens[0].type == CPP_PRAGMA);
if (parser->tokens_avail == 2)
parser->tokens[0] = parser->tokens[1];
parser->tokens_avail--;
parser->in_pragma = true;
}
/* Update the globals input_location and in_system_header from /* Update the globals input_location and in_system_header from
TOKEN. */ TOKEN. */
static inline void static inline void
@ -614,23 +648,6 @@ c_parser_set_source_position_from_token (c_token *token)
} }
} }
/* Allocate a new parser. */
static c_parser *
c_parser_new (void)
{
/* Use local storage to lex the first token because loading a PCH
file may cause garbage collection. */
c_parser tparser;
c_parser *ret;
memset (&tparser, 0, sizeof tparser);
c_lex_one_token (&tparser.tokens[0]);
tparser.tokens_avail = 1;
ret = GGC_NEW (c_parser);
memcpy (ret, &tparser, sizeof tparser);
return ret;
}
/* Issue a diagnostic of the form /* Issue a diagnostic of the form
FILE:LINE: MESSAGE before TOKEN FILE:LINE: MESSAGE before TOKEN
where TOKEN is the next token in the input stream of PARSER. where TOKEN is the next token in the input stream of PARSER.
@ -732,9 +749,12 @@ c_parser_skip_until_found (c_parser *parser,
c_parser_consume_token (parser); c_parser_consume_token (parser);
break; break;
} }
/* If we've run out of tokens, stop. */ /* If we've run out of tokens, stop. */
if (token->type == CPP_EOF) if (token->type == CPP_EOF)
return; return;
if (token->type == CPP_PRAGMA_EOL && parser->in_pragma)
return;
if (token->type == CPP_OPEN_BRACE if (token->type == CPP_OPEN_BRACE
|| token->type == CPP_OPEN_PAREN || token->type == CPP_OPEN_PAREN
|| token->type == CPP_OPEN_SQUARE) || token->type == CPP_OPEN_SQUARE)
@ -769,6 +789,8 @@ c_parser_skip_to_end_of_parameter (c_parser *parser)
/* If we've run out of tokens, stop. */ /* If we've run out of tokens, stop. */
if (token->type == CPP_EOF) if (token->type == CPP_EOF)
return; return;
if (token->type == CPP_PRAGMA_EOL && parser->in_pragma)
return;
if (token->type == CPP_OPEN_BRACE if (token->type == CPP_OPEN_BRACE
|| token->type == CPP_OPEN_PAREN || token->type == CPP_OPEN_PAREN
|| token->type == CPP_OPEN_SQUARE) || token->type == CPP_OPEN_SQUARE)
@ -803,6 +825,8 @@ c_parser_skip_to_end_of_block_or_statement (c_parser *parser)
/* If we've run out of tokens, stop. */ /* If we've run out of tokens, stop. */
if (token->type == CPP_EOF) if (token->type == CPP_EOF)
return; return;
if (token->type == CPP_PRAGMA_EOL && parser->in_pragma)
return;
/* If the next token is a ';', we have reached the end of the /* If the next token is a ';', we have reached the end of the
statement. */ statement. */
if (token->type == CPP_SEMICOLON && !nesting_depth) if (token->type == CPP_SEMICOLON && !nesting_depth)
@ -828,6 +852,31 @@ c_parser_skip_to_end_of_block_or_statement (c_parser *parser)
parser->error = false; parser->error = false;
} }
/* Expect to be at the end of the pragma directive and consume an
end of line marker. */
static void
c_parser_skip_to_pragma_eol (c_parser *parser)
{
gcc_assert (parser->in_pragma);
parser->in_pragma = false;
if (!c_parser_require (parser, CPP_PRAGMA_EOL, "expected end of line"))
while (true)
{
c_token *token = c_parser_peek_token (parser);
if (token->type == CPP_EOF)
break;
if (token->type == CPP_PRAGMA_EOL)
{
c_parser_consume_token (parser);
break;
}
c_parser_consume_token (parser);
}
parser->error = false;
}
/* Save the warning flags which are controlled by __extension__. */ /* Save the warning flags which are controlled by __extension__. */
@ -932,6 +981,9 @@ static struct c_expr c_parser_expression (c_parser *);
static struct c_expr c_parser_expression_conv (c_parser *); static struct c_expr c_parser_expression_conv (c_parser *);
static tree c_parser_expr_list (c_parser *, bool); static tree c_parser_expr_list (c_parser *, bool);
enum pragma_context { pragma_external, pragma_stmt, pragma_compound };
static bool c_parser_pragma (c_parser *, enum pragma_context);
/* These Objective-C parser functions are only ever called when /* These Objective-C parser functions are only ever called when
compiling Objective-C. */ compiling Objective-C. */
static void c_parser_objc_class_definition (c_parser *); static void c_parser_objc_class_definition (c_parser *);
@ -1063,6 +1115,9 @@ c_parser_external_declaration (c_parser *parser)
pedwarn ("ISO C does not allow extra %<;%> outside of a function"); pedwarn ("ISO C does not allow extra %<;%> outside of a function");
c_parser_consume_token (parser); c_parser_consume_token (parser);
break; break;
case CPP_PRAGMA:
c_parser_pragma (parser, pragma_external);
break;
case CPP_PLUS: case CPP_PLUS:
case CPP_MINUS: case CPP_MINUS:
if (c_dialect_objc ()) if (c_dialect_objc ())
@ -1082,6 +1137,7 @@ c_parser_external_declaration (c_parser *parser)
} }
} }
/* Parse a declaration or function definition (C90 6.5, 6.7.1, C99 /* Parse a declaration or function definition (C90 6.5, 6.7.1, C99
6.7, 6.9.1). If FNDEF_OK is true, a function definition is 6.7, 6.9.1). If FNDEF_OK is true, a function definition is
accepted; otherwise (old-style parameter declarations) only other accepted; otherwise (old-style parameter declarations) only other
@ -1142,6 +1198,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_ok,
tree prefix_attrs; tree prefix_attrs;
tree all_prefix_attrs; tree all_prefix_attrs;
bool diagnosed_no_specs = false; bool diagnosed_no_specs = false;
specs = build_null_declspecs (); specs = build_null_declspecs ();
c_parser_declspecs (parser, specs, true, true, start_attr_ok); c_parser_declspecs (parser, specs, true, true, start_attr_ok);
if (parser->error) if (parser->error)
@ -1808,6 +1865,12 @@ c_parser_struct_or_union_specifier (c_parser *parser)
c_parser_consume_token (parser); c_parser_consume_token (parser);
break; break;
} }
/* Accept #pragmas at struct scope. */
if (c_parser_next_token_is (parser, CPP_PRAGMA))
{
c_parser_pragma (parser, pragma_external);
continue;
}
/* Parse some comma-separated declarations, but not the /* Parse some comma-separated declarations, but not the
trailing semicolon if any. */ trailing semicolon if any. */
decls = c_parser_struct_declaration (parser); decls = c_parser_struct_declaration (parser);
@ -3268,11 +3331,6 @@ c_parser_compound_statement_nostart (c_parser *parser)
while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE)) while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE))
{ {
location_t loc = c_parser_peek_token (parser)->location; location_t loc = c_parser_peek_token (parser)->location;
if (c_parser_next_token_is (parser, CPP_EOF))
{
c_parser_error (parser, "expected declaration or statement");
return;
}
if (c_parser_next_token_is_keyword (parser, RID_CASE) if (c_parser_next_token_is_keyword (parser, RID_CASE)
|| c_parser_next_token_is_keyword (parser, RID_DEFAULT) || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
|| (c_parser_next_token_is (parser, CPP_NAME) || (c_parser_next_token_is (parser, CPP_NAME)
@ -3325,6 +3383,21 @@ c_parser_compound_statement_nostart (c_parser *parser)
else else
goto statement; goto statement;
} }
else if (c_parser_next_token_is (parser, CPP_PRAGMA))
{
/* External pragmas, and some omp pragmas, are not associated
with regular c code, and so are not to be considered statements
syntactically. This ensures that the user doesn't put them
places that would turn into syntax errors if the directive
were ignored. */
if (c_parser_pragma (parser, pragma_compound))
last_label = false, last_stmt = true;
}
else if (c_parser_next_token_is (parser, CPP_EOF))
{
c_parser_error (parser, "expected declaration or statement");
return;
}
else else
{ {
statement: statement:
@ -3578,6 +3651,9 @@ c_parser_statement_after_labels (c_parser *parser)
c_parser_error (parser, "expected statement"); c_parser_error (parser, "expected statement");
c_parser_consume_token (parser); c_parser_consume_token (parser);
break; break;
case CPP_PRAGMA:
c_parser_pragma (parser, pragma_stmt);
break;
default: default:
expr_stmt: expr_stmt:
stmt = c_finish_expr_stmt (c_parser_expression_conv (parser).value); stmt = c_finish_expr_stmt (c_parser_expression_conv (parser).value);
@ -5558,6 +5634,12 @@ c_parser_objc_class_instance_variables (c_parser *parser)
objc_set_visibility (1); objc_set_visibility (1);
continue; continue;
} }
else if (c_parser_next_token_is (parser, CPP_PRAGMA))
{
c_parser_pragma (parser, pragma_external);
continue;
}
/* Parse some comma-separated declarations. */ /* Parse some comma-separated declarations. */
decls = c_parser_struct_declaration (parser); decls = c_parser_struct_declaration (parser);
{ {
@ -6262,17 +6344,101 @@ c_parser_objc_keywordexpr (c_parser *parser)
} }
/* The actual parser and external interface. ??? Does this need to be /* Handle pragmas. ALLOW_STMT is true if we're within the context of
garbage-collected? */ a function and such pragmas are to be allowed. Returns true if we
actually parsed such a pragma. */
static GTY (()) c_parser *the_parser; static bool
c_parser_pragma (c_parser *parser, enum pragma_context context ATTRIBUTE_UNUSED)
{
unsigned int id;
id = c_parser_peek_token (parser)->pragma_kind;
gcc_assert (id != PRAGMA_NONE);
switch (id)
{
case PRAGMA_GCC_PCH_PREPROCESS:
c_parser_error (parser, "%<#pragma GCC pch_preprocess%> must be first");
c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
return false;
default:
gcc_assert (id >= PRAGMA_FIRST_EXTERNAL);
break;
}
c_parser_consume_pragma (parser);
c_invoke_pragma_handler (id);
/* Skip to EOL, but suppress any error message. Those will have been
generated by the handler routine through calling error, as opposed
to calling c_parser_error. */
parser->error = true;
c_parser_skip_to_pragma_eol (parser);
return false;
}
/* The interface the pragma parsers have to the lexer. */
enum cpp_ttype
pragma_lex (tree *value)
{
c_token *tok = c_parser_peek_token (the_parser);
enum cpp_ttype ret = tok->type;
*value = tok->value;
if (ret == CPP_PRAGMA_EOL || ret == CPP_EOF)
ret = CPP_EOF;
else
{
if (ret == CPP_KEYWORD)
ret = CPP_NAME;
c_parser_consume_token (the_parser);
}
return ret;
}
static void
c_parser_pragma_pch_preprocess (c_parser *parser)
{
tree name = NULL;
c_parser_consume_pragma (parser);
if (c_parser_next_token_is (parser, CPP_STRING))
{
name = c_parser_peek_token (parser)->value;
c_parser_consume_token (parser);
}
else
c_parser_error (parser, "expected string literal");
c_parser_skip_to_pragma_eol (parser);
if (name)
c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name));
}
/* Parse a single source file. */ /* Parse a single source file. */
void void
c_parse_file (void) c_parse_file (void)
{ {
the_parser = c_parser_new (); /* Use local storage to begin. If the first token is a pragma, parse it.
If it is #pragma GCC pch_preprocess, then this will load a PCH file
which will cause garbage collection. */
c_parser tparser;
memset (&tparser, 0, sizeof tparser);
the_parser = &tparser;
if (c_parser_peek_token (&tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS)
c_parser_pragma_pch_preprocess (&tparser);
the_parser = GGC_NEW (c_parser);
*the_parser = tparser;
c_parser_translation_unit (the_parser); c_parser_translation_unit (the_parser);
the_parser = NULL; the_parser = NULL;
} }

View File

@ -441,18 +441,10 @@ c_common_no_more_pch (void)
#endif #endif
void void
c_common_pch_pragma (cpp_reader *pfile) c_common_pch_pragma (cpp_reader *pfile, const char *name)
{ {
tree name_t;
const char *name;
int fd; int fd;
if (pragma_lex (&name_t) != CPP_STRING)
{
error ("malformed #pragma GCC pch_preprocess, ignored");
return;
}
if (!cpp_get_options (pfile)->preprocessed) if (!cpp_get_options (pfile)->preprocessed)
{ {
error ("pch_preprocess pragma should only be used with -fpreprocessed"); error ("pch_preprocess pragma should only be used with -fpreprocessed");
@ -460,8 +452,6 @@ c_common_pch_pragma (cpp_reader *pfile)
return; return;
} }
name = TREE_STRING_POINTER (name_t);
fd = open (name, O_RDONLY | O_BINARY, 0666); fd = open (name, O_RDONLY | O_BINARY, 0666);
if (fd == -1) if (fd == -1)
fatal_error ("%s: couldn%'t open PCH file: %m", name); fatal_error ("%s: couldn%'t open PCH file: %m", name);

View File

@ -37,6 +37,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#include "vec.h" #include "vec.h"
#include "target.h" #include "target.h"
#define GCC_BAD(gmsgid) \ #define GCC_BAD(gmsgid) \
do { warning (OPT_Wpragmas, gmsgid); return; } while (0) do { warning (OPT_Wpragmas, gmsgid); return; } while (0)
#define GCC_BAD2(gmsgid, arg) \ #define GCC_BAD2(gmsgid, arg) \
@ -343,7 +344,7 @@ handle_pragma_weak (cpp_reader * ARG_UNUSED (dummy))
t = pragma_lex (&x); t = pragma_lex (&x);
} }
if (t != CPP_EOF) if (t != CPP_EOF)
warning (OPT_Wpragmas, "junk at end of #pragma weak"); warning (OPT_Wpragmas, "junk at end of %<#pragma weak%>");
decl = identifier_global_value (name); decl = identifier_global_value (name);
if (decl && DECL_P (decl)) if (decl && DECL_P (decl))
@ -416,7 +417,7 @@ handle_pragma_redefine_extname (cpp_reader * ARG_UNUSED (dummy))
GCC_BAD ("malformed #pragma redefine_extname, ignored"); GCC_BAD ("malformed #pragma redefine_extname, ignored");
t = pragma_lex (&x); t = pragma_lex (&x);
if (t != CPP_EOF) if (t != CPP_EOF)
warning (OPT_Wpragmas, "junk at end of #pragma redefine_extname"); warning (OPT_Wpragmas, "junk at end of %<#pragma redefine_extname%>");
if (!flag_mudflap && !targetm.handle_pragma_redefine_extname) if (!flag_mudflap && !targetm.handle_pragma_redefine_extname)
{ {
@ -484,7 +485,7 @@ handle_pragma_extern_prefix (cpp_reader * ARG_UNUSED (dummy))
GCC_BAD ("malformed #pragma extern_prefix, ignored"); GCC_BAD ("malformed #pragma extern_prefix, ignored");
t = pragma_lex (&x); t = pragma_lex (&x);
if (t != CPP_EOF) if (t != CPP_EOF)
warning (OPT_Wpragmas, "junk at end of #pragma extern_prefix"); warning (OPT_Wpragmas, "junk at end of %<#pragma extern_prefix%>");
if (targetm.handle_pragma_extern_prefix) if (targetm.handle_pragma_extern_prefix)
/* Note that the length includes the null terminator. */ /* Note that the length includes the null terminator. */
@ -667,26 +668,65 @@ handle_pragma_visibility (cpp_reader *dummy ATTRIBUTE_UNUSED)
#endif #endif
/* A vector of registered pragma callbacks. */
DEF_VEC_O (pragma_handler);
DEF_VEC_ALLOC_O (pragma_handler, heap);
static VEC(pragma_handler, heap) *registered_pragmas;
/* Front-end wrappers for pragma registration to avoid dragging /* Front-end wrappers for pragma registration to avoid dragging
cpplib.h in almost everywhere. */ cpplib.h in almost everywhere. */
void
c_register_pragma (const char *space, const char *name, static void
void (*handler) (struct cpp_reader *)) c_register_pragma_1 (const char *space, const char *name,
pragma_handler handler, bool allow_expansion)
{ {
cpp_register_pragma (parse_in, space, name, handler, 0); unsigned id;
VEC_safe_push (pragma_handler, heap, registered_pragmas, &handler);
id = VEC_length (pragma_handler, registered_pragmas);
id += PRAGMA_FIRST_EXTERNAL - 1;
/* The C++ front end allocates 6 bits in cp_token; the C front end
allocates 7 bits in c_token. At present this is sufficient. */
gcc_assert (id < 64);
cpp_register_deferred_pragma (parse_in, space, name, id,
allow_expansion, false);
}
void
c_register_pragma (const char *space, const char *name, pragma_handler handler)
{
c_register_pragma_1 (space, name, handler, false);
} }
void void
c_register_pragma_with_expansion (const char *space, const char *name, c_register_pragma_with_expansion (const char *space, const char *name,
void (*handler) (struct cpp_reader *)) pragma_handler handler)
{ {
cpp_register_pragma (parse_in, space, name, handler, 1); c_register_pragma_1 (space, name, handler, true);
}
void
c_invoke_pragma_handler (unsigned int id)
{
pragma_handler handler;
id -= PRAGMA_FIRST_EXTERNAL;
handler = *VEC_index (pragma_handler, registered_pragmas, id);
handler (parse_in);
} }
/* Set up front-end pragmas. */ /* Set up front-end pragmas. */
void void
init_pragma (void) init_pragma (void)
{ {
cpp_register_deferred_pragma (parse_in, "GCC", "pch_preprocess",
PRAGMA_GCC_PCH_PREPROCESS, false, false);
#ifdef HANDLE_PRAGMA_PACK #ifdef HANDLE_PRAGMA_PACK
#ifdef HANDLE_PRAGMA_PACK_WITH_EXPANSION #ifdef HANDLE_PRAGMA_PACK_WITH_EXPANSION
c_register_pragma_with_expansion (0, "pack", handle_pragma_pack); c_register_pragma_with_expansion (0, "pack", handle_pragma_pack);
@ -704,8 +744,6 @@ init_pragma (void)
c_register_pragma (0, "redefine_extname", handle_pragma_redefine_extname); c_register_pragma (0, "redefine_extname", handle_pragma_redefine_extname);
c_register_pragma (0, "extern_prefix", handle_pragma_extern_prefix); c_register_pragma (0, "extern_prefix", handle_pragma_extern_prefix);
c_register_pragma ("GCC", "pch_preprocess", c_common_pch_pragma);
#ifdef REGISTER_TARGET_PRAGMAS #ifdef REGISTER_TARGET_PRAGMAS
REGISTER_TARGET_PRAGMAS (); REGISTER_TARGET_PRAGMAS ();
#endif #endif

View File

@ -24,6 +24,16 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#include <cpplib.h> /* For enum cpp_ttype. */ #include <cpplib.h> /* For enum cpp_ttype. */
/* Pragma identifiers built in to the front end parsers. Identifiers
for anciliary handlers will follow these. */
typedef enum pragma_kind {
PRAGMA_NONE = 0,
PRAGMA_GCC_PCH_PREPROCESS,
PRAGMA_FIRST_EXTERNAL
} pragma_kind;
/* Cause the `yydebug' variable to be defined. */ /* Cause the `yydebug' variable to be defined. */
#define YYDEBUG 1 #define YYDEBUG 1
extern int yydebug; extern int yydebug;
@ -53,18 +63,23 @@ extern struct cpp_reader* parse_in;
extern void init_pragma (void); extern void init_pragma (void);
/* Front-end wrappers for pragma registration to avoid dragging /* Front-end wrappers for pragma registration. */
cpplib.h in almost everywhere. */ typedef void (*pragma_handler)(struct cpp_reader *);
extern void c_register_pragma (const char *, const char *, extern void c_register_pragma (const char *, const char *, pragma_handler);
void (*) (struct cpp_reader *));
extern void c_register_pragma_with_expansion (const char *, const char *, extern void c_register_pragma_with_expansion (const char *, const char *,
void (*) (struct cpp_reader *)); pragma_handler);
extern void c_invoke_pragma_handler (unsigned int);
extern void maybe_apply_pragma_weak (tree); extern void maybe_apply_pragma_weak (tree);
extern void maybe_apply_pending_pragma_weaks (void); extern void maybe_apply_pending_pragma_weaks (void);
extern tree maybe_apply_renaming_pragma (tree, tree); extern tree maybe_apply_renaming_pragma (tree, tree);
extern void add_to_renaming_pragma_list (tree, tree); extern void add_to_renaming_pragma_list (tree, tree);
extern enum cpp_ttype pragma_lex (tree *); extern enum cpp_ttype pragma_lex (tree *);
/* This is not actually available to pragma parsers. It's merely a
convenient location to declare this function for c-lex, after
having enum cpp_ttype declared. */
extern enum cpp_ttype c_lex_with_flags (tree *, location_t *, unsigned char *); extern enum cpp_ttype c_lex_with_flags (tree *, location_t *, unsigned char *);
/* If 1, then lex strings into the execution character set. /* If 1, then lex strings into the execution character set.

View File

@ -1,4 +1,41 @@
2002-01-04 Dirk Mueller <dmueller@suse.com> 2006-01-04 Richard Henderson <rth@redhat.com>
Merge from gomp branch.
* lex.c (handle_pragma_java_exceptions): Fix whitespace.
* parser.c (struct cp_token): Add pragma_kind.
(eof_token): Update to match.
(struct cp_lexer): Add in_pragma; rearrange next for better packing.
(cp_parser_initial_pragma): New.
(cp_lexer_new_main): Use it. Don't bother clearing
c_lex_return_raw_strings.
(cp_lexer_get_preprocessor_token): Always initialize keyword
and pragma_kind fields. Handle CPP_PRAGMA.
(cp_lexer_consume_token): Don't allow CPP_PRAGMA_EOL when
in_pragma is set.
(cp_lexer_handle_pragma): Remove. Update callers to cp_parser_pragma.
(cp_lexer_print_token) <CPP_PRAGMA>: Don't print as a string.
(cp_parser_skip_to_pragma_eol): New.
(cp_parser_error): Use it.
(cp_parser_skip_to_closing_parenthesis): Stop at CPP_PRAGMA_EOL;
rearrange with switch statement.
(cp_parser_skip_to_end_of_statement): Likewise.
(cp_parser_skip_to_end_of_block_or_statement): Likewise.
(cp_parser_skip_to_closing_brace): Likewise.
(cp_parser_skip_until_found): Likewise.
(cp_parser_statement): Add in_compound argument; update callers.
Use it to decide how to handle pragma parsing.
(cp_parser_labeled_statement): Add in_compound argument; pass
it on to cp_parser_statement.
(cp_parser_statement_seq_opt): Stop at CPP_PRAGMA_EOL.
(cp_parser_declaration_seq_opt): Likewise.
(cp_parser_parameter_declaration): Likewise.
(cp_parser_member_specification_opt): Likewise.
(cp_parser_function_definition_after_decl): Likewise.
(cp_parser_cache_group): Handle CPP_PRAGMA/CPP_PRAGMA_EOL pairs.
(cp_parser_pragma): New.
(pragma_lex): New.
2006-01-04 Dirk Mueller <dmueller@suse.com>
* decl.c (finish_constructor_body): create simple * decl.c (finish_constructor_body): create simple
compound stmt instead of a if(1) { } construct. compound stmt instead of a if(1) { } construct.

View File

@ -580,7 +580,7 @@ handle_pragma_implementation (cpp_reader* dfile ATTRIBUTE_UNUSED )
/* Indicate that this file uses Java-personality exception handling. */ /* Indicate that this file uses Java-personality exception handling. */
static void static void
handle_pragma_java_exceptions (cpp_reader* dfile ATTRIBUTE_UNUSED ) handle_pragma_java_exceptions (cpp_reader* dfile ATTRIBUTE_UNUSED)
{ {
tree x; tree x;
if (pragma_lex (&x) != CPP_EOF) if (pragma_lex (&x) != CPP_EOF)

View File

@ -55,6 +55,8 @@ typedef struct cp_token GTY (())
ENUM_BITFIELD (rid) keyword : 8; ENUM_BITFIELD (rid) keyword : 8;
/* Token flags. */ /* Token flags. */
unsigned char flags; unsigned char flags;
/* Identifier for the pragma. */
ENUM_BITFIELD (pragma_kind) pragma_kind : 6;
/* True if this token is from a system header. */ /* True if this token is from a system header. */
BOOL_BITFIELD in_system_header : 1; BOOL_BITFIELD in_system_header : 1;
/* True if this token is from a context where it is implicitly extern "C" */ /* True if this token is from a context where it is implicitly extern "C" */
@ -76,7 +78,7 @@ DEF_VEC_ALLOC_P (cp_token_position,heap);
static const cp_token eof_token = static const cp_token eof_token =
{ {
CPP_EOF, RID_MAX, 0, 0, 0, false, NULL_TREE, CPP_EOF, RID_MAX, 0, PRAGMA_NONE, 0, 0, false, NULL_TREE,
#if USE_MAPPED_LOCATION #if USE_MAPPED_LOCATION
0 0
#else #else
@ -112,11 +114,15 @@ typedef struct cp_lexer GTY (())
tokens. */ tokens. */
VEC(cp_token_position,heap) *GTY ((skip)) saved_tokens; VEC(cp_token_position,heap) *GTY ((skip)) saved_tokens;
/* The next lexer in a linked list of lexers. */
struct cp_lexer *next;
/* True if we should output debugging information. */ /* True if we should output debugging information. */
bool debugging_p; bool debugging_p;
/* The next lexer in a linked list of lexers. */ /* True if we're in the context of parsing a pragma, and should not
struct cp_lexer *next; increment past the end-of-line marker. */
bool in_pragma;
} cp_lexer; } cp_lexer;
/* cp_token_cache is a range of tokens. There is no need to represent /* cp_token_cache is a range of tokens. There is no need to represent
@ -166,8 +172,6 @@ static void cp_lexer_purge_token
(cp_lexer *); (cp_lexer *);
static void cp_lexer_purge_tokens_after static void cp_lexer_purge_tokens_after
(cp_lexer *, cp_token_position); (cp_lexer *, cp_token_position);
static void cp_lexer_handle_pragma
(cp_lexer *);
static void cp_lexer_save_tokens static void cp_lexer_save_tokens
(cp_lexer *); (cp_lexer *);
static void cp_lexer_commit_tokens static void cp_lexer_commit_tokens
@ -196,6 +200,9 @@ static void cp_lexer_stop_debugging
static cp_token_cache *cp_token_cache_new static cp_token_cache *cp_token_cache_new
(cp_token *, cp_token *); (cp_token *, cp_token *);
static void cp_parser_initial_pragma
(cp_token *);
/* Manifest constants. */ /* Manifest constants. */
#define CP_LEXER_BUFFER_SIZE 10000 #define CP_LEXER_BUFFER_SIZE 10000
#define CP_SAVED_TOKEN_STACK 5 #define CP_SAVED_TOKEN_STACK 5
@ -244,17 +251,12 @@ cp_lexer_new_main (void)
size_t space; size_t space;
cp_token *buffer; cp_token *buffer;
/* It's possible that lexing the first token will load a PCH file, /* It's possible that parsing the first pragma will load a PCH file,
which is a GC collection point. So we have to grab the first which is a GC collection point. So we have to do that before
token before allocating any memory. Pragmas must not be deferred allocating any memory. */
as -fpch-preprocess can generate a pragma to load the PCH file in cp_parser_initial_pragma (&first_token);
the preprocessed output used by -save-temps. */
cp_lexer_get_preprocessor_token (NULL, &first_token);
/* Tell cpplib we want CPP_PRAGMA tokens. */ /* Tell c_lex_with_flags not to merge string constants. */
cpp_get_options (parse_in)->defer_pragmas = true;
/* Tell pragma_lex not to merge string constants. */
c_lex_return_raw_strings = true; c_lex_return_raw_strings = true;
c_common_no_more_pch (); c_common_no_more_pch ();
@ -296,11 +298,6 @@ cp_lexer_new_main (void)
lexer->last_token = pos; lexer->last_token = pos;
lexer->next_token = lexer->buffer_length ? buffer : (cp_token *)&eof_token; lexer->next_token = lexer->buffer_length ? buffer : (cp_token *)&eof_token;
/* Pragma processing (via cpp_handle_deferred_pragma) may result in
direct calls to pragma_lex. Those callers all expect pragma_lex
to do string constant concatenation. */
c_lex_return_raw_strings = false;
/* Subsequent preprocessor diagnostics should use compiler /* Subsequent preprocessor diagnostics should use compiler
diagnostic functions to get the compiler source location. */ diagnostic functions to get the compiler source location. */
cpp_get_options (parse_in)->client_diagnostic = true; cpp_get_options (parse_in)->client_diagnostic = true;
@ -395,6 +392,8 @@ cp_lexer_get_preprocessor_token (cp_lexer *lexer ATTRIBUTE_UNUSED ,
/* Get a new token from the preprocessor. */ /* Get a new token from the preprocessor. */
token->type token->type
= c_lex_with_flags (&token->value, &token->location, &token->flags); = c_lex_with_flags (&token->value, &token->location, &token->flags);
token->keyword = RID_MAX;
token->pragma_kind = PRAGMA_NONE;
token->in_system_header = in_system_header; token->in_system_header = in_system_header;
/* On some systems, some header files are surrounded by an /* On some systems, some header files are surrounded by an
@ -442,8 +441,12 @@ cp_lexer_get_preprocessor_token (cp_lexer *lexer ATTRIBUTE_UNUSED ,
default: token->keyword = C_RID_CODE (token->value); default: token->keyword = C_RID_CODE (token->value);
} }
} }
else else if (token->type == CPP_PRAGMA)
token->keyword = RID_MAX; {
/* We smuggled the cpp_token->u.pragma value in an INTEGER_CST. */
token->pragma_kind = TREE_INT_CST_LOW (token->value);
token->value = NULL;
}
} }
/* Update the globals input_location and in_system_header from TOKEN. */ /* Update the globals input_location and in_system_header from TOKEN. */
@ -553,6 +556,7 @@ cp_lexer_consume_token (cp_lexer* lexer)
cp_token *token = lexer->next_token; cp_token *token = lexer->next_token;
gcc_assert (token != &eof_token); gcc_assert (token != &eof_token);
gcc_assert (!lexer->in_pragma || token->type != CPP_PRAGMA_EOL);
do do
{ {
@ -630,25 +634,6 @@ cp_lexer_purge_tokens_after (cp_lexer *lexer, cp_token *tok)
} }
} }
/* Consume and handle a pragma token. */
static void
cp_lexer_handle_pragma (cp_lexer *lexer)
{
cpp_string s;
cp_token *token = cp_lexer_consume_token (lexer);
gcc_assert (token->type == CPP_PRAGMA);
gcc_assert (token->value);
s.len = TREE_STRING_LENGTH (token->value);
s.text = (const unsigned char *) TREE_STRING_POINTER (token->value);
cpp_handle_deferred_pragma (parse_in, &s);
/* Clearing token->value here means that we will get an ICE if we
try to process this #pragma again (which should be impossible). */
token->value = NULL;
}
/* Begin saving tokens. All tokens consumed after this point will be /* Begin saving tokens. All tokens consumed after this point will be
preserved. */ preserved. */
@ -731,7 +716,6 @@ cp_lexer_print_token (FILE * stream, cp_token *token)
case CPP_STRING: case CPP_STRING:
case CPP_WSTRING: case CPP_WSTRING:
case CPP_PRAGMA:
fprintf (stream, " \"%s\"", TREE_STRING_POINTER (token->value)); fprintf (stream, " \"%s\"", TREE_STRING_POINTER (token->value));
break; break;
@ -1463,9 +1447,9 @@ static tree cp_parser_builtin_offsetof
/* Statements [gram.stmt.stmt] */ /* Statements [gram.stmt.stmt] */
static void cp_parser_statement static void cp_parser_statement
(cp_parser *, tree); (cp_parser *, tree, bool);
static tree cp_parser_labeled_statement static tree cp_parser_labeled_statement
(cp_parser *, tree); (cp_parser *, tree, bool);
static tree cp_parser_expression_statement static tree cp_parser_expression_statement
(cp_parser *, tree); (cp_parser *, tree);
static tree cp_parser_compound_statement static tree cp_parser_compound_statement
@ -1685,6 +1669,10 @@ static bool cp_parser_extension_opt
static void cp_parser_label_declaration static void cp_parser_label_declaration
(cp_parser *); (cp_parser *);
enum pragma_context { pragma_external, pragma_stmt, pragma_compound };
static bool cp_parser_pragma
(cp_parser *, enum pragma_context);
/* Objective-C++ Productions */ /* Objective-C++ Productions */
static tree cp_parser_objc_message_receiver static tree cp_parser_objc_message_receiver
@ -1828,6 +1816,8 @@ static void cp_parser_skip_to_closing_brace
(cp_parser *); (cp_parser *);
static void cp_parser_skip_until_found static void cp_parser_skip_until_found
(cp_parser *, enum cpp_ttype, const char *); (cp_parser *, enum cpp_ttype, const char *);
static void cp_parser_skip_to_pragma_eol
(cp_parser*, cp_token *);
static bool cp_parser_error_occurred static bool cp_parser_error_occurred
(cp_parser *); (cp_parser *);
static bool cp_parser_allow_gnu_extensions_p static bool cp_parser_allow_gnu_extensions_p
@ -1888,12 +1878,14 @@ cp_parser_error (cp_parser* parser, const char* message)
/* This diagnostic makes more sense if it is tagged to the line /* This diagnostic makes more sense if it is tagged to the line
of the token we just peeked at. */ of the token we just peeked at. */
cp_lexer_set_source_position_from_token (token); cp_lexer_set_source_position_from_token (token);
if (token->type == CPP_PRAGMA) if (token->type == CPP_PRAGMA)
{ {
error ("%<#pragma%> is not allowed here"); error ("%<#pragma%> is not allowed here");
cp_lexer_purge_token (parser->lexer); cp_parser_skip_to_pragma_eol (parser, token);
return; return;
} }
c_parse_error (message, c_parse_error (message,
/* Because c_parser_error does not understand /* Because c_parser_error does not understand
CPP_KEYWORD, keywords are treated like CPP_KEYWORD, keywords are treated like
@ -2187,7 +2179,6 @@ cp_parser_skip_to_closing_parenthesis (cp_parser *parser,
{ {
unsigned paren_depth = 0; unsigned paren_depth = 0;
unsigned brace_depth = 0; unsigned brace_depth = 0;
int result;
if (recovering && !or_comma if (recovering && !or_comma
&& cp_parser_uncommitted_to_tentative_parse_p (parser)) && cp_parser_uncommitted_to_tentative_parse_p (parser))
@ -2195,62 +2186,55 @@ cp_parser_skip_to_closing_parenthesis (cp_parser *parser,
while (true) while (true)
{ {
cp_token *token; cp_token * token = cp_lexer_peek_token (parser->lexer);
/* If we've run out of tokens, then there is no closing `)'. */ switch (token->type)
if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
{ {
result = 0; case CPP_EOF:
case CPP_PRAGMA_EOL:
/* If we've run out of tokens, then there is no closing `)'. */
return 0;
case CPP_SEMICOLON:
/* This matches the processing in skip_to_end_of_statement. */
if (!brace_depth)
return 0;
break; break;
}
token = cp_lexer_peek_token (parser->lexer); case CPP_OPEN_BRACE:
++brace_depth;
/* This matches the processing in skip_to_end_of_statement. */
if (token->type == CPP_SEMICOLON && !brace_depth)
{
result = 0;
break; break;
} case CPP_CLOSE_BRACE:
if (token->type == CPP_OPEN_BRACE)
++brace_depth;
if (token->type == CPP_CLOSE_BRACE)
{
if (!brace_depth--) if (!brace_depth--)
{ return 0;
result = 0;
break;
}
}
if (recovering && or_comma && token->type == CPP_COMMA
&& !brace_depth && !paren_depth)
{
result = -1;
break; break;
}
if (!brace_depth) case CPP_COMMA:
{ if (recovering && or_comma && !brace_depth && !paren_depth)
/* If it is an `(', we have entered another level of nesting. */ return -1;
if (token->type == CPP_OPEN_PAREN) break;
case CPP_OPEN_PAREN:
if (!brace_depth)
++paren_depth; ++paren_depth;
/* If it is a `)', then we might be done. */ break;
else if (token->type == CPP_CLOSE_PAREN && !paren_depth--)
case CPP_CLOSE_PAREN:
if (!brace_depth && !paren_depth--)
{ {
if (consume_paren) if (consume_paren)
cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer);
{ return 1;
result = 1;
break;
}
} }
break;
default:
break;
} }
/* Consume the token. */ /* Consume the token. */
cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer);
} }
return result;
} }
/* Consume tokens until we reach the end of the current statement. /* Consume tokens until we reach the end of the current statement.
@ -2264,31 +2248,34 @@ cp_parser_skip_to_end_of_statement (cp_parser* parser)
while (true) while (true)
{ {
cp_token *token; cp_token *token = cp_lexer_peek_token (parser->lexer);
/* Peek at the next token. */ switch (token->type)
token = cp_lexer_peek_token (parser->lexer);
/* If we've run out of tokens, stop. */
if (token->type == CPP_EOF)
break;
/* If the next token is a `;', we have reached the end of the
statement. */
if (token->type == CPP_SEMICOLON && !nesting_depth)
break;
/* If the next token is a non-nested `}', then we have reached
the end of the current block. */
if (token->type == CPP_CLOSE_BRACE)
{ {
/* If this is a non-nested `}', stop before consuming it. case CPP_EOF:
case CPP_PRAGMA_EOL:
/* If we've run out of tokens, stop. */
return;
case CPP_SEMICOLON:
/* If the next token is a `;', we have reached the end of the
statement. */
if (!nesting_depth)
return;
break;
case CPP_CLOSE_BRACE:
/* If this is a non-nested '}', stop before consuming it.
That way, when confronted with something like: That way, when confronted with something like:
{ 3 + } { 3 + }
we stop before consuming the closing `}', even though we we stop before consuming the closing '}', even though we
have not yet reached a `;'. */ have not yet reached a `;'. */
if (nesting_depth == 0) if (nesting_depth == 0)
break; return;
/* If it is the closing `}' for a block that we have
/* If it is the closing '}' for a block that we have
scanned, stop -- but only after consuming the token. scanned, stop -- but only after consuming the token.
That way given: That way given:
@ -2301,13 +2288,17 @@ cp_parser_skip_to_end_of_statement (cp_parser* parser)
if (--nesting_depth == 0) if (--nesting_depth == 0)
{ {
cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer);
break; return;
} }
case CPP_OPEN_BRACE:
++nesting_depth;
break;
default:
break;
} }
/* If it the next token is a `{', then we are entering a new
block. Consume the entire block. */
else if (token->type == CPP_OPEN_BRACE)
++nesting_depth;
/* Consume the token. */ /* Consume the token. */
cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer);
} }
@ -2344,15 +2335,12 @@ cp_parser_skip_to_end_of_block_or_statement (cp_parser* parser)
{ {
cp_token *token = cp_lexer_peek_token (parser->lexer); cp_token *token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_EOF)
break;
switch (token->type) switch (token->type)
{ {
case CPP_EOF: case CPP_EOF:
case CPP_PRAGMA_EOL:
/* If we've run out of tokens, stop. */ /* If we've run out of tokens, stop. */
nesting_depth = -1; return;
continue;
case CPP_SEMICOLON: case CPP_SEMICOLON:
/* Stop if this is an unnested ';'. */ /* Stop if this is an unnested ';'. */
@ -2379,7 +2367,6 @@ cp_parser_skip_to_end_of_block_or_statement (cp_parser* parser)
/* Consume the token. */ /* Consume the token. */
cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer);
} }
} }
@ -2393,26 +2380,56 @@ cp_parser_skip_to_closing_brace (cp_parser *parser)
while (true) while (true)
{ {
cp_token *token; cp_token *token = cp_lexer_peek_token (parser->lexer);
switch (token->type)
{
case CPP_EOF:
case CPP_PRAGMA_EOL:
/* If we've run out of tokens, stop. */
return;
case CPP_CLOSE_BRACE:
/* If the next token is a non-nested `}', then we have reached
the end of the current block. */
if (nesting_depth-- == 0)
return;
break;
case CPP_OPEN_BRACE:
/* If it the next token is a `{', then we are entering a new
block. Consume the entire block. */
++nesting_depth;
break;
default:
break;
}
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* If we've run out of tokens, stop. */
if (token->type == CPP_EOF)
break;
/* If the next token is a non-nested `}', then we have reached
the end of the current block. */
if (token->type == CPP_CLOSE_BRACE && nesting_depth-- == 0)
break;
/* If it the next token is a `{', then we are entering a new
block. Consume the entire block. */
else if (token->type == CPP_OPEN_BRACE)
++nesting_depth;
/* Consume the token. */ /* Consume the token. */
cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer);
} }
} }
/* Consume tokens until we reach the end of the pragma. The PRAGMA_TOK
parameter is the PRAGMA token, allowing us to purge the entire pragma
sequence. */
static void
cp_parser_skip_to_pragma_eol (cp_parser* parser, cp_token *pragma_tok)
{
cp_token *token;
parser->lexer->in_pragma = false;
do
token = cp_lexer_consume_token (parser->lexer);
while (token->type != CPP_PRAGMA_EOL && token->type != CPP_EOF);
/* Ensure that the pragma is not parsed again. */
cp_lexer_purge_tokens_after (parser->lexer, pragma_tok);
}
/* This is a simple wrapper around make_typename_type. When the id is /* This is a simple wrapper around make_typename_type. When the id is
an unresolved identifier node, we can provide a superior diagnostic an unresolved identifier node, we can provide a superior diagnostic
using cp_parser_diagnose_invalid_type_name. */ using cp_parser_diagnose_invalid_type_name. */
@ -6005,15 +6022,20 @@ cp_parser_builtin_offsetof (cp_parser *parser)
iteration-statement iteration-statement
jump-statement jump-statement
declaration-statement declaration-statement
try-block */ try-block
IN_COMPOUND is true when the statement is nested inside a
cp_parser_compound_statement; this matters for certain pragmas. */
static void static void
cp_parser_statement (cp_parser* parser, tree in_statement_expr) cp_parser_statement (cp_parser* parser, tree in_statement_expr,
bool in_compound)
{ {
tree statement; tree statement;
cp_token *token; cp_token *token;
location_t statement_location; location_t statement_location;
restart:
/* There is no statement yet. */ /* There is no statement yet. */
statement = NULL_TREE; statement = NULL_TREE;
/* Peek at the next token. */ /* Peek at the next token. */
@ -6030,8 +6052,8 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr)
{ {
case RID_CASE: case RID_CASE:
case RID_DEFAULT: case RID_DEFAULT:
statement = cp_parser_labeled_statement (parser, statement = cp_parser_labeled_statement (parser, in_statement_expr,
in_statement_expr); in_compound);
break; break;
case RID_IF: case RID_IF:
@ -6077,7 +6099,8 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr)
labeled-statement. */ labeled-statement. */
token = cp_lexer_peek_nth_token (parser->lexer, 2); token = cp_lexer_peek_nth_token (parser->lexer, 2);
if (token->type == CPP_COLON) if (token->type == CPP_COLON)
statement = cp_parser_labeled_statement (parser, in_statement_expr); statement = cp_parser_labeled_statement (parser, in_statement_expr,
in_compound);
} }
/* Anything that starts with a `{' must be a compound-statement. */ /* Anything that starts with a `{' must be a compound-statement. */
else if (token->type == CPP_OPEN_BRACE) else if (token->type == CPP_OPEN_BRACE)
@ -6086,7 +6109,15 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr)
a statement all its own. */ a statement all its own. */
else if (token->type == CPP_PRAGMA) else if (token->type == CPP_PRAGMA)
{ {
cp_lexer_handle_pragma (parser->lexer); /* Only certain OpenMP pragmas are attached to statements, and thus
are considered statements themselves. All others are not. In
the context of a compound, accept the pragma as a "statement" and
return so that we can check for a close brace. Otherwise we
require a real statement and must go back and read one. */
if (in_compound)
cp_parser_pragma (parser, pragma_compound);
else if (!cp_parser_pragma (parser, pragma_stmt))
goto restart;
return; return;
} }
else if (token->type == CPP_EOF) else if (token->type == CPP_EOF)
@ -6132,10 +6163,14 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr)
case constant-expression ... constant-expression : statement case constant-expression ... constant-expression : statement
Returns the new CASE_LABEL_EXPR, for a `case' or `default' label. Returns the new CASE_LABEL_EXPR, for a `case' or `default' label.
For an ordinary label, returns a LABEL_EXPR. */ For an ordinary label, returns a LABEL_EXPR.
IN_COMPOUND is as for cp_parser_statement: true when we're nested
inside a compound. */
static tree static tree
cp_parser_labeled_statement (cp_parser* parser, tree in_statement_expr) cp_parser_labeled_statement (cp_parser* parser, tree in_statement_expr,
bool in_compound)
{ {
cp_token *token; cp_token *token;
tree statement = error_mark_node; tree statement = error_mark_node;
@ -6178,20 +6213,21 @@ cp_parser_labeled_statement (cp_parser* parser, tree in_statement_expr)
else else
expr_hi = NULL_TREE; expr_hi = NULL_TREE;
if (!parser->in_switch_statement_p) if (parser->in_switch_statement_p)
error ("case label %qE not within a switch statement", expr);
else
statement = finish_case_label (expr, expr_hi); statement = finish_case_label (expr, expr_hi);
else
error ("case label %qE not within a switch statement", expr);
} }
break; break;
case RID_DEFAULT: case RID_DEFAULT:
/* Consume the `default' token. */ /* Consume the `default' token. */
cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer);
if (!parser->in_switch_statement_p)
error ("case label not within a switch statement"); if (parser->in_switch_statement_p)
else
statement = finish_case_label (NULL_TREE, NULL_TREE); statement = finish_case_label (NULL_TREE, NULL_TREE);
else
error ("case label not within a switch statement");
break; break;
default: default:
@ -6203,7 +6239,7 @@ cp_parser_labeled_statement (cp_parser* parser, tree in_statement_expr)
/* Require the `:' token. */ /* Require the `:' token. */
cp_parser_require (parser, CPP_COLON, "`:'"); cp_parser_require (parser, CPP_COLON, "`:'");
/* Parse the labeled statement. */ /* Parse the labeled statement. */
cp_parser_statement (parser, in_statement_expr); cp_parser_statement (parser, in_statement_expr, in_compound);
/* Return the label, in the case of a `case' or `default' label. */ /* Return the label, in the case of a `case' or `default' label. */
return statement; return statement;
@ -6285,13 +6321,16 @@ cp_parser_statement_seq_opt (cp_parser* parser, tree in_statement_expr)
/* Scan statements until there aren't any more. */ /* Scan statements until there aren't any more. */
while (true) while (true)
{ {
cp_token *token = cp_lexer_peek_token (parser->lexer);
/* If we're looking at a `}', then we've run out of statements. */ /* If we're looking at a `}', then we've run out of statements. */
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE) if (token->type == CPP_CLOSE_BRACE
|| cp_lexer_next_token_is (parser->lexer, CPP_EOF)) || token->type == CPP_EOF
|| token->type == CPP_PRAGMA_EOL)
break; break;
/* Parse the statement. */ /* Parse the statement. */
cp_parser_statement (parser, in_statement_expr); cp_parser_statement (parser, in_statement_expr, true);
} }
} }
@ -6788,7 +6827,7 @@ cp_parser_implicitly_scoped_statement (cp_parser* parser)
/* Create a compound-statement. */ /* Create a compound-statement. */
statement = begin_compound_stmt (0); statement = begin_compound_stmt (0);
/* Parse the dependent-statement. */ /* Parse the dependent-statement. */
cp_parser_statement (parser, false); cp_parser_statement (parser, NULL_TREE, false);
/* Finish the dummy compound-statement. */ /* Finish the dummy compound-statement. */
finish_compound_stmt (statement); finish_compound_stmt (statement);
} }
@ -6810,13 +6849,13 @@ cp_parser_already_scoped_statement (cp_parser* parser)
{ {
/* If the token is a `{', then we must take special action. */ /* If the token is a `{', then we must take special action. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)) if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
cp_parser_statement (parser, false); cp_parser_statement (parser, NULL_TREE, false);
else else
{ {
/* Avoid calling cp_parser_compound_statement, so that we /* Avoid calling cp_parser_compound_statement, so that we
don't create a new scope. Do everything else by hand. */ don't create a new scope. Do everything else by hand. */
cp_parser_require (parser, CPP_OPEN_BRACE, "`{'"); cp_parser_require (parser, CPP_OPEN_BRACE, "`{'");
cp_parser_statement_seq_opt (parser, false); cp_parser_statement_seq_opt (parser, NULL_TREE);
cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'"); cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
} }
} }
@ -6839,7 +6878,8 @@ cp_parser_declaration_seq_opt (cp_parser* parser)
token = cp_lexer_peek_token (parser->lexer); token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_CLOSE_BRACE if (token->type == CPP_CLOSE_BRACE
|| token->type == CPP_EOF) || token->type == CPP_EOF
|| token->type == CPP_PRAGMA_EOL)
break; break;
if (token->type == CPP_SEMICOLON) if (token->type == CPP_SEMICOLON)
@ -6871,7 +6911,7 @@ cp_parser_declaration_seq_opt (cp_parser* parser)
A nested declaration cannot, so this is done here and not A nested declaration cannot, so this is done here and not
in cp_parser_declaration. (A #pragma at block scope is in cp_parser_declaration. (A #pragma at block scope is
handled in cp_parser_statement.) */ handled in cp_parser_statement.) */
cp_lexer_handle_pragma (parser->lexer); cp_parser_pragma (parser, pragma_external);
continue; continue;
} }
@ -12207,6 +12247,7 @@ cp_parser_parameter_declaration (cp_parser *parser,
/* If we run out of tokens, issue an error message. */ /* If we run out of tokens, issue an error message. */
case CPP_EOF: case CPP_EOF:
case CPP_PRAGMA_EOL:
error ("file ends in default argument"); error ("file ends in default argument");
done = true; done = true;
break; break;
@ -13242,7 +13283,9 @@ cp_parser_member_specification_opt (cp_parser* parser)
/* Peek at the next token. */ /* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer); token = cp_lexer_peek_token (parser->lexer);
/* If it's a `}', or EOF then we've seen all the members. */ /* If it's a `}', or EOF then we've seen all the members. */
if (token->type == CPP_CLOSE_BRACE || token->type == CPP_EOF) if (token->type == CPP_CLOSE_BRACE
|| token->type == CPP_EOF
|| token->type == CPP_PRAGMA_EOL)
break; break;
/* See if this token is a keyword. */ /* See if this token is a keyword. */
@ -13264,7 +13307,7 @@ cp_parser_member_specification_opt (cp_parser* parser)
/* Accept #pragmas at class scope. */ /* Accept #pragmas at class scope. */
if (token->type == CPP_PRAGMA) if (token->type == CPP_PRAGMA)
{ {
cp_lexer_handle_pragma (parser->lexer); cp_parser_pragma (parser, pragma_external);
break; break;
} }
@ -15185,9 +15228,15 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
/* Issue an error message. */ /* Issue an error message. */
error ("named return values are no longer supported"); error ("named return values are no longer supported");
/* Skip tokens until we reach the start of the function body. */ /* Skip tokens until we reach the start of the function body. */
while (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE) while (true)
&& cp_lexer_next_token_is_not (parser->lexer, CPP_EOF)) {
cp_lexer_consume_token (parser->lexer); cp_token *token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_OPEN_BRACE
|| token->type == CPP_EOF
|| token->type == CPP_PRAGMA_EOL)
break;
cp_lexer_consume_token (parser->lexer);
}
} }
/* The `extern' in `extern "C" void f () { ... }' does not apply to /* The `extern' in `extern "C" void f () { ... }' does not apply to
anything declared inside `f'. */ anything declared inside `f'. */
@ -16002,27 +16051,38 @@ cp_parser_skip_until_found (cp_parser* parser,
{ {
/* Peek at the next token. */ /* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer); token = cp_lexer_peek_token (parser->lexer);
/* If we've reached the token we want, consume it and
stop. */ /* If we've reached the token we want, consume it and stop. */
if (token->type == type && !nesting_depth) if (token->type == type && !nesting_depth)
{ {
cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer);
return; return;
} }
/* If we've run out of tokens, stop. */
if (token->type == CPP_EOF) switch (token->type)
return;
if (token->type == CPP_OPEN_BRACE
|| token->type == CPP_OPEN_PAREN
|| token->type == CPP_OPEN_SQUARE)
++nesting_depth;
else if (token->type == CPP_CLOSE_BRACE
|| token->type == CPP_CLOSE_PAREN
|| token->type == CPP_CLOSE_SQUARE)
{ {
case CPP_EOF:
case CPP_PRAGMA_EOL:
/* If we've run out of tokens, stop. */
return;
case CPP_OPEN_BRACE:
case CPP_OPEN_PAREN:
case CPP_OPEN_SQUARE:
++nesting_depth;
break;
case CPP_CLOSE_BRACE:
case CPP_CLOSE_PAREN:
case CPP_CLOSE_SQUARE:
if (nesting_depth-- == 0) if (nesting_depth-- == 0)
return; return;
break;
default:
break;
} }
/* Consume this token. */ /* Consume this token. */
cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer);
} }
@ -16241,7 +16301,9 @@ cp_parser_cache_group (cp_parser *parser,
&& cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) && cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
return; return;
/* If we've reached the end of the file, stop. */ /* If we've reached the end of the file, stop. */
if (cp_lexer_next_token_is (parser->lexer, CPP_EOF)) if (cp_lexer_next_token_is (parser->lexer, CPP_EOF)
|| (end != CPP_PRAGMA_EOL
&& cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA_EOL)))
return; return;
/* Consume the next token. */ /* Consume the next token. */
token = cp_lexer_consume_token (parser->lexer); token = cp_lexer_consume_token (parser->lexer);
@ -16254,6 +16316,8 @@ cp_parser_cache_group (cp_parser *parser,
} }
else if (token->type == CPP_OPEN_PAREN) else if (token->type == CPP_OPEN_PAREN)
cp_parser_cache_group (parser, CPP_CLOSE_PAREN, depth + 1); cp_parser_cache_group (parser, CPP_CLOSE_PAREN, depth + 1);
else if (token->type == CPP_PRAGMA)
cp_parser_cache_group (parser, CPP_PRAGMA_EOL, depth + 1);
else if (token->type == end) else if (token->type == end)
return; return;
} }
@ -16990,7 +17054,7 @@ cp_parser_objc_interstitial_code (cp_parser* parser)
cp_parser_linkage_specification (parser); cp_parser_linkage_specification (parser);
/* Handle #pragma, if any. */ /* Handle #pragma, if any. */
else if (token->type == CPP_PRAGMA) else if (token->type == CPP_PRAGMA)
cp_lexer_handle_pragma (parser->lexer); cp_parser_pragma (parser, pragma_external);
/* Allow stray semicolons. */ /* Allow stray semicolons. */
else if (token->type == CPP_SEMICOLON) else if (token->type == CPP_SEMICOLON)
cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer);
@ -17482,11 +17546,111 @@ cp_parser_objc_statement (cp_parser * parser) {
return error_mark_node; return error_mark_node;
} }
/* The parser. */ /* The parser. */
static GTY (()) cp_parser *the_parser; static GTY (()) cp_parser *the_parser;
/* Special handling for the first token or line in the file. The first
thing in the file might be #pragma GCC pch_preprocess, which loads a
PCH file, which is a GC collection point. So we need to handle this
first pragma without benefit of an existing lexer structure.
Always returns one token to the caller in *FIRST_TOKEN. This is
either the true first token of the file, or the first token after
the initial pragma. */
static void
cp_parser_initial_pragma (cp_token *first_token)
{
tree name = NULL;
cp_lexer_get_preprocessor_token (NULL, first_token);
if (first_token->pragma_kind != PRAGMA_GCC_PCH_PREPROCESS)
return;
cp_lexer_get_preprocessor_token (NULL, first_token);
if (first_token->type == CPP_STRING)
{
name = first_token->value;
cp_lexer_get_preprocessor_token (NULL, first_token);
if (first_token->type != CPP_PRAGMA_EOL)
error ("junk at end of %<#pragma GCC pch_preprocess%>");
}
else
error ("expected string literal");
/* Skip to the end of the pragma. */
while (first_token->type != CPP_PRAGMA_EOL && first_token->type != CPP_EOF)
cp_lexer_get_preprocessor_token (NULL, first_token);
/* Read one more token to return to our caller. */
cp_lexer_get_preprocessor_token (NULL, first_token);
/* Now actually load the PCH file. */
if (name)
c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name));
}
/* Normal parsing of a pragma token. Here we can (and must) use the
regular lexer. */
static bool
cp_parser_pragma (cp_parser *parser, enum pragma_context context ATTRIBUTE_UNUSED)
{
cp_token *pragma_tok;
unsigned int id;
pragma_tok = cp_lexer_consume_token (parser->lexer);
gcc_assert (pragma_tok->type == CPP_PRAGMA);
parser->lexer->in_pragma = true;
id = pragma_tok->pragma_kind;
switch (id)
{
case PRAGMA_GCC_PCH_PREPROCESS:
error ("%<#pragma GCC pch_preprocess%> must be first");
break;
default:
gcc_assert (id >= PRAGMA_FIRST_EXTERNAL);
c_invoke_pragma_handler (id);
break;
}
cp_parser_skip_to_pragma_eol (parser, pragma_tok);
return false;
}
/* The interface the pragma parsers have to the lexer. */
enum cpp_ttype
pragma_lex (tree *value)
{
cp_token *tok;
enum cpp_ttype ret;
tok = cp_lexer_peek_token (the_parser->lexer);
ret = tok->type;
*value = tok->value;
if (ret == CPP_PRAGMA_EOL || ret == CPP_EOF)
ret = CPP_EOF;
else if (ret == CPP_STRING)
*value = cp_parser_string_literal (the_parser, false, false);
else
{
cp_lexer_consume_token (the_parser->lexer);
if (ret == CPP_KEYWORD)
ret = CPP_NAME;
}
return ret;
}
/* External interface. */ /* External interface. */
/* Parse one entire translation unit. */ /* Parse one entire translation unit. */

View File

@ -1,3 +1,8 @@
2006-01-04 Richard Henderson <rth@redhat.com>
Merge from gomp branch.
* g++.dg/parse/pragma2.C: Update expected error lines.
2006-01-04 Jakub Jelinek <jakub@redhat.com> 2006-01-04 Jakub Jelinek <jakub@redhat.com>
* g++.dg/other/i386-2.C: New test. * g++.dg/other/i386-2.C: New test.

View File

@ -2,7 +2,7 @@
// Ideally, the #pragma error would come one line further down, but it // Ideally, the #pragma error would come one line further down, but it
// does not. // does not.
int f(int x, // { dg-error "not allowed here" } int f(int x,
#pragma interface #pragma interface // { dg-error "not allowed here" }
// The parser gets confused and issues an error on the next line. // The parser gets confused and issues an error on the next line.
int y); // { dg-bogus "" "" { xfail *-*-* } } int y); // { dg-bogus "" "" { xfail *-*-* } }

View File

@ -1,3 +1,38 @@
2006-01-04 Dmitry Kurochkin <dmitry.kurochkin@gmail.com>
Richard Henderson <rth@redhat.com>
Merge from gomp branch:
* directives.c (struct pragma_entry): Add is_deferred. Add ident
entry to value union.
(end_directive): Don't eat the line if in_deferred_pragma.
(run_directive): Remove pragma hacks.
(insert_pragma_entry): Remove.
(new_pragma_entry): New.
(register_pragma_1): Split out of register_pragma. Only handle
the lookup tree and return the new entry.
(cpp_register_pragma): Fill in the pragma entry here.
(cpp_register_deferred_pragma): New.
(register_pragma_internal): New.
(_cpp_init_internal_pragmas): Use register_pragma_internal.
(do_pragma): Allow pragma expansion after namespace. For deferred
pragmas, don't slurp the line into a string.
(destringize_and_run): Save tokens for deferred pragmas.
(cpp_handle_deferred_pragma): Remove.
* macro.c (builtin_macro): Remove pragma token hack.
(_cpp_push_token_context): Rename from push_token_context and export.
* internal.h (struct lexer_state): Add pragma_allow_expansion.
(_cpp_push_token_context): Declare.
* lex.c (_cpp_lex_token): Allow _cpp_handle_directive to return
a token. Update the line number correctly if so.
(_cpp_lex_direct): Emit CPP_PRAGMA_EOL tokens.
(cpp_token_val_index): Return CPP_TOKEN_FLD_PRAGMA for pragmas.
* include/cpplib.h (PRAGMA_EOL): New.
(CPP_TOKEN_FLD_PRAGMA): New.
(struct cpp_token): Add val.pragma.
(struct cpp_options): Remove defer_pragmas.
(cpp_handle_deferred_pragma): Remove.
(cpp_register_deferred_pragma): Declare.
2006-01-01 Jakub Jelinek <jakub@redhat.com> 2006-01-01 Jakub Jelinek <jakub@redhat.com>
PR c++/25294 PR c++/25294
@ -19,7 +54,7 @@
(cpp_classify_number): Disallow hexadecimal DFP constants. (cpp_classify_number): Disallow hexadecimal DFP constants.
2005-11-14 Gerald Pfeifer <gerald@pfeifer.com> 2005-11-14 Gerald Pfeifer <gerald@pfeifer.com>
Ian Lance Taylor <ian@airs.com> Ian Lance Taylor <ian@airs.com>
* include/cpplib.h (struct cpp_callbacks): Annotate error with * include/cpplib.h (struct cpp_callbacks): Annotate error with
ATTRIBUTE_FPTR_PRINTF(3,0) instead of ATTRIBUTE_PRINTF(3,0). ATTRIBUTE_FPTR_PRINTF(3,0) instead of ATTRIBUTE_PRINTF(3,0).

View File

@ -1,7 +1,6 @@
/* CPP Library. (Directive handling.) /* CPP Library. (Directive handling.)
Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
Free Software Foundation, Inc.
Contributed by Per Bothner, 1994-95. Contributed by Per Bothner, 1994-95.
Based on CCCP program by Paul Rubin, June 1986 Based on CCCP program by Paul Rubin, June 1986
Adapted to ANSI C, Richard Stallman, Jan 1987 Adapted to ANSI C, Richard Stallman, Jan 1987
@ -46,11 +45,13 @@ struct pragma_entry
struct pragma_entry *next; struct pragma_entry *next;
const cpp_hashnode *pragma; /* Name and length. */ const cpp_hashnode *pragma; /* Name and length. */
bool is_nspace; bool is_nspace;
bool allow_expansion;
bool is_internal; bool is_internal;
bool is_deferred;
bool allow_expansion;
union { union {
pragma_cb handler; pragma_cb handler;
struct pragma_entry *space; struct pragma_entry *space;
unsigned int ident;
} u; } u;
}; };
@ -106,13 +107,6 @@ static int undefine_macros (cpp_reader *, cpp_hashnode *, void *);
static void do_include_common (cpp_reader *, enum include_type); static void do_include_common (cpp_reader *, enum include_type);
static struct pragma_entry *lookup_pragma_entry (struct pragma_entry *, static struct pragma_entry *lookup_pragma_entry (struct pragma_entry *,
const cpp_hashnode *); const cpp_hashnode *);
static struct pragma_entry *insert_pragma_entry (cpp_reader *,
struct pragma_entry **,
const cpp_hashnode *,
pragma_cb,
bool, bool);
static void register_pragma (cpp_reader *, const char *, const char *,
pragma_cb, bool, bool);
static int count_registered_pragmas (struct pragma_entry *); static int count_registered_pragmas (struct pragma_entry *);
static char ** save_registered_pragmas (struct pragma_entry *, char **); static char ** save_registered_pragmas (struct pragma_entry *, char **);
static char ** restore_registered_pragmas (cpp_reader *, struct pragma_entry *, static char ** restore_registered_pragmas (cpp_reader *, struct pragma_entry *,
@ -278,7 +272,9 @@ start_directive (cpp_reader *pfile)
static void static void
end_directive (cpp_reader *pfile, int skip_line) end_directive (cpp_reader *pfile, int skip_line)
{ {
if (CPP_OPTION (pfile, traditional)) if (pfile->state.in_deferred_pragma)
;
else if (CPP_OPTION (pfile, traditional))
{ {
/* Revert change of prepare_directive_trad. */ /* Revert change of prepare_directive_trad. */
pfile->state.prevent_expansion--; pfile->state.prevent_expansion--;
@ -491,9 +487,6 @@ run_directive (cpp_reader *pfile, int dir_no, const char *buf, size_t count)
{ {
cpp_push_buffer (pfile, (const uchar *) buf, count, cpp_push_buffer (pfile, (const uchar *) buf, count,
/* from_stage3 */ true); /* from_stage3 */ true);
/* Disgusting hack. */
if (dir_no == T_PRAGMA && pfile->buffer->prev)
pfile->buffer->file = pfile->buffer->prev->file;
start_directive (pfile); start_directive (pfile);
/* This is a short-term fix to prevent a leading '#' being /* This is a short-term fix to prevent a leading '#' being
@ -505,8 +498,6 @@ run_directive (cpp_reader *pfile, int dir_no, const char *buf, size_t count)
prepare_directive_trad (pfile); prepare_directive_trad (pfile);
pfile->directive->handler (pfile); pfile->directive->handler (pfile);
end_directive (pfile, 1); end_directive (pfile, 1);
if (dir_no == T_PRAGMA)
pfile->buffer->file = NULL;
_cpp_pop_buffer (pfile); _cpp_pop_buffer (pfile);
} }
@ -1040,86 +1031,97 @@ lookup_pragma_entry (struct pragma_entry *chain, const cpp_hashnode *pragma)
return chain; return chain;
} }
/* Create and insert a pragma entry for NAME at the beginning of a /* Create and insert a blank pragma entry at the beginning of a
singly-linked CHAIN. If handler is NULL, it is a namespace, singly-linked CHAIN. */
otherwise it is a pragma and its handler. If INTERNAL is true
this pragma is being inserted by libcpp itself. */
static struct pragma_entry * static struct pragma_entry *
insert_pragma_entry (cpp_reader *pfile, struct pragma_entry **chain, new_pragma_entry (cpp_reader *pfile, struct pragma_entry **chain)
const cpp_hashnode *pragma, pragma_cb handler,
bool allow_expansion, bool internal)
{ {
struct pragma_entry *new_entry; struct pragma_entry *new_entry;
new_entry = (struct pragma_entry *) new_entry = (struct pragma_entry *)
_cpp_aligned_alloc (pfile, sizeof (struct pragma_entry)); _cpp_aligned_alloc (pfile, sizeof (struct pragma_entry));
new_entry->pragma = pragma;
if (handler)
{
new_entry->is_nspace = 0;
new_entry->u.handler = handler;
}
else
{
new_entry->is_nspace = 1;
new_entry->u.space = NULL;
}
new_entry->allow_expansion = allow_expansion; memset (new_entry, 0, sizeof (struct pragma_entry));
new_entry->is_internal = internal;
new_entry->next = *chain; new_entry->next = *chain;
*chain = new_entry; *chain = new_entry;
return new_entry; return new_entry;
} }
/* Register a pragma NAME in namespace SPACE. If SPACE is null, it /* Register a pragma NAME in namespace SPACE. If SPACE is null, it
goes in the global namespace. HANDLER is the handler it will call, goes in the global namespace. */
which must be non-NULL. If ALLOW_EXPANSION is set, allow macro static struct pragma_entry *
expansion while parsing pragma NAME. INTERNAL is true if this is a register_pragma_1 (cpp_reader *pfile, const char *space, const char *name,
pragma registered by cpplib itself, false if it is registered via bool allow_name_expansion)
cpp_register_pragma */
static void
register_pragma (cpp_reader *pfile, const char *space, const char *name,
pragma_cb handler, bool allow_expansion, bool internal)
{ {
struct pragma_entry **chain = &pfile->pragmas; struct pragma_entry **chain = &pfile->pragmas;
struct pragma_entry *entry; struct pragma_entry *entry;
const cpp_hashnode *node; const cpp_hashnode *node;
if (!handler)
abort ();
if (space) if (space)
{ {
node = cpp_lookup (pfile, U space, strlen (space)); node = cpp_lookup (pfile, U space, strlen (space));
entry = lookup_pragma_entry (*chain, node); entry = lookup_pragma_entry (*chain, node);
if (!entry) if (!entry)
entry = insert_pragma_entry (pfile, chain, node, NULL, {
allow_expansion, internal); entry = new_pragma_entry (pfile, chain);
entry->pragma = node;
entry->is_nspace = true;
entry->allow_expansion = allow_name_expansion;
}
else if (!entry->is_nspace) else if (!entry->is_nspace)
goto clash; goto clash;
else if (entry->allow_expansion != allow_name_expansion)
{
cpp_error (pfile, CPP_DL_ICE,
"registering pragmas in namespace \"%s\" with mismatched "
"name expansion", space);
return NULL;
}
chain = &entry->u.space; chain = &entry->u.space;
} }
else if (allow_name_expansion)
{
cpp_error (pfile, CPP_DL_ICE,
"registering pragma \"%s\" with name expansion "
"and no namespace", name);
return NULL;
}
/* Check for duplicates. */ /* Check for duplicates. */
node = cpp_lookup (pfile, U name, strlen (name)); node = cpp_lookup (pfile, U name, strlen (name));
entry = lookup_pragma_entry (*chain, node); entry = lookup_pragma_entry (*chain, node);
if (entry) if (entry == NULL)
{ {
if (entry->is_nspace) entry = new_pragma_entry (pfile, chain);
clash: entry->pragma = node;
cpp_error (pfile, CPP_DL_ICE, return entry;
"registering \"%s\" as both a pragma and a pragma namespace",
NODE_NAME (node));
else if (space)
cpp_error (pfile, CPP_DL_ICE, "#pragma %s %s is already registered",
space, name);
else
cpp_error (pfile, CPP_DL_ICE, "#pragma %s is already registered", name);
} }
if (entry->is_nspace)
clash:
cpp_error (pfile, CPP_DL_ICE,
"registering \"%s\" as both a pragma and a pragma namespace",
NODE_NAME (node));
else if (space)
cpp_error (pfile, CPP_DL_ICE, "#pragma %s %s is already registered",
space, name);
else else
insert_pragma_entry (pfile, chain, node, handler, allow_expansion, cpp_error (pfile, CPP_DL_ICE, "#pragma %s is already registered", name);
internal);
return NULL;
}
/* Register a cpplib internal pragma SPACE NAME with HANDLER. */
static void
register_pragma_internal (cpp_reader *pfile, const char *space,
const char *name, pragma_cb handler)
{
struct pragma_entry *entry;
entry = register_pragma_1 (pfile, space, name, false);
entry->is_internal = true;
entry->u.handler = handler;
} }
/* Register a pragma NAME in namespace SPACE. If SPACE is null, it /* Register a pragma NAME in namespace SPACE. If SPACE is null, it
@ -1131,7 +1133,39 @@ void
cpp_register_pragma (cpp_reader *pfile, const char *space, const char *name, cpp_register_pragma (cpp_reader *pfile, const char *space, const char *name,
pragma_cb handler, bool allow_expansion) pragma_cb handler, bool allow_expansion)
{ {
register_pragma (pfile, space, name, handler, allow_expansion, false); struct pragma_entry *entry;
if (!handler)
{
cpp_error (pfile, CPP_DL_ICE, "registering pragma with NULL handler");
return;
}
entry = register_pragma_1 (pfile, space, name, false);
if (entry)
{
entry->allow_expansion = allow_expansion;
entry->u.handler = handler;
}
}
/* Similarly, but create mark the pragma for deferred processing.
When found, a CPP_PRAGMA token will be insertted into the stream
with IDENT in the token->u.pragma slot. */
void
cpp_register_deferred_pragma (cpp_reader *pfile, const char *space,
const char *name, unsigned int ident,
bool allow_expansion, bool allow_name_expansion)
{
struct pragma_entry *entry;
entry = register_pragma_1 (pfile, space, name, allow_name_expansion);
if (entry)
{
entry->is_deferred = true;
entry->allow_expansion = allow_expansion;
entry->u.ident = ident;
}
} }
/* Register the pragmas the preprocessor itself handles. */ /* Register the pragmas the preprocessor itself handles. */
@ -1139,14 +1173,13 @@ void
_cpp_init_internal_pragmas (cpp_reader *pfile) _cpp_init_internal_pragmas (cpp_reader *pfile)
{ {
/* Pragmas in the global namespace. */ /* Pragmas in the global namespace. */
register_pragma (pfile, 0, "once", do_pragma_once, false, true); register_pragma_internal (pfile, 0, "once", do_pragma_once);
/* New GCC-specific pragmas should be put in the GCC namespace. */ /* New GCC-specific pragmas should be put in the GCC namespace. */
register_pragma (pfile, "GCC", "poison", do_pragma_poison, false, true); register_pragma_internal (pfile, "GCC", "poison", do_pragma_poison);
register_pragma (pfile, "GCC", "system_header", do_pragma_system_header, register_pragma_internal (pfile, "GCC", "system_header",
false, true); do_pragma_system_header);
register_pragma (pfile, "GCC", "dependency", do_pragma_dependency, register_pragma_internal (pfile, "GCC", "dependency", do_pragma_dependency);
false, true);
} }
/* Return the number of registered pragmas in PE. */ /* Return the number of registered pragmas in PE. */
@ -1224,11 +1257,9 @@ _cpp_restore_pragma_names (cpp_reader *pfile, char **saved)
front end. C99 defines three pragmas and says that no macro front end. C99 defines three pragmas and says that no macro
expansion is to be performed on them; whether or not macro expansion is to be performed on them; whether or not macro
expansion happens for other pragmas is implementation defined. expansion happens for other pragmas is implementation defined.
This implementation never macro-expands the text after #pragma. This implementation allows for a mix of both, since GCC did not
traditionally macro expand its (few) pragmas, whereas OpenMP
The library user has the option of deferring execution of specifies that macro expansion should happen. */
#pragmas not handled by cpplib, in which case they are converted
to CPP_PRAGMA tokens and inserted into the output stream. */
static void static void
do_pragma (cpp_reader *pfile) do_pragma (cpp_reader *pfile)
{ {
@ -1236,11 +1267,6 @@ do_pragma (cpp_reader *pfile)
const cpp_token *token, *pragma_token = pfile->cur_token; const cpp_token *token, *pragma_token = pfile->cur_token;
unsigned int count = 1; unsigned int count = 1;
/* Save the current position so that defer_pragmas mode can
copy the entire current line to a string. It will not work
to use _cpp_backup_tokens as that does not reverse buffer->cur. */
const uchar *line_start = CPP_BUFFER (pfile)->cur;
pfile->state.prevent_expansion++; pfile->state.prevent_expansion++;
token = cpp_get_token (pfile); token = cpp_get_token (pfile);
@ -1249,100 +1275,45 @@ do_pragma (cpp_reader *pfile)
p = lookup_pragma_entry (pfile->pragmas, token->val.node); p = lookup_pragma_entry (pfile->pragmas, token->val.node);
if (p && p->is_nspace) if (p && p->is_nspace)
{ {
count = 2; bool allow_name_expansion = p->allow_expansion;
if (allow_name_expansion)
pfile->state.prevent_expansion--;
token = cpp_get_token (pfile); token = cpp_get_token (pfile);
if (token->type == CPP_NAME) if (token->type == CPP_NAME)
p = lookup_pragma_entry (p->u.space, token->val.node); p = lookup_pragma_entry (p->u.space, token->val.node);
else else
p = NULL; p = NULL;
if (allow_name_expansion)
pfile->state.prevent_expansion++;
count = 2;
} }
} }
if (p) if (p)
{ {
if (p->is_internal || !CPP_OPTION (pfile, defer_pragmas)) if (p->is_deferred)
{ {
/* Since the handler below doesn't get the line number, that it pfile->directive_result.src_loc = pragma_token->src_loc;
might need for diagnostics, make sure it has the right pfile->directive_result.type = CPP_PRAGMA;
numbers in place. */ pfile->directive_result.flags = pragma_token->flags;
if (pfile->cb.line_change) pfile->directive_result.val.pragma = p->u.ident;
(*pfile->cb.line_change) (pfile, pragma_token, false); pfile->state.in_deferred_pragma = true;
/* Never expand macros if handling a deferred pragma, since pfile->state.pragma_allow_expansion = p->allow_expansion;
the macro definitions now applicable may be different if (!p->allow_expansion)
from those at the point the pragma appeared. */
if (p->allow_expansion && !pfile->state.in_deferred_pragma)
pfile->state.prevent_expansion--;
(*p->u.handler) (pfile);
if (p->allow_expansion && !pfile->state.in_deferred_pragma)
pfile->state.prevent_expansion++; pfile->state.prevent_expansion++;
} }
else else
{ {
/* Squirrel away the pragma text. Pragmas are /* Since the handler below doesn't get the line number, that
newline-terminated. */ it might need for diagnostics, make sure it has the right
const uchar *line_end; numbers in place. */
uchar *s, c, cc; if (pfile->cb.line_change)
cpp_string body; (*pfile->cb.line_change) (pfile, pragma_token, false);
cpp_token *ptok; if (p->allow_expansion)
pfile->state.prevent_expansion--;
for (line_end = line_start; (c = *line_end) != '\n'; line_end++) (*p->u.handler) (pfile);
if (c == '"' || c == '\'') if (p->allow_expansion)
{ pfile->state.prevent_expansion++;
/* Skip over string literal. */
do
{
cc = *++line_end;
if (cc == '\\' && line_end[1] != '\n')
line_end++;
else if (cc == '\n')
{
line_end--;
break;
}
}
while (cc != c);
}
else if (c == '/')
{
if (line_end[1] == '*')
{
/* Skip over C block comment, unless it is multi-line.
When encountering multi-line block comment, terminate
the pragma token right before that block comment. */
const uchar *le = line_end + 2;
while (*le != '\n')
if (*le++ == '*' && *le == '/')
{
line_end = le;
break;
}
if (line_end < le)
break;
}
else if (line_end[1] == '/'
&& (CPP_OPTION (pfile, cplusplus_comments)
|| cpp_in_system_header (pfile)))
{
line_end += 2;
while (*line_end != '\n')
line_end++;
break;
}
}
body.len = (line_end - line_start) + 1;
s = _cpp_unaligned_alloc (pfile, body.len + 1);
memcpy (s, line_start, body.len - 1);
s[body.len - 1] = '\n';
s[body.len] = '\0';
body.text = s;
/* Create a CPP_PRAGMA token. */
ptok = &pfile->directive_result;
ptok->src_loc = pragma_token->src_loc;
ptok->type = CPP_PRAGMA;
ptok->flags = pragma_token->flags | NO_EXPAND;
ptok->val.str = body;
} }
} }
else if (pfile->cb.def_pragma) else if (pfile->cb.def_pragma)
@ -1490,6 +1461,11 @@ destringize_and_run (cpp_reader *pfile, const cpp_string *in)
{ {
const unsigned char *src, *limit; const unsigned char *src, *limit;
char *dest, *result; char *dest, *result;
cpp_context *saved_context;
cpp_token *saved_cur_token;
tokenrun *saved_cur_run;
cpp_token *toks;
int count;
dest = result = (char *) alloca (in->len - 1); dest = result = (char *) alloca (in->len - 1);
src = in->text + 1 + (in->text[0] == 'L'); src = in->text + 1 + (in->text[0] == 'L');
@ -1511,36 +1487,81 @@ destringize_and_run (cpp_reader *pfile, const cpp_string *in)
Something like line-at-a-time lexing should remove the need for Something like line-at-a-time lexing should remove the need for
this. */ this. */
{ saved_context = pfile->context;
cpp_context *saved_context = pfile->context; saved_cur_token = pfile->cur_token;
cpp_token *saved_cur_token = pfile->cur_token; saved_cur_run = pfile->cur_run;
tokenrun *saved_cur_run = pfile->cur_run;
pfile->context = XNEW (cpp_context); pfile->context = XNEW (cpp_context);
pfile->context->macro = 0; pfile->context->macro = 0;
pfile->context->prev = 0; pfile->context->prev = 0;
run_directive (pfile, T_PRAGMA, result, dest - result);
XDELETE (pfile->context);
pfile->context = saved_context;
pfile->cur_token = saved_cur_token;
pfile->cur_run = saved_cur_run;
}
/* See above comment. For the moment, we'd like /* Inline run_directive, since we need to delay the _cpp_pop_buffer
until we've read all of the tokens that we want. */
cpp_push_buffer (pfile, (const uchar *) result, dest - result,
/* from_stage3 */ true);
/* ??? Antique Disgusting Hack. What does this do? */
if (pfile->buffer->prev)
pfile->buffer->file = pfile->buffer->prev->file;
token1 _Pragma ("foo") token2 start_directive (pfile);
_cpp_clean_line (pfile);
do_pragma (pfile);
end_directive (pfile, 1);
to be output as /* We always insert at least one token, the directive result. It'll
either be a CPP_PADDING or a CPP_PRAGMA. In the later case, we
need to insert *all* of the tokens, including the CPP_PRAGMA_EOL. */
token1 /* If we're not handling the pragma internally, read all of the tokens from
# 7 "file.c" the string buffer now, while the string buffer is still installed. */
#pragma foo /* ??? Note that the token buffer allocated here is leaked. It's not clear
# 7 "file.c" to me what the true lifespan of the tokens are. It would appear that
token2 the lifespan is the entire parse of the main input stream, in which case
this may not be wrong. */
if (pfile->directive_result.type == CPP_PRAGMA)
{
int maxcount;
Getting the line markers is a little tricky. */ count = 1;
if (pfile->cb.line_change) maxcount = 50;
pfile->cb.line_change (pfile, pfile->cur_token, false); toks = XNEWVEC (cpp_token, maxcount);
toks[0] = pfile->directive_result;
do
{
if (count == maxcount)
{
maxcount = maxcount * 3 / 2;
toks = XRESIZEVEC (cpp_token, toks, maxcount);
}
toks[count++] = *cpp_get_token (pfile);
}
while (toks[count-1].type != CPP_PRAGMA_EOL);
}
else
{
count = 1;
toks = XNEW (cpp_token);
toks[0] = pfile->directive_result;
/* If we handled the entire pragma internally, make sure we get the
line number correct for the next token. */
if (pfile->cb.line_change)
pfile->cb.line_change (pfile, pfile->cur_token, false);
}
/* Finish inlining run_directive. */
pfile->buffer->file = NULL;
_cpp_pop_buffer (pfile);
/* Reset the old macro state before ... */
XDELETE (pfile->context);
pfile->context = saved_context;
pfile->cur_token = saved_cur_token;
pfile->cur_run = saved_cur_run;
/* ... inserting the new tokens we collected. */
_cpp_push_token_context (pfile, NULL, toks, count);
} }
/* Handle the _Pragma operator. */ /* Handle the _Pragma operator. */
@ -1557,35 +1578,6 @@ _cpp_do__Pragma (cpp_reader *pfile)
"_Pragma takes a parenthesized string literal"); "_Pragma takes a parenthesized string literal");
} }
/* Handle a pragma that the front end deferred until now. */
void
cpp_handle_deferred_pragma (cpp_reader *pfile, const cpp_string *s)
{
cpp_context *saved_context = pfile->context;
cpp_token *saved_cur_token = pfile->cur_token;
tokenrun *saved_cur_run = pfile->cur_run;
bool saved_defer_pragmas = CPP_OPTION (pfile, defer_pragmas);
void (*saved_line_change) (cpp_reader *, const cpp_token *, int)
= pfile->cb.line_change;
pfile->context = XNEW (cpp_context);
pfile->context->macro = 0;
pfile->context->prev = 0;
pfile->cb.line_change = NULL;
pfile->state.in_deferred_pragma = true;
CPP_OPTION (pfile, defer_pragmas) = false;
run_directive (pfile, T_PRAGMA, (const char *)s->text, s->len);
XDELETE (pfile->context);
pfile->context = saved_context;
pfile->cur_token = saved_cur_token;
pfile->cur_run = saved_cur_run;
pfile->cb.line_change = saved_line_change;
pfile->state.in_deferred_pragma = false;
CPP_OPTION (pfile, defer_pragmas) = saved_defer_pragmas;
}
/* Handle #ifdef. */ /* Handle #ifdef. */
static void static void
do_ifdef (cpp_reader *pfile) do_ifdef (cpp_reader *pfile)

View File

@ -134,7 +134,8 @@ struct _cpp_file;
TK(COMMENT, LITERAL) /* Only if output comments. */ \ TK(COMMENT, LITERAL) /* Only if output comments. */ \
/* SPELL_LITERAL happens to DTRT. */ \ /* SPELL_LITERAL happens to DTRT. */ \
TK(MACRO_ARG, NONE) /* Macro argument. */ \ TK(MACRO_ARG, NONE) /* Macro argument. */ \
TK(PRAGMA, NONE) /* Only if deferring pragmas */ \ TK(PRAGMA, NONE) /* Only for deferred pragmas. */ \
TK(PRAGMA_EOL, NONE) /* End-of-line for deferred pragmas. */ \
TK(PADDING, NONE) /* Whitespace for -E. */ TK(PADDING, NONE) /* Whitespace for -E. */
#define OP(e, s) CPP_ ## e, #define OP(e, s) CPP_ ## e,
@ -182,6 +183,7 @@ enum cpp_token_fld_kind {
CPP_TOKEN_FLD_SOURCE, CPP_TOKEN_FLD_SOURCE,
CPP_TOKEN_FLD_STR, CPP_TOKEN_FLD_STR,
CPP_TOKEN_FLD_ARG_NO, CPP_TOKEN_FLD_ARG_NO,
CPP_TOKEN_FLD_PRAGMA,
CPP_TOKEN_FLD_NONE CPP_TOKEN_FLD_NONE
}; };
@ -211,6 +213,9 @@ struct cpp_token GTY(())
/* Argument no. for a CPP_MACRO_ARG. */ /* Argument no. for a CPP_MACRO_ARG. */
unsigned int GTY ((tag ("CPP_TOKEN_FLD_ARG_NO"))) arg_no; unsigned int GTY ((tag ("CPP_TOKEN_FLD_ARG_NO"))) arg_no;
/* Caller-supplied identifier for a CPP_PRAGMA. */
unsigned int GTY ((tag ("CPP_TOKEN_FLD_PRAGMA"))) pragma;
} GTY ((desc ("cpp_token_val_index (&%1)"))) val; } GTY ((desc ("cpp_token_val_index (&%1)"))) val;
}; };
@ -434,10 +439,6 @@ struct cpp_options
/* Nonzero means __STDC__ should have the value 0 in system headers. */ /* Nonzero means __STDC__ should have the value 0 in system headers. */
unsigned char stdc_0_in_system_headers; unsigned char stdc_0_in_system_headers;
/* True means return pragmas as tokens rather than processing
them directly. */
bool defer_pragmas;
/* True means error callback should be used for diagnostics. */ /* True means error callback should be used for diagnostics. */
bool client_diagnostic; bool client_diagnostic;
}; };
@ -673,7 +674,8 @@ extern unsigned char *cpp_spell_token (cpp_reader *, const cpp_token *,
unsigned char *, bool); unsigned char *, bool);
extern void cpp_register_pragma (cpp_reader *, const char *, const char *, extern void cpp_register_pragma (cpp_reader *, const char *, const char *,
void (*) (cpp_reader *), bool); void (*) (cpp_reader *), bool);
extern void cpp_handle_deferred_pragma (cpp_reader *, const cpp_string *); extern void cpp_register_deferred_pragma (cpp_reader *, const char *,
const char *, unsigned, bool, bool);
extern int cpp_avoid_paste (cpp_reader *, const cpp_token *, extern int cpp_avoid_paste (cpp_reader *, const cpp_token *,
const cpp_token *); const cpp_token *);
extern const cpp_token *cpp_get_token (cpp_reader *); extern const cpp_token *cpp_get_token (cpp_reader *);

View File

@ -205,9 +205,6 @@ struct lexer_state
/* Nonzero to prevent macro expansion. */ /* Nonzero to prevent macro expansion. */
unsigned char prevent_expansion; unsigned char prevent_expansion;
/* Nonzero when handling a deferred pragma. */
unsigned char in_deferred_pragma;
/* Nonzero when parsing arguments to a function-like macro. */ /* Nonzero when parsing arguments to a function-like macro. */
unsigned char parsing_args; unsigned char parsing_args;
@ -217,6 +214,12 @@ struct lexer_state
/* Nonzero to skip evaluating part of an expression. */ /* Nonzero to skip evaluating part of an expression. */
unsigned int skip_eval; unsigned int skip_eval;
/* Nonzero when handling a deferred pragma. */
unsigned char in_deferred_pragma;
/* Nonzero if the deferred pragma being handled allows macro expansion. */
unsigned char pragma_allow_expansion;
}; };
/* Special nodes - identifiers with predefined significance. */ /* Special nodes - identifiers with predefined significance. */
@ -496,7 +499,10 @@ extern bool _cpp_arguments_ok (cpp_reader *, cpp_macro *, const cpp_hashnode *,
unsigned int); unsigned int);
extern const unsigned char *_cpp_builtin_macro_text (cpp_reader *, extern const unsigned char *_cpp_builtin_macro_text (cpp_reader *,
cpp_hashnode *); cpp_hashnode *);
int _cpp_warn_if_unused_macro (cpp_reader *, cpp_hashnode *, void *); extern int _cpp_warn_if_unused_macro (cpp_reader *, cpp_hashnode *, void *);
extern void _cpp_push_token_context (cpp_reader *, cpp_hashnode *,
const cpp_token *, unsigned int);
/* In identifiers.c */ /* In identifiers.c */
extern void _cpp_init_hashtable (cpp_reader *, hash_table *); extern void _cpp_init_hashtable (cpp_reader *, hash_table *);
extern void _cpp_destroy_hashtable (cpp_reader *); extern void _cpp_destroy_hashtable (cpp_reader *);

View File

@ -767,24 +767,24 @@ _cpp_lex_token (cpp_reader *pfile)
/* 6.10.3 p 11: Directives in a list of macro arguments /* 6.10.3 p 11: Directives in a list of macro arguments
gives undefined behavior. This implementation gives undefined behavior. This implementation
handles the directive as normal. */ handles the directive as normal. */
&& pfile->state.parsing_args != 1 && pfile->state.parsing_args != 1)
&& _cpp_handle_directive (pfile, result->flags & PREV_WHITE))
{ {
if (pfile->directive_result.type == CPP_PADDING) if (_cpp_handle_directive (pfile, result->flags & PREV_WHITE))
continue;
else
{ {
if (pfile->directive_result.type == CPP_PADDING)
continue;
result = &pfile->directive_result; result = &pfile->directive_result;
break;
} }
} }
else if (pfile->state.in_deferred_pragma)
result = &pfile->directive_result;
if (pfile->cb.line_change && !pfile->state.skipping) if (pfile->cb.line_change && !pfile->state.skipping)
pfile->cb.line_change (pfile, result, pfile->state.parsing_args); pfile->cb.line_change (pfile, result, pfile->state.parsing_args);
} }
/* We don't skip tokens in directives. */ /* We don't skip tokens in directives. */
if (pfile->state.in_directive) if (pfile->state.in_directive || pfile->state.in_deferred_pragma)
break; break;
/* Outside a directive, invalidate controlling macros. At file /* Outside a directive, invalidate controlling macros. At file
@ -878,6 +878,14 @@ _cpp_lex_direct (cpp_reader *pfile)
buffer = pfile->buffer; buffer = pfile->buffer;
if (buffer->need_line) if (buffer->need_line)
{ {
if (pfile->state.in_deferred_pragma)
{
result->type = CPP_PRAGMA_EOL;
pfile->state.in_deferred_pragma = false;
if (!pfile->state.pragma_allow_expansion)
pfile->state.prevent_expansion--;
return result;
}
if (!_cpp_get_fresh_line (pfile)) if (!_cpp_get_fresh_line (pfile))
{ {
result->type = CPP_EOF; result->type = CPP_EOF;
@ -1697,7 +1705,7 @@ cpp_token_val_index (cpp_token *tok)
else if (tok->type == CPP_PADDING) else if (tok->type == CPP_PADDING)
return CPP_TOKEN_FLD_SOURCE; return CPP_TOKEN_FLD_SOURCE;
else if (tok->type == CPP_PRAGMA) else if (tok->type == CPP_PRAGMA)
return CPP_TOKEN_FLD_STR; return CPP_TOKEN_FLD_PRAGMA;
/* else fall through */ /* else fall through */
default: default:
return CPP_TOKEN_FLD_NONE; return CPP_TOKEN_FLD_NONE;

View File

@ -42,8 +42,6 @@ struct macro_arg
static int enter_macro_context (cpp_reader *, cpp_hashnode *); static int enter_macro_context (cpp_reader *, cpp_hashnode *);
static int builtin_macro (cpp_reader *, cpp_hashnode *); static int builtin_macro (cpp_reader *, cpp_hashnode *);
static void push_token_context (cpp_reader *, cpp_hashnode *,
const cpp_token *, unsigned int);
static void push_ptoken_context (cpp_reader *, cpp_hashnode *, _cpp_buff *, static void push_ptoken_context (cpp_reader *, cpp_hashnode *, _cpp_buff *,
const cpp_token **, unsigned int); const cpp_token **, unsigned int);
static _cpp_buff *collect_args (cpp_reader *, const cpp_hashnode *); static _cpp_buff *collect_args (cpp_reader *, const cpp_hashnode *);
@ -261,13 +259,6 @@ builtin_macro (cpp_reader *pfile, cpp_hashnode *node)
return 0; return 0;
_cpp_do__Pragma (pfile); _cpp_do__Pragma (pfile);
if (pfile->directive_result.type == CPP_PRAGMA)
{
cpp_token *tok = _cpp_temp_token (pfile);
*tok = pfile->directive_result;
push_token_context (pfile, NULL, tok, 1);
}
return 1; return 1;
} }
@ -282,7 +273,7 @@ builtin_macro (cpp_reader *pfile, cpp_hashnode *node)
/* Set pfile->cur_token as required by _cpp_lex_direct. */ /* Set pfile->cur_token as required by _cpp_lex_direct. */
pfile->cur_token = _cpp_temp_token (pfile); pfile->cur_token = _cpp_temp_token (pfile);
push_token_context (pfile, NULL, _cpp_lex_direct (pfile), 1); _cpp_push_token_context (pfile, NULL, _cpp_lex_direct (pfile), 1);
if (pfile->buffer->cur != pfile->buffer->rlimit) if (pfile->buffer->cur != pfile->buffer->rlimit)
cpp_error (pfile, CPP_DL_ICE, "invalid built-in macro \"%s\"", cpp_error (pfile, CPP_DL_ICE, "invalid built-in macro \"%s\"",
NODE_NAME (node)); NODE_NAME (node));
@ -480,7 +471,7 @@ paste_all_tokens (cpp_reader *pfile, const cpp_token *lhs)
while (rhs->flags & PASTE_LEFT); while (rhs->flags & PASTE_LEFT);
/* Put the resulting token in its own context. */ /* Put the resulting token in its own context. */
push_token_context (pfile, NULL, lhs, 1); _cpp_push_token_context (pfile, NULL, lhs, 1);
} }
/* Returns TRUE if the number of arguments ARGC supplied in an /* Returns TRUE if the number of arguments ARGC supplied in an
@ -694,7 +685,7 @@ funlike_invocation_p (cpp_reader *pfile, cpp_hashnode *node)
too difficult. We re-insert it in its own context. */ too difficult. We re-insert it in its own context. */
_cpp_backup_tokens (pfile, 1); _cpp_backup_tokens (pfile, 1);
if (padding) if (padding)
push_token_context (pfile, NULL, padding, 1); _cpp_push_token_context (pfile, NULL, padding, 1);
} }
return NULL; return NULL;
@ -750,7 +741,7 @@ enter_macro_context (cpp_reader *pfile, cpp_hashnode *node)
macro->used = 1; macro->used = 1;
if (macro->paramc == 0) if (macro->paramc == 0)
push_token_context (pfile, node, macro->exp.tokens, macro->count); _cpp_push_token_context (pfile, node, macro->exp.tokens, macro->count);
return 1; return 1;
} }
@ -943,9 +934,9 @@ push_ptoken_context (cpp_reader *pfile, cpp_hashnode *macro, _cpp_buff *buff,
} }
/* Push a list of tokens. */ /* Push a list of tokens. */
static void void
push_token_context (cpp_reader *pfile, cpp_hashnode *macro, _cpp_push_token_context (cpp_reader *pfile, cpp_hashnode *macro,
const cpp_token *first, unsigned int count) const cpp_token *first, unsigned int count)
{ {
cpp_context *context = next_context (pfile); cpp_context *context = next_context (pfile);