OSDN Git Service

libcpp/
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 4 Jan 2006 16:33:38 +0000 (16:33 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 4 Jan 2006 16:33:38 +0000 (16:33 +0000)
* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@109336 138bc75d-0d04-0410-961f-82ee72b054a4

20 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/c-common.c
gcc/c-common.h
gcc/c-lex.c
gcc/c-parser.c
gcc/c-pch.c
gcc/c-pragma.c
gcc/c-pragma.h
gcc/cp/ChangeLog
gcc/cp/lex.c
gcc/cp/parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/parse/pragma2.C
libcpp/ChangeLog
libcpp/directives.c
libcpp/include/cpplib.h
libcpp/internal.h
libcpp/lex.c
libcpp/macro.c

index b818536..a9a6e92 100644 (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>
 
        PR ada/24994
index 6c7ca28..82e5de2 100644 (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-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@
 
index 76e9096..2a7c1e7 100644 (file)
@@ -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");
index 65a0107..735250f 100644 (file)
@@ -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 */
index af3695f..44e63d7 100644 (file)
@@ -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.  */
index 8469eca..eff5b83 100644 (file)
@@ -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"
 
 \f
 /* 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)
 }
 
 \f
-/* 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));
+}
+\f
 /* 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;
 }
index 1bbcab1..37c8c30 100644 (file)
@@ -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);
index 18eafcd..e2a4677 100644 (file)
@@ -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
index 057aca6..9876555 100644 (file)
@@ -24,6 +24,16 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 
 #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.  */
 #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.  
index 29389f4..1dbf600 100644 (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
        compound stmt instead of a if(1) { } construct.
index 469efc8..a800432 100644 (file)
@@ -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)
index bfcf261..86763eb 100644 (file)
@@ -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;
 }
-\f
 /* The parser.  */
 
 static GTY (()) cp_parser *the_parser;
 
+\f
+/* 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;
+}
+
+\f
 /* External interface.  */
 
 /* Parse one entire translation unit.  */
index 1e33d4c..07b9a0d 100644 (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>
 
        * g++.dg/other/i386-2.C: New test.
index 9cab9d8..c5616ff 100644 (file)
@@ -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 *-*-* } } 
index b2f0c9a..ad66535 100644 (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>
 
        PR c++/25294
@@ -19,7 +54,7 @@
        (cpp_classify_number): Disallow hexadecimal DFP constants.
 
 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
        ATTRIBUTE_FPTR_PRINTF(3,0) instead of ATTRIBUTE_PRINTF(3,0).
index 2de65fb..0eea67d 100644 (file)
@@ -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)
index 0ab6635..f1b5eab 100644 (file)
@@ -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 *);
index 4aa6dcc..8ac1103 100644 (file)
@@ -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 *);
index 0313161..cae9b03 100644 (file)
@@ -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;
index a0aa93e..2f1a974 100644 (file)
@@ -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);