This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gomp merge][c/c++] rearrange pragma handling


This patch rearranges all extant pragma handling such that there
is only one code path.  All pragmas are deferred, and parsed in
the same token stream as the rest of the source.  This eliminates
the somewhat hidious callback-within-callback path.

Tested on ppc64-linux.  I'll wait a bit for comments from the C++
crowd before committing.


r~



libcpp/
2005-09-29  Dmitry Kurochkin <dmitry.kurochkin@gmail.com>
            Richard Henderson  <rth@redhat.com>

        * 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.
        (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.
        (cpp_handle_deferred_pragma): Remove.
        * internal.h (struct lexer_state): Add pragma_allow_expansion.
        * 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.

Index: gcc/c-lex.c
===================================================================
--- gcc/c-lex.c	(revision 107569)
+++ gcc/c-lex.c	(working copy)
@@ -453,11 +453,11 @@ c_lex_with_flags (tree *value, location_
 	  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.  */
@@ -485,13 +485,6 @@ c_lex_with_flags (tree *value, location_
   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: gcc/testsuite/g++.dg/parse/pragma2.C
===================================================================
--- gcc/testsuite/g++.dg/parse/pragma2.C	(revision 107569)
+++ gcc/testsuite/g++.dg/parse/pragma2.C	(working copy)
@@ -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: gcc/cp/lex.c
===================================================================
--- gcc/cp/lex.c	(revision 107569)
+++ gcc/cp/lex.c	(working copy)
@@ -580,7 +580,7 @@ handle_pragma_implementation (cpp_reader
 
 /* 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: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 107569)
+++ gcc/cp/parser.c	(working copy)
@@ -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_lexe
    /* 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_lexe
 	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 *l
     }
 }
 
-/* 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_
 
     case CPP_STRING:
     case CPP_WSTRING:
-    case CPP_PRAGMA:
       fprintf (stream, " \"%s\"", TREE_STRING_POINTER (token->value));
       break;
 
@@ -1456,9 +1440,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
@@ -1678,6 +1662,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
@@ -1821,6 +1809,8 @@ static void cp_parser_skip_to_closing_br
   (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
@@ -1881,12 +1871,14 @@ cp_parser_error (cp_parser* parser, cons
       /* 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
@@ -2180,7 +2172,6 @@ cp_parser_skip_to_closing_parenthesis (c
 {
   unsigned paren_depth = 0;
   unsigned brace_depth = 0;
-  int result;
 
   if (recovering && !or_comma
       && cp_parser_uncommitted_to_tentative_parse_p (parser))
@@ -2188,62 +2179,55 @@ cp_parser_skip_to_closing_parenthesis (c
 
   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.
@@ -2257,31 +2241,34 @@ cp_parser_skip_to_end_of_statement (cp_p
 
   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:
 
@@ -2294,13 +2281,17 @@ cp_parser_skip_to_end_of_statement (cp_p
 	  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);
     }
@@ -2337,15 +2328,12 @@ cp_parser_skip_to_end_of_block_or_statem
     {
       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 ';'. */
@@ -2372,7 +2360,6 @@ cp_parser_skip_to_end_of_block_or_statem
 
       /* Consume the token.  */
       cp_lexer_consume_token (parser->lexer);
-
     }
 }
 
@@ -2386,26 +2373,54 @@ cp_parser_skip_to_closing_brace (cp_pars
 
   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.  */
+
+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.  */
@@ -6001,12 +6016,14 @@ cp_parser_builtin_offsetof (cp_parser *p
      try-block  */
 
 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.  */
@@ -6023,8 +6040,8 @@ cp_parser_statement (cp_parser* parser, 
 	{
 	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:
@@ -6070,7 +6087,8 @@ cp_parser_statement (cp_parser* parser, 
 	 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)
@@ -6079,7 +6097,15 @@ cp_parser_statement (cp_parser* parser, 
      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)
@@ -6128,7 +6154,8 @@ cp_parser_statement (cp_parser* parser, 
    For an ordinary label, returns a LABEL_EXPR.  */
 
 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;
@@ -6171,20 +6198,21 @@ cp_parser_labeled_statement (cp_parser* 
 	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:
@@ -6196,7 +6224,7 @@ cp_parser_labeled_statement (cp_parser* 
   /* 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;
@@ -6278,13 +6306,16 @@ cp_parser_statement_seq_opt (cp_parser* 
   /* 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);
     }
 }
 
@@ -6781,7 +6812,7 @@ cp_parser_implicitly_scoped_statement (c
       /* 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);
     }
@@ -6803,13 +6834,13 @@ cp_parser_already_scoped_statement (cp_p
 {
   /* 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, "`}'");
     }
 }
@@ -6832,7 +6863,8 @@ cp_parser_declaration_seq_opt (cp_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)
@@ -6864,7 +6896,7 @@ cp_parser_declaration_seq_opt (cp_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;
 	}
 
@@ -12156,6 +12188,7 @@ cp_parser_parameter_declaration (cp_pars
 
 		  /* 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;
@@ -13190,7 +13223,9 @@ cp_parser_member_specification_opt (cp_p
       /* 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.  */
@@ -13212,7 +13247,7 @@ cp_parser_member_specification_opt (cp_p
 	  /* Accept #pragmas at class scope.  */
 	  if (token->type == CPP_PRAGMA)
 	    {
-	      cp_lexer_handle_pragma (parser->lexer);
+	      cp_parser_pragma (parser, pragma_external);
 	      break;
 	    }
 
@@ -15137,9 +15172,15 @@ cp_parser_function_definition_after_decl
       /* 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'.  */
@@ -15958,27 +15999,38 @@ cp_parser_skip_until_found (cp_parser* p
     {
       /* 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);
     }
@@ -16197,7 +16249,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);
@@ -16210,6 +16264,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;
     }
@@ -16946,7 +17002,7 @@ cp_parser_objc_interstitial_code (cp_par
     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);
@@ -17437,11 +17493,111 @@ cp_parser_objc_statement (cp_parser * pa
 
   return error_mark_node;
 }
-
 /* The parser.  */
 
 static GTY (()) cp_parser *the_parser;
 
+
+/* Special handling for the first token or line in the file.  The first
+   thing in the file might be #pragma GCC pch_preprocess, which loads a
+   PCH file, which is a GC collection point.  So we need to handle this
+   first pragma without benefit of an existing lexer structure.
+
+   Always returns one token to the caller in *FIRST_TOKEN.  This is 
+   either the true first token of the file, or the first token after
+   the initial pragma.  */
+
+static void
+cp_parser_initial_pragma (cp_token *first_token)
+{
+  tree name = NULL;
+
+  cp_lexer_get_preprocessor_token (NULL, first_token);
+  if (first_token->pragma_kind != PRAGMA_GCC_PCH_PREPROCESS)
+    return;
+
+  cp_lexer_get_preprocessor_token (NULL, first_token);
+  if (first_token->type == CPP_STRING)
+    {
+      name = first_token->value;
+
+      cp_lexer_get_preprocessor_token (NULL, first_token);
+      if (first_token->type != CPP_PRAGMA_EOL)
+	error ("junk at end of %<#pragma GCC pch_preprocess%>");
+    }
+  else
+    error ("expected string literal");
+
+  /* Skip to the end of the pragma.  */
+  while (first_token->type != CPP_PRAGMA_EOL && first_token->type != CPP_EOF)
+    cp_lexer_get_preprocessor_token (NULL, first_token);
+
+  /* Read one more token to return to our caller.  */
+  cp_lexer_get_preprocessor_token (NULL, first_token);
+
+  /* Now actually load the PCH file.  */
+  if (name)
+    c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name));
+}
+
+/* Normal parsing of a pragma token.  Here we can (and must) use the
+   regular lexer.  */
+
+static bool
+cp_parser_pragma (cp_parser *parser, enum pragma_context context ATTRIBUTE_UNUSED)
+{
+  cp_token *pragma_tok;
+  unsigned int id;
+
+  pragma_tok = cp_lexer_consume_token (parser->lexer);
+  gcc_assert (pragma_tok->type == CPP_PRAGMA);
+  parser->lexer->in_pragma = true;
+
+  id = pragma_tok->pragma_kind;
+  switch (id)
+    {
+    case PRAGMA_GCC_PCH_PREPROCESS:
+      error ("%<#pragma GCC pch_preprocess%> must be first");
+      break;
+
+    default:
+      gcc_assert (id >= PRAGMA_FIRST_EXTERNAL);
+      c_invoke_pragma_handler (id);
+      break;
+    }
+
+  cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+  return false;
+}
+
+/* The interface the pragma parsers have to the lexer.  */
+
+enum cpp_ttype
+pragma_lex (tree *value)
+{
+  cp_token *tok;
+  enum cpp_ttype ret;
+
+  tok = cp_lexer_peek_token (the_parser->lexer);
+
+  ret = tok->type;
+  *value = tok->value;
+
+  if (ret == CPP_PRAGMA_EOL || ret == CPP_EOF)
+    ret = CPP_EOF;
+  else if (ret == CPP_STRING)
+    *value = cp_parser_string_literal (the_parser, false, false);
+  else
+    {
+      cp_lexer_consume_token (the_parser->lexer);
+      if (ret == CPP_KEYWORD)
+	ret = CPP_NAME;
+    }
+
+  return ret;
+}
+
+
 /* External interface.  */
 
 /* Parse one entire translation unit.  */
Index: gcc/c-pch.c
===================================================================
--- gcc/c-pch.c	(revision 107569)
+++ gcc/c-pch.c	(working copy)
@@ -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: gcc/c-pragma.c
===================================================================
--- gcc/c-pragma.c	(revision 107569)
+++ gcc/c-pragma.c	(working copy)
@@ -37,6 +37,7 @@ Software Foundation, 51 Franklin Street,
 #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_UNU
       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_read
     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 
     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 *du
 
 #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: gcc/c-pragma.h
===================================================================
--- gcc/c-pragma.h	(revision 107569)
+++ gcc/c-pragma.h	(working copy)
@@ -24,6 +24,16 @@ Software Foundation, 51 Franklin Street,
 
 #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: gcc/c-common.c
===================================================================
--- gcc/c-common.c	(revision 107569)
+++ gcc/c-common.c	(working copy)
@@ -5798,6 +5798,10 @@ c_parse_error (const char *gmsgid, enum 
       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: gcc/c-common.h
===================================================================
--- gcc/c-common.h	(revision 107569)
+++ gcc/c-common.h	(working copy)
@@ -851,7 +851,7 @@ extern void c_common_read_pch (cpp_reade
 			       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: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	(revision 107569)
+++ gcc/Makefile.in	(working copy)
@@ -1470,7 +1470,8 @@ c-errors.o: c-errors.c $(CONFIG_H) $(SYS
     $(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
 
@@ -2759,6 +2760,7 @@ GTFILES = $(srcdir)/input.h $(srcdir)/co
   $(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: gcc/c-parser.c
===================================================================
--- gcc/c-parser.c	(revision 107569)
+++ gcc/c-parser.c	(working copy)
@@ -42,6 +42,7 @@ Software Foundation, 51 Franklin Street,
 #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,
 #include "toplev.h"
 #include "ggc.h"
 #include "c-common.h"
+#include "vec.h"
+#include "target.h"
 
 
 /* Miscellaneous data and functions needed for the parser.  */
@@ -263,6 +266,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.  */
@@ -284,21 +290,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;
 
@@ -355,13 +374,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:
@@ -371,12 +389,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);
@@ -573,6 +592,7 @@ c_parser_peek_2nd_token (c_parser *parse
     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];
@@ -583,16 +603,30 @@ c_parser_peek_2nd_token (c_parser *parse
 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
@@ -605,23 +639,6 @@ c_parser_set_source_position_from_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.
@@ -723,9 +740,12 @@ c_parser_skip_until_found (c_parser *par
 	  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)
@@ -760,6 +780,8 @@ c_parser_skip_to_end_of_parameter (c_par
       /* 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)
@@ -794,6 +816,8 @@ c_parser_skip_to_end_of_block_or_stateme
       /* 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)
@@ -819,6 +843,31 @@ c_parser_skip_to_end_of_block_or_stateme
   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__.  */
 
@@ -923,6 +972,9 @@ static struct c_expr c_parser_expression
 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 *);
@@ -1054,6 +1106,9 @@ c_parser_external_declaration (c_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 ())
@@ -1073,6 +1128,7 @@ c_parser_external_declaration (c_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
@@ -1133,6 +1189,7 @@ c_parser_declaration_or_fndef (c_parser 
   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)
@@ -3250,11 +3307,6 @@ c_parser_compound_statement_nostart (c_p
   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)
@@ -3307,6 +3359,21 @@ c_parser_compound_statement_nostart (c_p
 	  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:
@@ -3560,6 +3627,9 @@ c_parser_statement_after_labels (c_parse
       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);
@@ -6244,17 +6314,101 @@ c_parser_objc_keywordexpr (c_parser *par
 }
 
 
-/* The actual parser and external interface.  ??? Does this need to be
-   garbage-collected?  */
+/* Handle pragmas.  ALLOW_STMT is true if we're within the context of
+   a function and such pragmas are to be allowed.  Returns true if we
+   actually parsed such a pragma.  */
 
-static GTY (()) c_parser *the_parser;
+static bool
+c_parser_pragma (c_parser *parser, enum pragma_context context ATTRIBUTE_UNUSED)
+{
+  unsigned int id;
+
+  id = c_parser_peek_token (parser)->pragma_kind;
+  gcc_assert (id != PRAGMA_NONE);
+
+  switch (id)
+    {
+    case PRAGMA_GCC_PCH_PREPROCESS:
+      c_parser_error (parser, "%<#pragma GCC pch_preprocess%> must be first");
+      c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+      return false;
+
+    default:
+      gcc_assert (id >= PRAGMA_FIRST_EXTERNAL);
+      break;
+    }
+
+  c_parser_consume_pragma (parser);
+  c_invoke_pragma_handler (id);
+
+  /* Skip to EOL, but suppress any error message.  Those will have been 
+     generated by the handler routine through calling error, as opposed
+     to calling c_parser_error.  */
+  parser->error = true;
+  c_parser_skip_to_pragma_eol (parser);
+
+  return false;
+}
 
+/* The interface the pragma parsers have to the lexer.  */
+
+enum cpp_ttype
+pragma_lex (tree *value)
+{
+  c_token *tok = c_parser_peek_token (the_parser);
+  enum cpp_ttype ret = tok->type;
+
+  *value = tok->value;
+  if (ret == CPP_PRAGMA_EOL || ret == CPP_EOF)
+    ret = CPP_EOF;
+  else
+    {
+      if (ret == CPP_KEYWORD)
+	ret = CPP_NAME;
+      c_parser_consume_token (the_parser);
+    }
+
+  return ret;
+}
+
+static void
+c_parser_pragma_pch_preprocess (c_parser *parser)
+{
+  tree name = NULL;
+
+  c_parser_consume_pragma (parser);
+  if (c_parser_next_token_is (parser, CPP_STRING))
+    {
+      name = c_parser_peek_token (parser)->value;
+      c_parser_consume_token (parser);
+    }
+  else
+    c_parser_error (parser, "expected string literal");
+  c_parser_skip_to_pragma_eol (parser);
+
+  if (name)
+    c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name));
+}
+
 /* Parse a single source file.  */
 
 void
 c_parse_file (void)
 {
-  the_parser = c_parser_new ();
+  /* Use local storage to begin.  If the first token is a pragma, parse it.
+     If it is #pragma GCC pch_preprocess, then this will load a PCH file
+     which will cause garbage collection.  */
+  c_parser tparser;
+
+  memset (&tparser, 0, sizeof tparser);
+  the_parser = &tparser;
+
+  if (c_parser_peek_token (&tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS)
+    c_parser_pragma_pch_preprocess (&tparser);
+
+  the_parser = GGC_NEW (c_parser);
+  *the_parser = tparser;
+
   c_parser_translation_unit (the_parser);
   the_parser = NULL;
 }
Index: libcpp/directives.c
===================================================================
--- libcpp/directives.c	(revision 107569)
+++ libcpp/directives.c	(working copy)
@@ -45,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;
 };
 
@@ -105,13 +107,6 @@ static int undefine_macros (cpp_reader *
 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 *,
@@ -277,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--;
@@ -1039,86 +1036,97 @@ lookup_pragma_entry (struct pragma_entry
   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
@@ -1130,22 +1138,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.  */
@@ -1223,11 +1262,9 @@ _cpp_restore_pragma_names (cpp_reader *p
    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)
 {
@@ -1235,11 +1272,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);
@@ -1248,57 +1280,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)
 	{
-	  /* Since the handler below doesn't get the line number, that it
-	     might need for diagnostics, make sure it has the right
+	  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
 	     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;
-	  cpp_string body;
-	  cpp_token *ptok;
-
-	  line_end = ustrchr (line_start, '\n');
-
-	  body.len = (line_end - line_start) + 1;
-	  s = _cpp_unaligned_alloc (pfile, body.len + 1);
-	  memcpy (s, line_start, body.len);
-	  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)
     {
@@ -1512,35 +1533,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: libcpp/include/cpplib.h
===================================================================
--- libcpp/include/cpplib.h	(revision 107569)
+++ libcpp/include/cpplib.h	(working copy)
@@ -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,
@@ -180,6 +181,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
 };
 
@@ -209,6 +211,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;
 };
 
@@ -432,10 +437,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;
 };
@@ -671,7 +672,8 @@ extern unsigned char *cpp_spell_token (c
 				       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: libcpp/internal.h
===================================================================
--- libcpp/internal.h	(revision 107569)
+++ libcpp/internal.h	(working copy)
@@ -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.  */
Index: libcpp/lex.c
===================================================================
--- libcpp/lex.c	(revision 107569)
+++ libcpp/lex.c	(working copy)
@@ -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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]