From b75b98aa8366f8c69c546a6e0a8f0e7559540363 Mon Sep 17 00:00:00 2001 From: rth Date: Wed, 4 Jan 2006 16:33:38 +0000 Subject: [PATCH] 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) : 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) : 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@109336 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 46 ++++ gcc/Makefile.in | 4 +- gcc/c-common.c | 4 + gcc/c-common.h | 2 +- gcc/c-lex.c | 13 +- gcc/c-parser.c | 244 ++++++++++++++--- gcc/c-pch.c | 12 +- gcc/c-pragma.c | 58 +++- gcc/c-pragma.h | 25 +- gcc/cp/ChangeLog | 39 ++- gcc/cp/lex.c | 2 +- gcc/cp/parser.c | 502 +++++++++++++++++++++++------------ gcc/testsuite/ChangeLog | 5 + gcc/testsuite/g++.dg/parse/pragma2.C | 4 +- libcpp/ChangeLog | 37 ++- libcpp/directives.c | 412 ++++++++++++++-------------- libcpp/include/cpplib.h | 14 +- libcpp/internal.h | 14 +- libcpp/lex.c | 24 +- libcpp/macro.c | 23 +- 20 files changed, 989 insertions(+), 495 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b818536ad29..a9a6e927f9e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,49 @@ +2006-01-04 Richard Henderson + + Merge from gomp branch: + * c-lex.c (c_lex_with_flags) : 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 PR ada/24994 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 6c7ca28853d..82e5de26e9b 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -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-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 \ - $(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 @@ -2811,6 +2812,7 @@ GTFILES = $(srcdir)/input.h $(srcdir)/coretypes.h \ $(srcdir)/tree-profile.c $(srcdir)/tree-nested.c \ $(srcdir)/ipa-reference.c $(srcdir)/tree-ssa-structalias.h \ $(srcdir)/tree-ssa-structalias.c \ + $(srcdir)/c-pragma.h \ $(srcdir)/targhooks.c $(out_file) \ @all_gtfiles@ diff --git a/gcc/c-common.c b/gcc/c-common.c index 76e90962f9b..2a7c1e777d3 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -5803,6 +5803,10 @@ c_parse_error (const char *gmsgid, enum cpp_ttype token, tree value) free (message); 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) { message = catenate_messages (gmsgid, " before %qs token"); diff --git a/gcc/c-common.h b/gcc/c-common.h index 65a0107c69c..735250f8011 100644 --- a/gcc/c-common.h +++ b/gcc/c-common.h @@ -854,7 +854,7 @@ extern void c_common_read_pch (cpp_reader *pfile, const char *name, int fd, const char *orig); extern void c_common_write_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); /* In *-checksum.c */ diff --git a/gcc/c-lex.c b/gcc/c-lex.c index af3695f6e5a..44e63d73816 100644 --- a/gcc/c-lex.c +++ b/gcc/c-lex.c @@ -458,11 +458,11 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags) type = lex_string (tok, value, false); break; } + *value = build_string (tok->val.str.len, (char *) tok->val.str.text); + break; - /* FALLTHROUGH */ - case CPP_PRAGMA: - *value = build_string (tok->val.str.len, (char *) tok->val.str.text); + *value = build_int_cst (NULL, tok->val.pragma); break; /* 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; } -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 minimum specified by FLAGS, that can fit HIGH:LOW, or itk_none if there isn't one. */ diff --git a/gcc/c-parser.c b/gcc/c-parser.c index 8469ecad229..eff5b832347 100644 --- a/gcc/c-parser.c +++ b/gcc/c-parser.c @@ -42,6 +42,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "coretypes.h" #include "tm.h" #include "tree.h" +#include "rtl.h" #include "langhooks.h" #include "input.h" #include "cpplib.h" @@ -53,6 +54,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "toplev.h" #include "ggc.h" #include "c-common.h" +#include "vec.h" +#include "target.h" /* 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. Otherwise, this value is RID_MAX. */ 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. */ BOOL_BITFIELD in_system_header : 1; /* 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 enough tokens have been consumed to recover from the error. */ 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; + +/* 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. */ static void c_lex_one_token (c_token *token) { timevar_push (TV_LEX); + 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; + switch (token->type) { case CPP_NAME: - token->id_kind = C_ID_NONE; - token->keyword = RID_MAX; { tree decl; @@ -358,13 +377,12 @@ c_lex_one_token (c_token *token) break; } } + token->id_kind = C_ID_ID; } - token->id_kind = C_ID_ID; break; case CPP_AT_NAME: /* This only happens in Objective-C; it must be a keyword. */ token->type = CPP_KEYWORD; - token->id_kind = C_ID_NONE; token->keyword = C_RID_CODE (token->value); break; case CPP_COLON: @@ -374,12 +392,13 @@ c_lex_one_token (c_token *token) /* These tokens may affect the interpretation of any identifiers following, if doing Objective-C. */ OBJC_NEED_RAW_IDENTIFIER (0); - token->id_kind = C_ID_NONE; - token->keyword = RID_MAX; + break; + 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; default: - token->id_kind = C_ID_NONE; - token->keyword = RID_MAX; break; } timevar_pop (TV_LEX); @@ -582,6 +601,7 @@ c_parser_peek_2nd_token (c_parser *parser) return &parser->tokens[1]; gcc_assert (parser->tokens_avail == 1); gcc_assert (parser->tokens[0].type != CPP_EOF); + gcc_assert (parser->tokens[0].type != CPP_PRAGMA_EOL); c_lex_one_token (&parser->tokens[1]); parser->tokens_avail = 2; return &parser->tokens[1]; @@ -592,16 +612,30 @@ c_parser_peek_2nd_token (c_parser *parser) static void 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) parser->tokens[0] = parser->tokens[1]; - else - { - gcc_assert (parser->tokens_avail == 1); - gcc_assert (parser->tokens[0].type != CPP_EOF); - } 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 TOKEN. */ 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 FILE:LINE: MESSAGE before TOKEN 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); break; } + /* If we've run out of tokens, stop. */ if (token->type == CPP_EOF) return; + if (token->type == CPP_PRAGMA_EOL && parser->in_pragma) + return; if (token->type == CPP_OPEN_BRACE || token->type == CPP_OPEN_PAREN || 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 (token->type == CPP_EOF) return; + if (token->type == CPP_PRAGMA_EOL && parser->in_pragma) + return; if (token->type == CPP_OPEN_BRACE || token->type == CPP_OPEN_PAREN || 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 (token->type == CPP_EOF) return; + if (token->type == CPP_PRAGMA_EOL && parser->in_pragma) + return; /* If the next token is a ';', we have reached the end of the statement. */ 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; } +/* 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__. */ @@ -932,6 +981,9 @@ static struct c_expr c_parser_expression (c_parser *); static struct c_expr c_parser_expression_conv (c_parser *); 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 compiling Objective-C. */ 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"); c_parser_consume_token (parser); break; + case CPP_PRAGMA: + c_parser_pragma (parser, pragma_external); + break; case CPP_PLUS: case CPP_MINUS: 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 6.7, 6.9.1). If FNDEF_OK is true, a function definition is 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 all_prefix_attrs; bool diagnosed_no_specs = false; + specs = build_null_declspecs (); c_parser_declspecs (parser, specs, true, true, start_attr_ok); if (parser->error) @@ -1808,6 +1865,12 @@ c_parser_struct_or_union_specifier (c_parser *parser) c_parser_consume_token (parser); 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 trailing semicolon if any. */ 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)) { 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) || c_parser_next_token_is_keyword (parser, RID_DEFAULT) || (c_parser_next_token_is (parser, CPP_NAME) @@ -3325,6 +3383,21 @@ c_parser_compound_statement_nostart (c_parser *parser) else 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 { statement: @@ -3578,6 +3651,9 @@ c_parser_statement_after_labels (c_parser *parser) c_parser_error (parser, "expected statement"); c_parser_consume_token (parser); break; + case CPP_PRAGMA: + c_parser_pragma (parser, pragma_stmt); + break; default: expr_stmt: 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); continue; } + else if (c_parser_next_token_is (parser, CPP_PRAGMA)) + { + c_parser_pragma (parser, pragma_external); + continue; + } + /* Parse some comma-separated declarations. */ 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 - garbage-collected? */ +/* Handle pragmas. ALLOW_STMT is true if we're within the context of + 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. */ 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); the_parser = NULL; } diff --git a/gcc/c-pch.c b/gcc/c-pch.c index 1bbcab1193c..37c8c30da9c 100644 --- a/gcc/c-pch.c +++ b/gcc/c-pch.c @@ -441,18 +441,10 @@ c_common_no_more_pch (void) #endif 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; - if (pragma_lex (&name_t) != CPP_STRING) - { - error ("malformed #pragma GCC pch_preprocess, ignored"); - return; - } - if (!cpp_get_options (pfile)->preprocessed) { error ("pch_preprocess pragma should only be used with -fpreprocessed"); @@ -460,8 +452,6 @@ c_common_pch_pragma (cpp_reader *pfile) return; } - name = TREE_STRING_POINTER (name_t); - fd = open (name, O_RDONLY | O_BINARY, 0666); if (fd == -1) fatal_error ("%s: couldn%'t open PCH file: %m", name); diff --git a/gcc/c-pragma.c b/gcc/c-pragma.c index 18eafcd96ad..e2a46773a95 100644 --- a/gcc/c-pragma.c +++ b/gcc/c-pragma.c @@ -37,6 +37,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "vec.h" #include "target.h" + #define GCC_BAD(gmsgid) \ do { warning (OPT_Wpragmas, gmsgid); return; } while (0) #define GCC_BAD2(gmsgid, arg) \ @@ -343,7 +344,7 @@ handle_pragma_weak (cpp_reader * ARG_UNUSED (dummy)) t = pragma_lex (&x); } 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); 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"); t = pragma_lex (&x); 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) { @@ -484,7 +485,7 @@ handle_pragma_extern_prefix (cpp_reader * ARG_UNUSED (dummy)) GCC_BAD ("malformed #pragma extern_prefix, ignored"); t = pragma_lex (&x); 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) /* Note that the length includes the null terminator. */ @@ -667,26 +668,65 @@ handle_pragma_visibility (cpp_reader *dummy ATTRIBUTE_UNUSED) #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 cpplib.h in almost everywhere. */ + +static void +c_register_pragma_1 (const char *space, const char *name, + pragma_handler handler, bool allow_expansion) +{ + 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, - void (*handler) (struct cpp_reader *)) +c_register_pragma (const char *space, const char *name, pragma_handler handler) { - cpp_register_pragma (parse_in, space, name, handler, 0); + c_register_pragma_1 (space, name, handler, false); } void c_register_pragma_with_expansion (const char *space, const char *name, - void (*handler) (struct cpp_reader *)) + pragma_handler handler) +{ + c_register_pragma_1 (space, name, handler, true); +} + +void +c_invoke_pragma_handler (unsigned int id) { - cpp_register_pragma (parse_in, space, name, handler, 1); + pragma_handler handler; + + id -= PRAGMA_FIRST_EXTERNAL; + handler = *VEC_index (pragma_handler, registered_pragmas, id); + + handler (parse_in); } /* Set up front-end pragmas. */ 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_WITH_EXPANSION 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, "extern_prefix", handle_pragma_extern_prefix); - c_register_pragma ("GCC", "pch_preprocess", c_common_pch_pragma); - #ifdef REGISTER_TARGET_PRAGMAS REGISTER_TARGET_PRAGMAS (); #endif diff --git a/gcc/c-pragma.h b/gcc/c-pragma.h index 057aca6ecde..98765555ef4 100644 --- a/gcc/c-pragma.h +++ b/gcc/c-pragma.h @@ -24,6 +24,16 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include /* 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. */ #define YYDEBUG 1 extern int yydebug; @@ -53,18 +63,23 @@ extern struct cpp_reader* parse_in; extern void init_pragma (void); -/* Front-end wrappers for pragma registration to avoid dragging - cpplib.h in almost everywhere. */ -extern void c_register_pragma (const char *, const char *, - void (*) (struct cpp_reader *)); +/* Front-end wrappers for pragma registration. */ +typedef void (*pragma_handler)(struct cpp_reader *); +extern void c_register_pragma (const char *, const char *, pragma_handler); 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_pending_pragma_weaks (void); extern tree maybe_apply_renaming_pragma (tree, tree); extern void add_to_renaming_pragma_list (tree, 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 *); /* If 1, then lex strings into the execution character set. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 29389f45bdd..1dbf6004e9a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,4 +1,41 @@ -2002-01-04 Dirk Mueller +2006-01-04 Richard Henderson + + 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) : 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 * decl.c (finish_constructor_body): create simple compound stmt instead of a if(1) { } construct. diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c index 469efc83971..a8004326564 100644 --- a/gcc/cp/lex.c +++ b/gcc/cp/lex.c @@ -580,7 +580,7 @@ handle_pragma_implementation (cpp_reader* dfile ATTRIBUTE_UNUSED ) /* Indicate that this file uses Java-personality exception handling. */ static void -handle_pragma_java_exceptions (cpp_reader* dfile ATTRIBUTE_UNUSED ) +handle_pragma_java_exceptions (cpp_reader* dfile ATTRIBUTE_UNUSED) { tree x; if (pragma_lex (&x) != CPP_EOF) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index bfcf2612acf..86763eb42bd 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -55,6 +55,8 @@ typedef struct cp_token GTY (()) ENUM_BITFIELD (rid) keyword : 8; /* Token flags. */ unsigned char flags; + /* Identifier for the pragma. */ + ENUM_BITFIELD (pragma_kind) pragma_kind : 6; /* True if this token is from a system header. */ BOOL_BITFIELD in_system_header : 1; /* 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 = { - 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 0 #else @@ -112,11 +114,15 @@ typedef struct cp_lexer GTY (()) 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. */ bool debugging_p; - /* The next lexer in a linked list of lexers. */ - struct cp_lexer *next; + /* True if we're in the context of parsing a pragma, and should not + increment past the end-of-line marker. */ + bool in_pragma; } cp_lexer; /* 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 *); static void cp_lexer_purge_tokens_after (cp_lexer *, cp_token_position); -static void cp_lexer_handle_pragma - (cp_lexer *); static void cp_lexer_save_tokens (cp_lexer *); static void cp_lexer_commit_tokens @@ -196,6 +200,9 @@ static void cp_lexer_stop_debugging static cp_token_cache *cp_token_cache_new (cp_token *, cp_token *); +static void cp_parser_initial_pragma + (cp_token *); + /* Manifest constants. */ #define CP_LEXER_BUFFER_SIZE 10000 #define CP_SAVED_TOKEN_STACK 5 @@ -244,17 +251,12 @@ cp_lexer_new_main (void) size_t space; cp_token *buffer; - /* It's possible that lexing the first token will load a PCH file, - which is a GC collection point. So we have to grab the first - token before allocating any memory. Pragmas must not be deferred - as -fpch-preprocess can generate a pragma to load the PCH file in - the preprocessed output used by -save-temps. */ - cp_lexer_get_preprocessor_token (NULL, &first_token); - - /* Tell cpplib we want CPP_PRAGMA tokens. */ - cpp_get_options (parse_in)->defer_pragmas = true; + /* It's possible that parsing the first pragma will load a PCH file, + which is a GC collection point. So we have to do that before + allocating any memory. */ + cp_parser_initial_pragma (&first_token); - /* Tell pragma_lex not to merge string constants. */ + /* Tell c_lex_with_flags not to merge string constants. */ c_lex_return_raw_strings = true; c_common_no_more_pch (); @@ -296,11 +298,6 @@ cp_lexer_new_main (void) lexer->last_token = pos; 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 diagnostic functions to get the compiler source location. */ 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. */ token->type = 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; /* 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); } } - else - token->keyword = RID_MAX; + else if (token->type == 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; + } } /* 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; gcc_assert (token != &eof_token); + gcc_assert (!lexer->in_pragma || token->type != CPP_PRAGMA_EOL); 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 preserved. */ @@ -731,7 +716,6 @@ cp_lexer_print_token (FILE * stream, cp_token *token) case CPP_STRING: case CPP_WSTRING: - case CPP_PRAGMA: fprintf (stream, " \"%s\"", TREE_STRING_POINTER (token->value)); break; @@ -1463,9 +1447,9 @@ static tree cp_parser_builtin_offsetof /* Statements [gram.stmt.stmt] */ static void cp_parser_statement - (cp_parser *, tree); + (cp_parser *, tree, bool); static tree cp_parser_labeled_statement - (cp_parser *, tree); + (cp_parser *, tree, bool); static tree cp_parser_expression_statement (cp_parser *, tree); static tree cp_parser_compound_statement @@ -1685,6 +1669,10 @@ static bool cp_parser_extension_opt static void cp_parser_label_declaration (cp_parser *); +enum pragma_context { pragma_external, pragma_stmt, pragma_compound }; +static bool cp_parser_pragma + (cp_parser *, enum pragma_context); + /* Objective-C++ Productions */ static tree cp_parser_objc_message_receiver @@ -1828,6 +1816,8 @@ static void cp_parser_skip_to_closing_brace (cp_parser *); static void cp_parser_skip_until_found (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 (cp_parser *); 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 of the token we just peeked at. */ cp_lexer_set_source_position_from_token (token); + if (token->type == CPP_PRAGMA) { error ("%<#pragma%> is not allowed here"); - cp_lexer_purge_token (parser->lexer); + cp_parser_skip_to_pragma_eol (parser, token); return; } + c_parse_error (message, /* Because c_parser_error does not understand CPP_KEYWORD, keywords are treated like @@ -2187,7 +2179,6 @@ cp_parser_skip_to_closing_parenthesis (cp_parser *parser, { unsigned paren_depth = 0; unsigned brace_depth = 0; - int result; if (recovering && !or_comma && cp_parser_uncommitted_to_tentative_parse_p (parser)) @@ -2195,62 +2186,55 @@ cp_parser_skip_to_closing_parenthesis (cp_parser *parser, 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 `)'. */ - if (cp_lexer_next_token_is (parser->lexer, CPP_EOF)) + switch (token->type) { - result = 0; - break; - } + case CPP_EOF: + case CPP_PRAGMA_EOL: + /* If we've run out of tokens, then there is no closing `)'. */ + return 0; - token = cp_lexer_peek_token (parser->lexer); + case CPP_SEMICOLON: + /* This matches the processing in skip_to_end_of_statement. */ + if (!brace_depth) + return 0; + break; - /* This matches the processing in skip_to_end_of_statement. */ - if (token->type == CPP_SEMICOLON && !brace_depth) - { - result = 0; + case CPP_OPEN_BRACE: + ++brace_depth; break; - } - if (token->type == CPP_OPEN_BRACE) - ++brace_depth; - if (token->type == CPP_CLOSE_BRACE) - { + case CPP_CLOSE_BRACE: if (!brace_depth--) - { - result = 0; - break; - } - } - if (recovering && or_comma && token->type == CPP_COMMA - && !brace_depth && !paren_depth) - { - result = -1; + return 0; break; - } - if (!brace_depth) - { - /* If it is an `(', we have entered another level of nesting. */ - if (token->type == CPP_OPEN_PAREN) + case CPP_COMMA: + if (recovering && or_comma && !brace_depth && !paren_depth) + return -1; + break; + + case CPP_OPEN_PAREN: + if (!brace_depth) ++paren_depth; - /* If it is a `)', then we might be done. */ - else if (token->type == CPP_CLOSE_PAREN && !paren_depth--) + break; + + case CPP_CLOSE_PAREN: + if (!brace_depth && !paren_depth--) { if (consume_paren) cp_lexer_consume_token (parser->lexer); - { - result = 1; - break; - } + return 1; } + break; + + default: + break; } /* Consume the token. */ cp_lexer_consume_token (parser->lexer); } - - return result; } /* 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) { - cp_token *token; + cp_token *token = cp_lexer_peek_token (parser->lexer); - /* 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 `;', 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) + switch (token->type) { - /* 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: { 3 + } - we stop before consuming the closing `}', even though we + we stop before consuming the closing '}', even though we have not yet reached a `;'. */ if (nesting_depth == 0) - break; - /* If it is the closing `}' for a block that we have + return; + + /* If it is the closing '}' for a block that we have scanned, stop -- but only after consuming the token. That way given: @@ -2301,13 +2288,17 @@ cp_parser_skip_to_end_of_statement (cp_parser* parser) if (--nesting_depth == 0) { 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. */ 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); - if (token->type == CPP_EOF) - break; - switch (token->type) { case CPP_EOF: + case CPP_PRAGMA_EOL: /* If we've run out of tokens, stop. */ - nesting_depth = -1; - continue; + return; case CPP_SEMICOLON: /* 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. */ cp_lexer_consume_token (parser->lexer); - } } @@ -2393,26 +2380,56 @@ cp_parser_skip_to_closing_brace (cp_parser *parser) 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. */ 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 an unresolved identifier node, we can provide a superior diagnostic using cp_parser_diagnose_invalid_type_name. */ @@ -6005,15 +6022,20 @@ cp_parser_builtin_offsetof (cp_parser *parser) iteration-statement jump-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 -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; cp_token *token; location_t statement_location; + restart: /* There is no statement yet. */ statement = NULL_TREE; /* Peek at the next token. */ @@ -6030,8 +6052,8 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr) { case RID_CASE: case RID_DEFAULT: - statement = cp_parser_labeled_statement (parser, - in_statement_expr); + statement = cp_parser_labeled_statement (parser, in_statement_expr, + in_compound); break; case RID_IF: @@ -6077,7 +6099,8 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr) labeled-statement. */ token = cp_lexer_peek_nth_token (parser->lexer, 2); 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. */ 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. */ 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; } 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 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 -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; tree statement = error_mark_node; @@ -6178,20 +6213,21 @@ cp_parser_labeled_statement (cp_parser* parser, tree in_statement_expr) else expr_hi = NULL_TREE; - if (!parser->in_switch_statement_p) - error ("case label %qE not within a switch statement", expr); - else + if (parser->in_switch_statement_p) statement = finish_case_label (expr, expr_hi); + else + error ("case label %qE not within a switch statement", expr); } break; case RID_DEFAULT: /* Consume the `default' token. */ cp_lexer_consume_token (parser->lexer); - if (!parser->in_switch_statement_p) - error ("case label not within a switch statement"); - else + + if (parser->in_switch_statement_p) statement = finish_case_label (NULL_TREE, NULL_TREE); + else + error ("case label not within a switch statement"); break; default: @@ -6203,7 +6239,7 @@ cp_parser_labeled_statement (cp_parser* parser, tree in_statement_expr) /* Require the `:' token. */ cp_parser_require (parser, CPP_COLON, "`:'"); /* 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 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. */ 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 (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE) - || cp_lexer_next_token_is (parser->lexer, CPP_EOF)) + if (token->type == CPP_CLOSE_BRACE + || token->type == CPP_EOF + || token->type == CPP_PRAGMA_EOL) break; /* 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. */ statement = begin_compound_stmt (0); /* Parse the dependent-statement. */ - cp_parser_statement (parser, false); + cp_parser_statement (parser, NULL_TREE, false); /* Finish the dummy compound-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 (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)) - cp_parser_statement (parser, false); + cp_parser_statement (parser, NULL_TREE, false); else { /* Avoid calling cp_parser_compound_statement, so that we don't create a new scope. Do everything else by hand. */ 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, "`}'"); } } @@ -6839,7 +6878,8 @@ cp_parser_declaration_seq_opt (cp_parser* parser) token = cp_lexer_peek_token (parser->lexer); if (token->type == CPP_CLOSE_BRACE - || token->type == CPP_EOF) + || token->type == CPP_EOF + || token->type == CPP_PRAGMA_EOL) break; 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 in cp_parser_declaration. (A #pragma at block scope is handled in cp_parser_statement.) */ - cp_lexer_handle_pragma (parser->lexer); + cp_parser_pragma (parser, pragma_external); continue; } @@ -12207,6 +12247,7 @@ cp_parser_parameter_declaration (cp_parser *parser, /* If we run out of tokens, issue an error message. */ case CPP_EOF: + case CPP_PRAGMA_EOL: error ("file ends in default argument"); done = true; break; @@ -13242,7 +13283,9 @@ cp_parser_member_specification_opt (cp_parser* parser) /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); /* 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; /* See if this token is a keyword. */ @@ -13264,7 +13307,7 @@ cp_parser_member_specification_opt (cp_parser* parser) /* Accept #pragmas at class scope. */ if (token->type == CPP_PRAGMA) { - cp_lexer_handle_pragma (parser->lexer); + cp_parser_pragma (parser, pragma_external); break; } @@ -15185,9 +15228,15 @@ cp_parser_function_definition_after_declarator (cp_parser* parser, /* Issue an error message. */ error ("named return values are no longer supported"); /* Skip tokens until we reach the start of the function body. */ - while (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE) - && cp_lexer_next_token_is_not (parser->lexer, CPP_EOF)) - cp_lexer_consume_token (parser->lexer); + while (true) + { + 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 anything declared inside `f'. */ @@ -16002,27 +16051,38 @@ cp_parser_skip_until_found (cp_parser* parser, { /* Peek at the next token. */ 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) { cp_lexer_consume_token (parser->lexer); return; } - /* If we've run out of tokens, stop. */ - if (token->type == CPP_EOF) - 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) + + switch (token->type) { + 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) return; + break; + + default: + break; } + /* Consume this token. */ 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)) return; /* 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; /* Consume the next token. */ 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) 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) return; } @@ -16990,7 +17054,7 @@ cp_parser_objc_interstitial_code (cp_parser* parser) cp_parser_linkage_specification (parser); /* Handle #pragma, if any. */ else if (token->type == CPP_PRAGMA) - cp_lexer_handle_pragma (parser->lexer); + cp_parser_pragma (parser, pragma_external); /* Allow stray semicolons. */ else if (token->type == CPP_SEMICOLON) cp_lexer_consume_token (parser->lexer); @@ -17482,11 +17546,111 @@ cp_parser_objc_statement (cp_parser * parser) { return error_mark_node; } - /* 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. */ /* Parse one entire translation unit. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1e33d4c9c63..07b9a0df5f7 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2006-01-04 Richard Henderson + + Merge from gomp branch. + * g++.dg/parse/pragma2.C: Update expected error lines. + 2006-01-04 Jakub Jelinek * g++.dg/other/i386-2.C: New test. diff --git a/gcc/testsuite/g++.dg/parse/pragma2.C b/gcc/testsuite/g++.dg/parse/pragma2.C index 9cab9d88b87..c5616ff74f5 100644 --- a/gcc/testsuite/g++.dg/parse/pragma2.C +++ b/gcc/testsuite/g++.dg/parse/pragma2.C @@ -2,7 +2,7 @@ // Ideally, the #pragma error would come one line further down, but it // does not. -int f(int x, // { dg-error "not allowed here" } -#pragma interface +int f(int x, +#pragma interface // { dg-error "not allowed here" } // The parser gets confused and issues an error on the next line. int y); // { dg-bogus "" "" { xfail *-*-* } } diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog index b2f0c9a2bf9..ad6653572cd 100644 --- a/libcpp/ChangeLog +++ b/libcpp/ChangeLog @@ -1,3 +1,38 @@ +2006-01-04 Dmitry Kurochkin + Richard Henderson + + 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 PR c++/25294 @@ -19,7 +54,7 @@ (cpp_classify_number): Disallow hexadecimal DFP constants. 2005-11-14 Gerald Pfeifer - Ian Lance Taylor + Ian Lance Taylor * include/cpplib.h (struct cpp_callbacks): Annotate error with ATTRIBUTE_FPTR_PRINTF(3,0) instead of ATTRIBUTE_PRINTF(3,0). diff --git a/libcpp/directives.c b/libcpp/directives.c index 2de65fbeaa3..0eea67d133c 100644 --- a/libcpp/directives.c +++ b/libcpp/directives.c @@ -1,7 +1,6 @@ /* CPP Library. (Directive handling.) Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. Contributed by Per Bothner, 1994-95. Based on CCCP program by Paul Rubin, June 1986 Adapted to ANSI C, Richard Stallman, Jan 1987 @@ -46,11 +45,13 @@ struct pragma_entry struct pragma_entry *next; const cpp_hashnode *pragma; /* Name and length. */ bool is_nspace; - bool allow_expansion; bool is_internal; + bool is_deferred; + bool allow_expansion; union { pragma_cb handler; struct pragma_entry *space; + unsigned int ident; } 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 struct pragma_entry *lookup_pragma_entry (struct pragma_entry *, 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 char ** save_registered_pragmas (struct pragma_entry *, char **); static char ** restore_registered_pragmas (cpp_reader *, struct pragma_entry *, @@ -278,7 +272,9 @@ start_directive (cpp_reader *pfile) static void 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. */ 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, /* from_stage3 */ true); - /* Disgusting hack. */ - if (dir_no == T_PRAGMA && pfile->buffer->prev) - pfile->buffer->file = pfile->buffer->prev->file; start_directive (pfile); /* 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); pfile->directive->handler (pfile); end_directive (pfile, 1); - if (dir_no == T_PRAGMA) - pfile->buffer->file = NULL; _cpp_pop_buffer (pfile); } @@ -1040,86 +1031,97 @@ lookup_pragma_entry (struct pragma_entry *chain, const cpp_hashnode *pragma) return chain; } -/* Create and insert a pragma entry for NAME at the beginning of a - singly-linked CHAIN. If handler is NULL, it is a namespace, - otherwise it is a pragma and its handler. If INTERNAL is true - this pragma is being inserted by libcpp itself. */ +/* Create and insert a blank pragma entry at the beginning of a + singly-linked CHAIN. */ static struct pragma_entry * -insert_pragma_entry (cpp_reader *pfile, struct pragma_entry **chain, - const cpp_hashnode *pragma, pragma_cb handler, - bool allow_expansion, bool internal) +new_pragma_entry (cpp_reader *pfile, struct pragma_entry **chain) { struct pragma_entry *new_entry; new_entry = (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; - new_entry->is_internal = internal; + memset (new_entry, 0, sizeof (struct pragma_entry)); new_entry->next = *chain; + *chain = new_entry; return new_entry; } /* Register a pragma NAME in namespace SPACE. If SPACE is null, it - goes in the global namespace. HANDLER is the handler it will call, - which must be non-NULL. If ALLOW_EXPANSION is set, allow macro - expansion while parsing pragma NAME. INTERNAL is true if this is a - pragma registered by cpplib itself, false if it is registered via - cpp_register_pragma */ -static void -register_pragma (cpp_reader *pfile, const char *space, const char *name, - pragma_cb handler, bool allow_expansion, bool internal) + goes in the global namespace. */ +static struct pragma_entry * +register_pragma_1 (cpp_reader *pfile, const char *space, const char *name, + bool allow_name_expansion) { struct pragma_entry **chain = &pfile->pragmas; struct pragma_entry *entry; const cpp_hashnode *node; - if (!handler) - abort (); - if (space) { node = cpp_lookup (pfile, U space, strlen (space)); entry = lookup_pragma_entry (*chain, node); 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) 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; } + 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. */ node = cpp_lookup (pfile, U name, strlen (name)); entry = lookup_pragma_entry (*chain, node); - if (entry) + if (entry == NULL) { - 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 - cpp_error (pfile, CPP_DL_ICE, "#pragma %s is already registered", name); + entry = new_pragma_entry (pfile, chain); + entry->pragma = node; + return entry; } + + 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 - insert_pragma_entry (pfile, chain, node, handler, allow_expansion, - internal); + cpp_error (pfile, CPP_DL_ICE, "#pragma %s is already registered", name); + + 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 @@ -1131,22 +1133,53 @@ void cpp_register_pragma (cpp_reader *pfile, const char *space, const char *name, 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. */ void _cpp_init_internal_pragmas (cpp_reader *pfile) { /* 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. */ - register_pragma (pfile, "GCC", "poison", do_pragma_poison, false, true); - register_pragma (pfile, "GCC", "system_header", do_pragma_system_header, - false, true); - register_pragma (pfile, "GCC", "dependency", do_pragma_dependency, - false, true); + register_pragma_internal (pfile, "GCC", "poison", do_pragma_poison); + register_pragma_internal (pfile, "GCC", "system_header", + do_pragma_system_header); + register_pragma_internal (pfile, "GCC", "dependency", do_pragma_dependency); } /* 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 expansion is to be performed on them; whether or not macro expansion happens for other pragmas is implementation defined. - This implementation never macro-expands the text after #pragma. - - The library user has the option of deferring execution of - #pragmas not handled by cpplib, in which case they are converted - to CPP_PRAGMA tokens and inserted into the output stream. */ + This implementation allows for a mix of both, since GCC did not + traditionally macro expand its (few) pragmas, whereas OpenMP + specifies that macro expansion should happen. */ static void do_pragma (cpp_reader *pfile) { @@ -1236,11 +1267,6 @@ do_pragma (cpp_reader *pfile) const cpp_token *token, *pragma_token = pfile->cur_token; 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++; token = cpp_get_token (pfile); @@ -1249,101 +1275,46 @@ do_pragma (cpp_reader *pfile) p = lookup_pragma_entry (pfile->pragmas, token->val.node); 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); if (token->type == CPP_NAME) p = lookup_pragma_entry (p->u.space, token->val.node); else p = NULL; + if (allow_name_expansion) + pfile->state.prevent_expansion++; + count = 2; } } if (p) { - if (p->is_internal || !CPP_OPTION (pfile, defer_pragmas)) + if (p->is_deferred) + { + pfile->directive_result.src_loc = pragma_token->src_loc; + pfile->directive_result.type = CPP_PRAGMA; + pfile->directive_result.flags = pragma_token->flags; + pfile->directive_result.val.pragma = p->u.ident; + pfile->state.in_deferred_pragma = true; + pfile->state.pragma_allow_expansion = p->allow_expansion; + if (!p->allow_expansion) + pfile->state.prevent_expansion++; + } + else { - /* Since the handler below doesn't get the line number, that it - might need for diagnostics, make sure it has the right + /* Since the handler below doesn't get the line number, that + it might need for diagnostics, make sure it has the right numbers in place. */ if (pfile->cb.line_change) (*pfile->cb.line_change) (pfile, pragma_token, false); - /* Never expand macros if handling a deferred pragma, since - the macro definitions now applicable may be different - from those at the point the pragma appeared. */ - if (p->allow_expansion && !pfile->state.in_deferred_pragma) + if (p->allow_expansion) pfile->state.prevent_expansion--; (*p->u.handler) (pfile); - if (p->allow_expansion && !pfile->state.in_deferred_pragma) + if (p->allow_expansion) pfile->state.prevent_expansion++; } - else - { - /* Squirrel away the pragma text. Pragmas are - newline-terminated. */ - const uchar *line_end; - uchar *s, c, cc; - cpp_string body; - cpp_token *ptok; - - for (line_end = line_start; (c = *line_end) != '\n'; line_end++) - if (c == '"' || c == '\'') - { - /* 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) { @@ -1490,6 +1461,11 @@ destringize_and_run (cpp_reader *pfile, const cpp_string *in) { const unsigned char *src, *limit; 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); 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 this. */ - { - cpp_context *saved_context = pfile->context; - cpp_token *saved_cur_token = pfile->cur_token; - tokenrun *saved_cur_run = pfile->cur_run; - - pfile->context = XNEW (cpp_context); - pfile->context->macro = 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; - } + saved_context = pfile->context; + saved_cur_token = pfile->cur_token; + saved_cur_run = pfile->cur_run; - /* See above comment. For the moment, we'd like + pfile->context = XNEW (cpp_context); + pfile->context->macro = 0; + pfile->context->prev = 0; - token1 _Pragma ("foo") token2 + /* 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; - to be output as + start_directive (pfile); + _cpp_clean_line (pfile); + do_pragma (pfile); + end_directive (pfile, 1); - token1 - # 7 "file.c" - #pragma foo - # 7 "file.c" - token2 + /* 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. */ + + /* If we're not handling the pragma internally, read all of the tokens from + the string buffer now, while the string buffer is still installed. */ + /* ??? Note that the token buffer allocated here is leaked. It's not clear + to me what the true lifespan of the tokens are. It would appear that + 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; + + count = 1; + maxcount = 50; + toks = XNEWVEC (cpp_token, maxcount); + toks[0] = pfile->directive_result; - Getting the line markers is a little tricky. */ - if (pfile->cb.line_change) - pfile->cb.line_change (pfile, pfile->cur_token, false); + 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. */ @@ -1557,35 +1578,6 @@ _cpp_do__Pragma (cpp_reader *pfile) "_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. */ static void do_ifdef (cpp_reader *pfile) diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h index 0ab66357341..f1b5eab93e2 100644 --- a/libcpp/include/cpplib.h +++ b/libcpp/include/cpplib.h @@ -134,7 +134,8 @@ struct _cpp_file; TK(COMMENT, LITERAL) /* Only if output comments. */ \ /* SPELL_LITERAL happens to DTRT. */ \ 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. */ #define OP(e, s) CPP_ ## e, @@ -182,6 +183,7 @@ enum cpp_token_fld_kind { CPP_TOKEN_FLD_SOURCE, CPP_TOKEN_FLD_STR, CPP_TOKEN_FLD_ARG_NO, + CPP_TOKEN_FLD_PRAGMA, CPP_TOKEN_FLD_NONE }; @@ -211,6 +213,9 @@ struct cpp_token GTY(()) /* Argument no. for a CPP_MACRO_ARG. */ 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; }; @@ -434,10 +439,6 @@ struct cpp_options /* Nonzero means __STDC__ should have the value 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. */ bool client_diagnostic; }; @@ -673,7 +674,8 @@ extern unsigned char *cpp_spell_token (cpp_reader *, const cpp_token *, unsigned char *, bool); extern void cpp_register_pragma (cpp_reader *, const char *, const char *, 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 *, const cpp_token *); extern const cpp_token *cpp_get_token (cpp_reader *); diff --git a/libcpp/internal.h b/libcpp/internal.h index 4aa6dcc510b..8ac1103c2d7 100644 --- a/libcpp/internal.h +++ b/libcpp/internal.h @@ -205,9 +205,6 @@ struct lexer_state /* Nonzero to prevent macro 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. */ unsigned char parsing_args; @@ -217,6 +214,12 @@ struct lexer_state /* Nonzero to skip evaluating part of an expression. */ 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. */ @@ -496,7 +499,10 @@ extern bool _cpp_arguments_ok (cpp_reader *, cpp_macro *, const cpp_hashnode *, unsigned int); extern const unsigned char *_cpp_builtin_macro_text (cpp_reader *, 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 */ extern void _cpp_init_hashtable (cpp_reader *, hash_table *); extern void _cpp_destroy_hashtable (cpp_reader *); diff --git a/libcpp/lex.c b/libcpp/lex.c index 03131618eb5..cae9b037663 100644 --- a/libcpp/lex.c +++ b/libcpp/lex.c @@ -767,24 +767,24 @@ _cpp_lex_token (cpp_reader *pfile) /* 6.10.3 p 11: Directives in a list of macro arguments gives undefined behavior. This implementation handles the directive as normal. */ - && pfile->state.parsing_args != 1 - && _cpp_handle_directive (pfile, result->flags & PREV_WHITE)) + && pfile->state.parsing_args != 1) { - if (pfile->directive_result.type == CPP_PADDING) - continue; - else + if (_cpp_handle_directive (pfile, result->flags & PREV_WHITE)) { + if (pfile->directive_result.type == CPP_PADDING) + continue; result = &pfile->directive_result; - break; } } + else if (pfile->state.in_deferred_pragma) + result = &pfile->directive_result; if (pfile->cb.line_change && !pfile->state.skipping) pfile->cb.line_change (pfile, result, pfile->state.parsing_args); } /* We don't skip tokens in directives. */ - if (pfile->state.in_directive) + if (pfile->state.in_directive || pfile->state.in_deferred_pragma) break; /* Outside a directive, invalidate controlling macros. At file @@ -878,6 +878,14 @@ _cpp_lex_direct (cpp_reader *pfile) buffer = pfile->buffer; 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)) { result->type = CPP_EOF; @@ -1697,7 +1705,7 @@ cpp_token_val_index (cpp_token *tok) else if (tok->type == CPP_PADDING) return CPP_TOKEN_FLD_SOURCE; else if (tok->type == CPP_PRAGMA) - return CPP_TOKEN_FLD_STR; + return CPP_TOKEN_FLD_PRAGMA; /* else fall through */ default: return CPP_TOKEN_FLD_NONE; diff --git a/libcpp/macro.c b/libcpp/macro.c index a0aa93ea994..2f1a97497a1 100644 --- a/libcpp/macro.c +++ b/libcpp/macro.c @@ -42,8 +42,6 @@ struct macro_arg static int enter_macro_context (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 *, const cpp_token **, unsigned int); static _cpp_buff *collect_args (cpp_reader *, const cpp_hashnode *); @@ -261,13 +259,6 @@ builtin_macro (cpp_reader *pfile, cpp_hashnode *node) return 0; _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; } @@ -282,7 +273,7 @@ builtin_macro (cpp_reader *pfile, cpp_hashnode *node) /* Set pfile->cur_token as required by _cpp_lex_direct. */ 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) cpp_error (pfile, CPP_DL_ICE, "invalid built-in macro \"%s\"", NODE_NAME (node)); @@ -480,7 +471,7 @@ paste_all_tokens (cpp_reader *pfile, const cpp_token *lhs) while (rhs->flags & PASTE_LEFT); /* 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 @@ -694,7 +685,7 @@ funlike_invocation_p (cpp_reader *pfile, cpp_hashnode *node) too difficult. We re-insert it in its own context. */ _cpp_backup_tokens (pfile, 1); if (padding) - push_token_context (pfile, NULL, padding, 1); + _cpp_push_token_context (pfile, NULL, padding, 1); } return NULL; @@ -750,7 +741,7 @@ enter_macro_context (cpp_reader *pfile, cpp_hashnode *node) macro->used = 1; 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; } @@ -943,9 +934,9 @@ push_ptoken_context (cpp_reader *pfile, cpp_hashnode *macro, _cpp_buff *buff, } /* Push a list of tokens. */ -static void -push_token_context (cpp_reader *pfile, cpp_hashnode *macro, - const cpp_token *first, unsigned int count) +void +_cpp_push_token_context (cpp_reader *pfile, cpp_hashnode *macro, + const cpp_token *first, unsigned int count) { cpp_context *context = next_context (pfile); -- 2.11.4.GIT