#include "c-pragma.h" /* For parse_in. */
#include "file-prefix-map.h" /* remap_macro_filename() */
+class token_streamer;
+
/* Encapsulates state used to convert a stream of tokens into a text
file. */
static struct
bool prev_was_system_token; /* True if the previous token was a
system token.*/
const char *src_file; /* Current source file. */
+ token_streamer *streamer; /* Instance of class token_streamer using this
+ object. */
} print;
/* Defined and undefined macros being queued for output with -dU at
putc ('\n', print.outf);
}
+/* Don't emit #pragma or #ident directives if we are processing
+ assembly language; the assembler may choke on them. */
+static bool
+should_output_pragmas ()
+{
+ return cpp_get_options (parse_in)->lang != CLK_ASM;
+}
+
/* Set up the callbacks as appropriate. */
void
init_pp_output (FILE *out_stream)
if (!flag_no_output)
{
cb->line_change = cb_line_change;
- /* Don't emit #pragma or #ident directives if we are processing
- assembly language; the assembler may choke on them. */
- if (cpp_get_options (parse_in)->lang != CLK_ASM)
+ if (should_output_pragmas ())
{
cb->ident = cb_ident;
cb->def_pragma = cb_def_pragma;
print.first_time = 1;
print.src_file = "";
print.prev_was_system_token = false;
+ print.streamer = nullptr;
}
// FIXME: Ideally we'd just turn the entirety of the print struct into
in_pragma (false),
line_marker_emitted (false)
{
+ gcc_assert (!print.streamer);
+ print.streamer = this;
}
void begin_pragma ()
print.printed = true;
}
}
- else if (token->flags & PREV_WHITE)
+ else if (token->flags & PREV_WHITE && token->type != CPP_PRAGMA)
{
unsigned src_line = LOCATION_LINE (loc);
print.prev = token;
if (token->type == CPP_PRAGMA)
{
- const char *space;
- const char *name;
-
- line_marker_emitted = maybe_print_line (token->src_loc);
- fputs ("#pragma ", print.outf);
- c_pp_lookup_pragma (token->val.pragma, &space, &name);
- if (space)
- fprintf (print.outf, "%s %s", space, name);
- else
- fprintf (print.outf, "%s", name);
- print.printed = true;
in_pragma = true;
+ if (should_output_pragmas ())
+ {
+ const char *space;
+ const char *name;
+
+ line_marker_emitted = maybe_print_line (token->src_loc);
+ fputs ("#pragma ", print.outf);
+ c_pp_lookup_pragma (token->val.pragma, &space, &name);
+ if (space)
+ fprintf (print.outf, "%s %s", space, name);
+ else
+ fprintf (print.outf, "%s", name);
+ print.printed = true;
+ }
+ if (token->val.pragma >= PRAGMA_FIRST_EXTERNAL)
+ c_pp_invoke_early_pragma_handler (token->val.pragma);
}
else if (token->type == CPP_PRAGMA_EOL)
{
- maybe_print_line (UNKNOWN_LOCATION);
+ if (should_output_pragmas ())
+ maybe_print_line (UNKNOWN_LOCATION);
in_pragma = false;
}
else
do_line_change (pfile, token, loc, false);
print.prev_was_system_token = !!in_system_header_at (loc);
}
- cpp_output_token (token, print.outf);
- line_marker_emitted = false;
- print.printed = true;
+ if (!in_pragma || should_output_pragmas ())
+ {
+ cpp_output_token (token, print.outf);
+ line_marker_emitted = false;
+ print.printed = true;
+ }
}
/* CPP_COMMENT tokens and raw-string literal tokens can have
one space per column greater than 2, since scan_translation_unit
will provide a space if PREV_WHITE. Don't bother trying to
reconstruct tabs; we can't get it right in general, and nothing
- ought to care. Some things do care; the fault lies with them. */
- if (!CPP_OPTION (pfile, traditional))
+ ought to care. Some things do care; the fault lies with them.
+
+ Also do not output the spaces if this is a CPP_PRAGMA token. In this
+ case, libcpp has provided the location of the first token after #pragma,
+ so we would start at the wrong column. */
+ if (!CPP_OPTION (pfile, traditional) && token->type != CPP_PRAGMA)
{
int spaces = LOCATION_COLUMN (src_loc) - 2;
print.printed = true;
print.src_line++;
}
+/* Stream a token as if we had seen it directly ourselves; needed
+ in case a token was lexed externally, e.g. while processing a
+ pragma. */
+void
+c_pp_stream_token (cpp_reader *pfile, const cpp_token *tok, location_t loc)
+{
+ gcc_assert (print.streamer);
+ print.streamer->stream (pfile, tok, loc);
+}
+
/* Dump out the hash table. */
static int
dump_macro (cpp_reader *pfile, cpp_hashnode *node, void *v ATTRIBUTE_UNUSED)
warning (OPT_Wpragmas, "junk at end of %<#pragma GCC visibility%>");
}
+/* Helper routines for parsing #pragma GCC diagnostic. */
+class pragma_diagnostic_data
+{
+ pragma_diagnostic_data (const pragma_diagnostic_data &) = delete;
+ pragma_diagnostic_data& operator= (const pragma_diagnostic_data &) = delete;
+
+public:
+ bool valid;
+ location_t loc_kind, loc_option;
+ enum pd_kind_t
+ {
+ PK_INVALID,
+ PK_PUSH,
+ PK_POP,
+ PK_IGNORED_ATTRIBUTES,
+ PK_DIAGNOSTIC,
+ } pd_kind;
+ diagnostic_t diagnostic_kind;
+ const char *kind_str;
+ const char *option_str;
+ bool own_option_str;
+
+ pragma_diagnostic_data () { clear (); }
+ void clear ()
+ {
+ valid = false;
+ loc_kind = loc_option = UNKNOWN_LOCATION;
+ pd_kind = PK_INVALID;
+ diagnostic_kind = DK_UNSPECIFIED;
+ kind_str = option_str = nullptr;
+ own_option_str = false;
+ }
+
+ ~pragma_diagnostic_data ()
+ {
+ if (own_option_str && option_str)
+ XDELETEVEC (const_cast<char *> (option_str));
+ }
+
+ void set_kind (const char *kind_string)
+ {
+ kind_str = kind_string;
+
+ pd_kind = PK_INVALID;
+ diagnostic_kind = DK_UNSPECIFIED;
+ if (strcmp (kind_str, "push") == 0)
+ pd_kind = PK_PUSH;
+ else if (strcmp (kind_str, "pop") == 0)
+ pd_kind = PK_POP;
+ else if (strcmp (kind_str, "ignored_attributes") == 0)
+ pd_kind = PK_IGNORED_ATTRIBUTES;
+ else if (strcmp (kind_str, "error") == 0)
+ {
+ pd_kind = PK_DIAGNOSTIC;
+ diagnostic_kind = DK_ERROR;
+ }
+ else if (strcmp (kind_str, "warning") == 0)
+ {
+ pd_kind = PK_DIAGNOSTIC;
+ diagnostic_kind = DK_WARNING;
+ }
+ else if (strcmp (kind_str, "ignored") == 0)
+ {
+ pd_kind = PK_DIAGNOSTIC;
+ diagnostic_kind = DK_IGNORED;
+ }
+ }
+
+ bool needs_option () const
+ {
+ return pd_kind == PK_IGNORED_ATTRIBUTES
+ || pd_kind == PK_DIAGNOSTIC;
+ }
+
+};
+
+/* When compiling normally, use pragma_lex () to obtain the needed tokens.
+ This will call into either the C or C++ frontends as appropriate. */
+
static void
-handle_pragma_diagnostic(cpp_reader *)
+pragma_diagnostic_lex_normal (pragma_diagnostic_data *result)
{
+ result->clear ();
tree x;
- location_t loc;
- enum cpp_ttype token = pragma_lex (&x, &loc);
- if (token != CPP_NAME)
+ auto ttype = pragma_lex (&x, &result->loc_kind);
+ if (ttype != CPP_NAME)
+ return;
+ result->set_kind (IDENTIFIER_POINTER (x));
+ if (result->pd_kind == pragma_diagnostic_data::PK_INVALID)
+ return;
+
+ if (result->needs_option ())
{
- warning_at (loc, OPT_Wpragmas,
- "missing %<error%>, %<warning%>, %<ignored%>, %<push%>, "
- "%<pop%>, or %<ignored_attributes%> after "
- "%<#pragma GCC diagnostic%>");
- return;
+ ttype = pragma_lex (&x, &result->loc_option);
+ if (ttype != CPP_STRING)
+ return;
+ result->option_str = TREE_STRING_POINTER (x);
}
- diagnostic_t kind;
- const char *kind_string = IDENTIFIER_POINTER (x);
- if (strcmp (kind_string, "error") == 0)
- kind = DK_ERROR;
- else if (strcmp (kind_string, "warning") == 0)
- kind = DK_WARNING;
- else if (strcmp (kind_string, "ignored") == 0)
- kind = DK_IGNORED;
- else if (strcmp (kind_string, "push") == 0)
+ result->valid = true;
+}
+
+/* When preprocessing only, pragma_lex () is not available, so obtain the
+ tokens directly from libcpp. We also need to inform the token streamer
+ about all tokens we lex ourselves here, so it outputs them too; this is
+ done by calling c_pp_stream_token () for each.
+
+ ??? If we need to support more pragmas in the future, maybe initialize
+ this_parser with the pragma tokens and call pragma_lex () instead? */
+
+static void
+pragma_diagnostic_lex_pp (pragma_diagnostic_data *result)
+{
+ result->clear ();
+
+ auto tok = cpp_get_token_with_location (parse_in, &result->loc_kind);
+ c_pp_stream_token (parse_in, tok, result->loc_kind);
+ if (!(tok->type == CPP_NAME || tok->type == CPP_KEYWORD))
+ return;
+ const unsigned char *const kind_u = cpp_token_as_text (parse_in, tok);
+ result->set_kind ((const char *)kind_u);
+ if (result->pd_kind == pragma_diagnostic_data::PK_INVALID)
+ return;
+
+ if (result->needs_option ())
{
- diagnostic_push_diagnostics (global_dc, input_location);
- return;
+ tok = cpp_get_token_with_location (parse_in, &result->loc_option);
+ c_pp_stream_token (parse_in, tok, result->loc_option);
+ if (tok->type != CPP_STRING)
+ return;
+ cpp_string str;
+ if (!cpp_interpret_string_notranslate (parse_in, &tok->val.str, 1, &str,
+ CPP_STRING)
+ || !str.len)
+ return;
+ result->option_str = (const char *)str.text;
+ result->own_option_str = true;
}
- else if (strcmp (kind_string, "pop") == 0)
+
+ result->valid = true;
+}
+
+/* Handle #pragma GCC diagnostic. Early mode is used by frontends (such as C++)
+ that do not process the deferred pragma while they are consuming tokens; they
+ can use early mode to make sure diagnostics affecting the preprocessor itself
+ are correctly modified by the #pragma. */
+template<bool early, bool is_pp> static void
+handle_pragma_diagnostic_impl ()
+{
+ static const bool want_diagnostics = (is_pp || !early);
+
+ pragma_diagnostic_data data;
+ if (is_pp)
+ pragma_diagnostic_lex_pp (&data);
+ else
+ pragma_diagnostic_lex_normal (&data);
+
+ if (!data.kind_str)
{
- diagnostic_pop_diagnostics (global_dc, input_location);
+ if (want_diagnostics)
+ warning_at (data.loc_kind, OPT_Wpragmas,
+ "missing %<error%>, %<warning%>, %<ignored%>, %<push%>, "
+ "%<pop%>, or %<ignored_attributes%> after "
+ "%<#pragma GCC diagnostic%>");
return;
}
- else if (strcmp (kind_string, "ignored_attributes") == 0)
+
+ switch (data.pd_kind)
{
- token = pragma_lex (&x, &loc);
- if (token != CPP_STRING)
- {
- warning_at (loc, OPT_Wpragmas,
- "missing attribute name after %<#pragma GCC diagnostic "
- "ignored_attributes%>");
- return;
- }
- char *args = xstrdup (TREE_STRING_POINTER (x));
- const size_t l = strlen (args);
- if (l == 0)
- {
- warning_at (loc, OPT_Wpragmas, "missing argument to %<#pragma GCC "
- "diagnostic ignored_attributes%>");
- free (args);
+
+ case pragma_diagnostic_data::PK_PUSH:
+ diagnostic_push_diagnostics (global_dc, input_location);
+ return;
+
+ case pragma_diagnostic_data::PK_POP:
+ diagnostic_pop_diagnostics (global_dc, input_location);
+ return;
+
+ case pragma_diagnostic_data::PK_IGNORED_ATTRIBUTES:
+ {
+ if (early)
return;
- }
- else if (args[l - 1] == ',')
+ if (!data.option_str)
+ {
+ warning_at (data.loc_option, OPT_Wpragmas,
+ "missing attribute name after %<#pragma GCC diagnostic "
+ "ignored_attributes%>");
+ return;
+ }
+ char *args = xstrdup (data.option_str);
+ const size_t l = strlen (args);
+ if (l == 0)
+ {
+ warning_at (data.loc_option, OPT_Wpragmas,
+ "missing argument to %<#pragma GCC "
+ "diagnostic ignored_attributes%>");
+ free (args);
+ return;
+ }
+ else if (args[l - 1] == ',')
+ {
+ warning_at (data.loc_option, OPT_Wpragmas,
+ "trailing %<,%> in arguments for "
+ "%<#pragma GCC diagnostic ignored_attributes%>");
+ free (args);
+ return;
+ }
+ auto_vec<char *> v;
+ for (char *p = strtok (args, ","); p; p = strtok (NULL, ","))
+ v.safe_push (p);
+ handle_ignored_attributes_option (&v);
+ free (args);
+ return;
+ }
+
+ case pragma_diagnostic_data::PK_DIAGNOSTIC:
+ if (!data.option_str)
{
- warning_at (loc, OPT_Wpragmas, "trailing %<,%> in arguments for "
- "%<#pragma GCC diagnostic ignored_attributes%>");
- free (args);
+ if (want_diagnostics)
+ warning_at (data.loc_option, OPT_Wpragmas,
+ "missing option after %<#pragma GCC diagnostic%> kind");
return;
}
- auto_vec<char *> v;
- for (char *p = strtok (args, ","); p; p = strtok (NULL, ","))
- v.safe_push (p);
- handle_ignored_attributes_option (&v);
- free (args);
- return;
- }
- else
- {
- warning_at (loc, OPT_Wpragmas,
- "expected %<error%>, %<warning%>, %<ignored%>, %<push%>, "
- "%<pop%>, %<ignored_attributes%> after "
- "%<#pragma GCC diagnostic%>");
- return;
- }
+ break;
- token = pragma_lex (&x, &loc);
- if (token != CPP_STRING)
- {
- warning_at (loc, OPT_Wpragmas,
- "missing option after %<#pragma GCC diagnostic%> kind");
+ default:
+ if (want_diagnostics)
+ warning_at (data.loc_kind, OPT_Wpragmas,
+ "expected %<error%>, %<warning%>, %<ignored%>, %<push%>, "
+ "%<pop%>, %<ignored_attributes%> after "
+ "%<#pragma GCC diagnostic%>");
return;
+
}
- const char *option_string = TREE_STRING_POINTER (x);
+ gcc_assert (data.pd_kind == pragma_diagnostic_data::PK_DIAGNOSTIC);
+ gcc_assert (data.valid);
+
unsigned int lang_mask = c_common_option_lang_mask () | CL_COMMON;
/* option_string + 1 to skip the initial '-' */
- unsigned int option_index = find_opt (option_string + 1, lang_mask);
+ unsigned int option_index = find_opt (data.option_str + 1, lang_mask);
+
+ if (early && !c_option_is_from_cpp_diagnostics (option_index))
+ return;
+
+ const char *arg = NULL;
+ if (cl_options[option_index].flags & CL_JOINED)
+ arg = data.option_str + 1 + cl_options[option_index].opt_len;
+
if (option_index == OPT_SPECIAL_unknown)
{
- auto_diagnostic_group d;
- if (warning_at (loc, OPT_Wpragmas,
- "unknown option after %<#pragma GCC diagnostic%> kind"))
+ if (want_diagnostics)
{
- option_proposer op;
- const char *hint = op.suggest_option (option_string + 1);
- if (hint)
- inform (loc, "did you mean %<-%s%>?", hint);
+ auto_diagnostic_group d;
+ if (warning_at (data.loc_option, OPT_Wpragmas,
+ "unknown option after %<#pragma GCC diagnostic%> kind"))
+ {
+ option_proposer op;
+ const char *hint = op.suggest_option (data.option_str + 1);
+ if (hint)
+ inform (data.loc_option, "did you mean %<-%s%>?", hint);
+ }
}
return;
}
else if (!(cl_options[option_index].flags & CL_WARNING))
{
- warning_at (loc, OPT_Wpragmas,
- "%qs is not an option that controls warnings", option_string);
+ if (want_diagnostics)
+ warning_at (data.loc_option, OPT_Wpragmas,
+ "%qs is not an option that controls warnings",
+ data.option_str);
return;
}
else if (!(cl_options[option_index].flags & lang_mask))
{
- char *ok_langs = write_langs (cl_options[option_index].flags);
- char *bad_lang = write_langs (c_common_option_lang_mask ());
- warning_at (loc, OPT_Wpragmas,
- "option %qs is valid for %s but not for %s",
- option_string, ok_langs, bad_lang);
- free (ok_langs);
- free (bad_lang);
+ if (want_diagnostics)
+ {
+ char *ok_langs = write_langs (cl_options[option_index].flags);
+ char *bad_lang = write_langs (c_common_option_lang_mask ());
+ warning_at (data.loc_option, OPT_Wpragmas,
+ "option %qs is valid for %s but not for %s",
+ data.option_str, ok_langs, bad_lang);
+ free (ok_langs);
+ free (bad_lang);
+ }
return;
}
struct cl_option_handlers handlers;
set_default_handlers (&handlers, NULL);
- const char *arg = NULL;
- if (cl_options[option_index].flags & CL_JOINED)
- arg = option_string + 1 + cl_options[option_index].opt_len;
/* FIXME: input_location isn't the best location here, but it is
what we used to do here before and changing it breaks e.g.
PR69543 and PR69558. */
- control_warning_option (option_index, (int) kind,
- arg, kind != DK_IGNORED,
+ control_warning_option (option_index, (int) data.diagnostic_kind,
+ arg, data.diagnostic_kind != DK_IGNORED,
input_location, lang_mask, &handlers,
&global_options, &global_options_set,
global_dc);
}
+static void
+handle_pragma_diagnostic (cpp_reader *)
+{
+ handle_pragma_diagnostic_impl<false, false> ();
+}
+
+static void
+handle_pragma_diagnostic_early (cpp_reader *)
+{
+ handle_pragma_diagnostic_impl<true, false> ();
+}
+
+static void
+handle_pragma_diagnostic_early_pp (cpp_reader *)
+{
+ handle_pragma_diagnostic_impl<true, true> ();
+}
+
/* Parse #pragma GCC target (xxx) to set target specific options. */
static void
handle_pragma_target(cpp_reader *)
static vec<internal_pragma_handler> registered_pragmas;
-struct pragma_ns_name
+struct pragma_pp_data
{
const char *space;
const char *name;
+ pragma_handler_1arg early_handler;
};
-static vec<pragma_ns_name> registered_pp_pragmas;
+static vec<pragma_pp_data> registered_pp_pragmas;
struct omp_pragma_def { const char *name; unsigned int id; };
static const struct omp_pragma_def oacc_pragmas[] = {
if (flag_preprocess_only)
{
- pragma_ns_name ns_name;
-
- if (!allow_expansion)
+ if (!(allow_expansion || ihandler.early_handler.handler_1arg))
return;
- ns_name.space = space;
- ns_name.name = name;
- registered_pp_pragmas.safe_push (ns_name);
+ pragma_pp_data pp_data;
+ pp_data.space = space;
+ pp_data.name = name;
+ pp_data.early_handler = ihandler.early_handler.handler_1arg;
+ registered_pp_pragmas.safe_push (pp_data);
id = registered_pp_pragmas.length ();
id += PRAGMA_FIRST_EXTERNAL - 1;
}
void
c_register_pragma (const char *space, const char *name,
pragma_handler_1arg handler)
+{
+ c_register_pragma_with_early_handler (space, name, handler, nullptr);
+}
+void c_register_pragma_with_early_handler (const char *space, const char *name,
+ pragma_handler_1arg handler,
+ pragma_handler_1arg early_handler)
{
internal_pragma_handler ihandler;
ihandler.handler.handler_1arg = handler;
+ ihandler.early_handler.handler_1arg = early_handler;
ihandler.extra_data = false;
ihandler.data = NULL;
c_register_pragma_1 (space, name, ihandler, false);
internal_pragma_handler ihandler;
ihandler.handler.handler_2arg = handler;
+ ihandler.early_handler.handler_2arg = nullptr;
ihandler.extra_data = true;
ihandler.data = data;
c_register_pragma_1 (space, name, ihandler, false);
internal_pragma_handler ihandler;
ihandler.handler.handler_1arg = handler;
+ ihandler.early_handler.handler_1arg = nullptr;
ihandler.extra_data = false;
ihandler.data = NULL;
c_register_pragma_1 (space, name, ihandler, true);
internal_pragma_handler ihandler;
ihandler.handler.handler_2arg = handler;
+ ihandler.early_handler.handler_2arg = nullptr;
ihandler.extra_data = true;
ihandler.data = data;
c_register_pragma_1 (space, name, ihandler, true);
}
}
+/* In contrast to the normal handler, the early handler is optional. */
+void
+c_invoke_early_pragma_handler (unsigned int id)
+{
+ internal_pragma_handler *ihandler;
+ pragma_handler_1arg handler_1arg;
+ pragma_handler_2arg handler_2arg;
+
+ id -= PRAGMA_FIRST_EXTERNAL;
+ ihandler = ®istered_pragmas[id];
+ if (ihandler->extra_data)
+ {
+ handler_2arg = ihandler->early_handler.handler_2arg;
+ if (handler_2arg)
+ handler_2arg (parse_in, ihandler->data);
+ }
+ else
+ {
+ handler_1arg = ihandler->early_handler.handler_1arg;
+ if (handler_1arg)
+ handler_1arg (parse_in);
+ }
+}
+
+void
+c_pp_invoke_early_pragma_handler (unsigned int id)
+{
+ const auto data = ®istered_pp_pragmas[id - PRAGMA_FIRST_EXTERNAL];
+ if (data->early_handler)
+ data->early_handler (parse_in);
+}
+
/* Set up front-end pragmas. */
void
init_pragma (void)
c_register_pragma ("GCC", "visibility", handle_pragma_visibility);
- c_register_pragma ("GCC", "diagnostic", handle_pragma_diagnostic);
+ if (flag_preprocess_only)
+ c_register_pragma_with_early_handler ("GCC", "diagnostic",
+ nullptr,
+ handle_pragma_diagnostic_early_pp);
+ else
+ c_register_pragma_with_early_handler ("GCC", "diagnostic",
+ handle_pragma_diagnostic,
+ handle_pragma_diagnostic_early);
c_register_pragma ("GCC", "target", handle_pragma_target);
c_register_pragma ("GCC", "optimize", handle_pragma_optimize);
c_register_pragma ("GCC", "push_options", handle_pragma_push_options);
|| token->keyword == RID__IMPORT;
}
+/* Return TOKEN's pragma_kind if it is CPP_PRAGMA, otherwise
+ PRAGMA_NONE. */
+
+static enum pragma_kind
+cp_parser_pragma_kind (cp_token *token)
+{
+ if (token->type != CPP_PRAGMA)
+ return PRAGMA_NONE;
+ /* We smuggled the cpp_token->u.pragma value in an INTEGER_CST. */
+ return (enum pragma_kind) TREE_INT_CST_LOW (token->u.value);
+}
+
+/* Handle early pragmas such as #pragma GCC diagnostic, which needs to be done
+ during preprocessing for the case of preprocessing-related diagnostics. This
+ is called immediately after pushing the CPP_PRAGMA_EOL token onto
+ lexer->buffer. */
+
+static void
+cp_lexer_handle_early_pragma (cp_lexer *lexer)
+{
+ const auto first_token = lexer->buffer->address ();
+ const auto last_token = first_token + lexer->buffer->length () - 1;
+
+ /* Back up to the start of the pragma so pragma_lex () can parse it when
+ c-pragma lib asks it to. */
+ auto begin = last_token;
+ gcc_assert (begin->type == CPP_PRAGMA_EOL);
+ while (begin->type != CPP_PRAGMA)
+ {
+ if (cp_token_is_module_directive (begin))
+ return;
+ gcc_assert (begin != first_token);
+ --begin;
+ }
+ gcc_assert (!lexer->next_token);
+ gcc_assert (!lexer->last_token);
+ lexer->next_token = begin;
+ lexer->last_token = last_token;
+
+ /* Dispatch it. */
+ const unsigned int id
+ = cp_parser_pragma_kind (cp_lexer_consume_token (lexer));
+ if (id >= PRAGMA_FIRST_EXTERNAL)
+ c_invoke_early_pragma_handler (id);
+
+ /* Reset to normal state. */
+ lexer->next_token = lexer->last_token = nullptr;
+}
+
+/* The parser. */
+static cp_parser *cp_parser_new (cp_lexer *);
+static GTY (()) cp_parser *the_parser;
+
/* Create a new main C++ lexer, the lexer that gets tokens from the
- preprocessor. */
+ preprocessor, and also create the main parser. */
static cp_lexer *
cp_lexer_new_main (void)
if (modules_p ())
filter = module_token_cdtor (parse_in, filter);
+ /* Create the parser now, so we can use it to handle early pragmas. */
+ gcc_assert (!the_parser);
+ the_parser = cp_parser_new (lexer);
+
/* Get the remaining tokens from the preprocessor. */
while (tok->type != CPP_EOF)
{
/* Process the previous token. */
module_token_lang (tok->type, tok->keyword, tok->u.value,
tok->location, filter);
+
+ /* Check for early pragmas that need to be handled now. */
+ if (tok->type == CPP_PRAGMA_EOL)
+ cp_lexer_handle_early_pragma (lexer);
+
tok = vec_safe_push (lexer->buffer, cp_token ());
cp_lexer_get_preprocessor_token (C_LEX_STRING_NO_JOIN, tok);
}
/* Prototypes. */
-/* Constructors and destructors. */
-
-static cp_parser *cp_parser_new
- (cp_lexer *);
-
/* Routines to parse various constructs.
Those that return `tree' will return the error_mark_node (rather
return token->keyword == keyword;
}
-/* Return TOKEN's pragma_kind if it is CPP_PRAGMA, otherwise
- PRAGMA_NONE. */
-
-static enum pragma_kind
-cp_parser_pragma_kind (cp_token *token)
-{
- if (token->type != CPP_PRAGMA)
- return PRAGMA_NONE;
- /* We smuggled the cpp_token->u.pragma value in an INTEGER_CST. */
- return (enum pragma_kind) TREE_INT_CST_LOW (token->u.value);
-}
-
/* Helper function for cp_parser_error.
Having peeked a token of kind TOK1_KIND that might signify
a conflict marker, peek successor tokens to determine
return stmt;
}
\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
/* cp_lexer_new_main is called before doing any GC allocation
because tokenization might load a PCH file. */
- cp_lexer *lexer = cp_lexer_new_main ();
-
- the_parser = cp_parser_new (lexer);
+ cp_lexer_new_main ();
cp_parser_translation_unit (the_parser);
class_decl_loc_t::diag_mismatched_tags ();