/* CPP Library. (Directive handling.)
- Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005,
- 2007, 2008, 2009 Free Software Foundation, Inc.
+ Copyright (C) 1986-2013 Free Software Foundation, Inc.
Contributed by Per Bothner, 1994-95.
Based on CCCP program by Paul Rubin, June 1986
Adapted to ANSI C, Richard Stallman, Jan 1987
struct if_stack
{
struct if_stack *next;
- linenum_type line; /* Line where condition started. */
+ source_location line; /* Line where condition started. */
const cpp_hashnode *mi_cmacro;/* macro name for #ifndef around entire file */
bool skip_elses; /* Can future #else / #elif be skipped? */
bool was_skipping; /* If were skipping on entry. */
static void push_conditional (cpp_reader *, int, int, const cpp_hashnode *);
static unsigned int read_flag (cpp_reader *, unsigned int);
static bool strtolinenum (const uchar *, size_t, linenum_type *, bool *);
-static void do_diagnostic (cpp_reader *, int, int);
+static void do_diagnostic (cpp_reader *, int, int, int);
static cpp_hashnode *lex_macro_node (cpp_reader *, bool);
static int undefine_macros (cpp_reader *, cpp_hashnode *, void *);
static void do_include_common (cpp_reader *, enum include_type);
static void do_pragma_poison (cpp_reader *);
static void do_pragma_system_header (cpp_reader *);
static void do_pragma_dependency (cpp_reader *);
+static void do_pragma_warning_or_error (cpp_reader *, bool error);
+static void do_pragma_warning (cpp_reader *);
+static void do_pragma_error (cpp_reader *);
static void do_linemarker (cpp_reader *);
static const cpp_token *get_token_no_padding (cpp_reader *);
static const cpp_token *get__Pragma_string (cpp_reader *);
static cpp_hashnode *parse_assertion (cpp_reader *, struct answer **, int);
static struct answer ** find_answer (cpp_hashnode *, const struct answer *);
static void handle_assertion (cpp_reader *, const char *, int);
+static void do_pragma_push_macro (cpp_reader *);
+static void do_pragma_pop_macro (cpp_reader *);
+static void cpp_pop_definition (cpp_reader *, struct def_pragma_macro *);
/* This is the table of directive handlers. It is ordered by
frequency of occurrence; the numbers at the end are directive
static void
end_directive (cpp_reader *pfile, int skip_line)
{
- if (pfile->state.in_deferred_pragma)
- ;
- else if (CPP_OPTION (pfile, traditional))
+ if (CPP_OPTION (pfile, traditional))
{
/* Revert change of prepare_directive_trad. */
- pfile->state.prevent_expansion--;
+ if (!pfile->state.in_deferred_pragma)
+ pfile->state.prevent_expansion--;
if (pfile->directive != &dtable[T_DEFINE])
_cpp_remove_overlay (pfile);
}
+ else if (pfile->state.in_deferred_pragma)
+ ;
/* We don't skip for an assembler #. */
else if (skip_line)
{
cpp_error (pfile, CPP_DL_PEDWARN, "#%s is a GCC extension", dir->name);
else if (((dir->flags & DEPRECATED) != 0
|| (dir == &dtable[T_IMPORT] && !CPP_OPTION (pfile, objc)))
- && CPP_OPTION (pfile, warn_deprecated))
- cpp_error (pfile, CPP_DL_WARNING, "#%s is a deprecated GCC extension",
- dir->name);
+ && CPP_OPTION (pfile, cpp_warn_deprecated))
+ cpp_warning (pfile, CPP_W_DEPRECATED,
+ "#%s is a deprecated GCC extension", dir->name);
}
/* Traditionally, a directive is ignored unless its # is in
if (CPP_WTRADITIONAL (pfile))
{
if (dir == &dtable[T_ELIF])
- cpp_error (pfile, CPP_DL_WARNING,
- "suggest not using #elif in traditional C");
+ cpp_warning (pfile, CPP_W_TRADITIONAL,
+ "suggest not using #elif in traditional C");
else if (indented && dir->origin == KANDR)
- cpp_error (pfile, CPP_DL_WARNING,
- "traditional C ignores #%s with the # indented",
- dir->name);
+ cpp_warning (pfile, CPP_W_TRADITIONAL,
+ "traditional C ignores #%s with the # indented",
+ dir->name);
else if (!indented && dir->origin != KANDR)
- cpp_error (pfile, CPP_DL_WARNING,
- "suggest hiding #%s from traditional C with an indented #",
- dir->name);
+ cpp_warning (pfile, CPP_W_TRADITIONAL,
+ "suggest hiding #%s from traditional C with an indented #",
+ dir->name);
}
}
if (was_parsing_args)
{
- if (CPP_OPTION (pfile, pedantic))
+ if (CPP_OPTION (pfile, cpp_pedantic))
cpp_error (pfile, CPP_DL_PEDWARN,
"embedding a directive within macro arguments is not portable");
pfile->state.parsing_args = 0;
We exclude the -fdirectives-only case because macro expansion
has not been performed yet, and block comments can cause spaces
- to preceed the directive. */
+ to precede the directive. */
if (CPP_OPTION (pfile, preprocessed)
&& !CPP_OPTION (pfile, directives_only)
&& (indented || !(dir->flags & IN_I)))
/* Allow macro expansion. */
header = get_token_no_padding (pfile);
*location = header->src_loc;
- if (header->type == CPP_STRING || header->type == CPP_HEADER_NAME)
+ if ((header->type == CPP_STRING && header->val.str.text[0] != 'R')
+ || header->type == CPP_HEADER_NAME)
{
fname = XNEWVEC (char, header->val.str.len - 1);
memcpy (fname, header->val.str.text + 1, header->val.str.len - 2);
do_line (cpp_reader *pfile)
{
const struct line_maps *line_table = pfile->line_table;
- const struct line_map *map = &line_table->maps[line_table->used - 1];
+ const struct line_map *map = LINEMAPS_LAST_ORDINARY_MAP (line_table);
/* skip_rest_of_line() may cause line table to be realloc()ed so note down
sysp right now. */
- unsigned char map_sysp = map->sysp;
+ unsigned char map_sysp = ORDINARY_MAP_IN_SYSTEM_HEADER_P (map);
const cpp_token *token;
- const char *new_file = map->to_file;
+ const char *new_file = ORDINARY_MAP_FILE_NAME (map);
linenum_type new_lineno;
/* C99 raised the minimum limit on #line numbers. */
do_linemarker (cpp_reader *pfile)
{
const struct line_maps *line_table = pfile->line_table;
- const struct line_map *map = &line_table->maps[line_table->used - 1];
+ const struct line_map *map = LINEMAPS_LAST_ORDINARY_MAP (line_table);
const cpp_token *token;
- const char *new_file = map->to_file;
+ const char *new_file = ORDINARY_MAP_FILE_NAME (map);
linenum_type new_lineno;
- unsigned int new_sysp = map->sysp;
+ unsigned int new_sysp = ORDINARY_MAP_IN_SYSTEM_HEADER_P (map);
enum lc_reason reason = LC_RENAME_VERBATIM;
int flag;
bool wrapped;
const struct line_map *map = linemap_add (pfile->line_table, reason, sysp,
to_file, file_line);
if (map != NULL)
- linemap_line_start (pfile->line_table, map->to_line, 127);
+ linemap_line_start (pfile->line_table,
+ ORDINARY_MAP_STARTING_LINE_NUMBER (map),
+ 127);
if (pfile->cb.file_change)
pfile->cb.file_change (pfile, map);
/* Report a warning or error detected by the program we are
processing. Use the directive's tokens in the error message. */
static void
-do_diagnostic (cpp_reader *pfile, int code, int print_dir)
+do_diagnostic (cpp_reader *pfile, int code, int reason, int print_dir)
{
const unsigned char *dir_name;
unsigned char *line;
line = cpp_output_line_to_string (pfile, dir_name);
pfile->state.prevent_expansion--;
- cpp_error_with_line (pfile, code, src_loc, 0, "%s", line);
+ if (code == CPP_DL_WARNING_SYSHDR && reason)
+ cpp_warning_with_line_syshdr (pfile, reason, src_loc, 0, "%s", line);
+ else if (code == CPP_DL_WARNING && reason)
+ cpp_warning_with_line (pfile, reason, src_loc, 0, "%s", line);
+ else
+ cpp_error_with_line (pfile, code, src_loc, 0, "%s", line);
free (line);
}
static void
do_error (cpp_reader *pfile)
{
- do_diagnostic (pfile, CPP_DL_ERROR, 1);
+ do_diagnostic (pfile, CPP_DL_ERROR, 0, 1);
}
static void
do_warning (cpp_reader *pfile)
{
/* We want #warning diagnostics to be emitted in system headers too. */
- do_diagnostic (pfile, CPP_DL_WARNING_SYSHDR, 1);
+ do_diagnostic (pfile, CPP_DL_WARNING_SYSHDR, CPP_W_WARNING_DIRECTIVE, 1);
}
/* Report program identification. */
{
/* Pragmas in the global namespace. */
register_pragma_internal (pfile, 0, "once", do_pragma_once);
+ register_pragma_internal (pfile, 0, "push_macro", do_pragma_push_macro);
+ register_pragma_internal (pfile, 0, "pop_macro", do_pragma_pop_macro);
/* New GCC-specific pragmas should be put in the GCC namespace. */
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);
+ register_pragma_internal (pfile, "GCC", "warning", do_pragma_warning);
+ register_pragma_internal (pfile, "GCC", "error", do_pragma_error);
}
/* Return the number of registered pragmas in PE. */
do_pragma (cpp_reader *pfile)
{
const struct pragma_entry *p = NULL;
- const cpp_token *token, *pragma_token = pfile->cur_token;
+ const cpp_token *token, *pragma_token;
+ source_location pragma_token_virt_loc = 0;
cpp_token ns_token;
unsigned int count = 1;
pfile->state.prevent_expansion++;
- token = cpp_get_token (pfile);
+ pragma_token = token = cpp_get_token_with_location (pfile,
+ &pragma_token_virt_loc);
ns_token = *token;
if (token->type == CPP_NAME)
{
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.node);
{
if (p->is_deferred)
{
- pfile->directive_result.src_loc = pragma_token->src_loc;
+ pfile->directive_result.src_loc = pragma_token_virt_loc;
pfile->directive_result.type = CPP_PRAGMA;
pfile->directive_result.flags = pragma_token->flags;
pfile->directive_result.val.pragma = p->u.ident;
_cpp_mark_file_once_only (pfile, pfile->buffer->file);
}
+/* Handle #pragma push_macro(STRING). */
+static void
+do_pragma_push_macro (cpp_reader *pfile)
+{
+ cpp_hashnode *node;
+ size_t defnlen;
+ const uchar *defn = NULL;
+ char *macroname, *dest;
+ const char *limit, *src;
+ const cpp_token *txt;
+ struct def_pragma_macro *c;
+
+ txt = get__Pragma_string (pfile);
+ if (!txt)
+ {
+ source_location src_loc = pfile->cur_token[-1].src_loc;
+ cpp_error_with_line (pfile, CPP_DL_ERROR, src_loc, 0,
+ "invalid #pragma push_macro directive");
+ check_eol (pfile, false);
+ skip_rest_of_line (pfile);
+ return;
+ }
+ dest = macroname = (char *) alloca (txt->val.str.len + 2);
+ src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L'));
+ limit = (const char *) (txt->val.str.text + txt->val.str.len - 1);
+ while (src < limit)
+ {
+ /* We know there is a character following the backslash. */
+ if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+ src++;
+ *dest++ = *src++;
+ }
+ *dest = 0;
+ check_eol (pfile, false);
+ skip_rest_of_line (pfile);
+ c = XNEW (struct def_pragma_macro);
+ memset (c, 0, sizeof (struct def_pragma_macro));
+ c->name = XNEWVAR (char, strlen (macroname) + 1);
+ strcpy (c->name, macroname);
+ c->next = pfile->pushed_macros;
+ node = _cpp_lex_identifier (pfile, c->name);
+ if (node->type == NT_VOID)
+ c->is_undef = 1;
+ else
+ {
+ defn = cpp_macro_definition (pfile, node);
+ defnlen = ustrlen (defn);
+ c->definition = XNEWVEC (uchar, defnlen + 2);
+ c->definition[defnlen] = '\n';
+ c->definition[defnlen + 1] = 0;
+ c->line = node->value.macro->line;
+ c->syshdr = node->value.macro->syshdr;
+ c->used = node->value.macro->used;
+ memcpy (c->definition, defn, defnlen);
+ }
+
+ pfile->pushed_macros = c;
+}
+
+/* Handle #pragma pop_macro(STRING). */
+static void
+do_pragma_pop_macro (cpp_reader *pfile)
+{
+ char *macroname, *dest;
+ const char *limit, *src;
+ const cpp_token *txt;
+ struct def_pragma_macro *l = NULL, *c = pfile->pushed_macros;
+ txt = get__Pragma_string (pfile);
+ if (!txt)
+ {
+ source_location src_loc = pfile->cur_token[-1].src_loc;
+ cpp_error_with_line (pfile, CPP_DL_ERROR, src_loc, 0,
+ "invalid #pragma pop_macro directive");
+ check_eol (pfile, false);
+ skip_rest_of_line (pfile);
+ return;
+ }
+ dest = macroname = (char *) alloca (txt->val.str.len + 2);
+ src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L'));
+ limit = (const char *) (txt->val.str.text + txt->val.str.len - 1);
+ while (src < limit)
+ {
+ /* We know there is a character following the backslash. */
+ if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+ src++;
+ *dest++ = *src++;
+ }
+ *dest = 0;
+ check_eol (pfile, false);
+ skip_rest_of_line (pfile);
+
+ while (c != NULL)
+ {
+ if (!strcmp (c->name, macroname))
+ {
+ if (!l)
+ pfile->pushed_macros = c->next;
+ else
+ l->next = c->next;
+ cpp_pop_definition (pfile, c);
+ free (c->definition);
+ free (c->name);
+ free (c);
+ break;
+ }
+ l = c;
+ c = c->next;
+ }
+}
+
/* Handle #pragma GCC poison, to poison one or more identifiers so
that the lexer produces a hard error for each subsequent usage. */
static void
if (cpp_get_token (pfile)->type != CPP_EOF)
{
_cpp_backup_tokens (pfile, 1);
- do_diagnostic (pfile, CPP_DL_WARNING, 0);
+ do_diagnostic (pfile, CPP_DL_WARNING, 0, 0);
}
}
free ((void *) fname);
}
+/* Issue a diagnostic with the message taken from the pragma. If
+ ERROR is true, the diagnostic is a warning, otherwise, it is an
+ error. */
+static void
+do_pragma_warning_or_error (cpp_reader *pfile, bool error)
+{
+ const cpp_token *tok = _cpp_lex_token (pfile);
+ cpp_string str;
+ if (tok->type != CPP_STRING
+ || !cpp_interpret_string_notranslate (pfile, &tok->val.str, 1, &str,
+ CPP_STRING)
+ || str.len == 0)
+ {
+ cpp_error (pfile, CPP_DL_ERROR, "invalid \"#pragma GCC %s\" directive",
+ error ? "error" : "warning");
+ return;
+ }
+ cpp_error (pfile, error ? CPP_DL_ERROR : CPP_DL_WARNING,
+ "%s", str.text);
+ free ((void *)str.text);
+}
+
+/* Issue a warning diagnostic. */
+static void
+do_pragma_warning (cpp_reader *pfile)
+{
+ do_pragma_warning_or_error (pfile, false);
+}
+
+/* Issue an error diagnostic. */
+static void
+do_pragma_error (cpp_reader *pfile)
+{
+ do_pragma_warning_or_error (pfile, true);
+}
+
/* Get a token but skip padding. */
static const cpp_token *
get_token_no_padding (cpp_reader *pfile)
if (string->type == CPP_EOF)
_cpp_backup_tokens (pfile, 1);
if (string->type != CPP_STRING && string->type != CPP_WSTRING
- && string->type != CPP_STRING32 && string->type != CPP_STRING16)
+ && string->type != CPP_STRING32 && string->type != CPP_STRING16
+ && string->type != CPP_UTF8STRING)
return NULL;
paren = get_token_no_padding (pfile);
saved_cur_token = pfile->cur_token;
saved_cur_run = pfile->cur_run;
- pfile->context = XNEW (cpp_context);
- pfile->context->macro = 0;
- pfile->context->prev = 0;
- pfile->context->next = 0;
+ pfile->context = XCNEW (cpp_context);
/* Inline run_directive, since we need to delay the _cpp_pop_buffer
until we've read all of the tokens that we want. */
if (node)
{
- skip = node->type != NT_MACRO;
+ /* Do not treat conditional macros as being defined. This is due to
+ the powerpc and spu ports using conditional macros for 'vector',
+ 'bool', and 'pixel' to act as conditional keywords. This messes
+ up tests like #ifndef bool. */
+ skip = (node->type != NT_MACRO
+ || ((node->flags & NODE_CONDITIONAL) != 0));
_cpp_mark_macro_used (node);
if (!(node->flags & NODE_USED))
{
node->flags |= NODE_USED;
if (node->type == NT_MACRO)
{
+ if ((node->flags & NODE_BUILTIN)
+ && pfile->cb.user_builtin_macro)
+ pfile->cb.user_builtin_macro (pfile, node);
if (pfile->cb.used_define)
pfile->cb.used_define (pfile, pfile->directive_line, node);
}
pfile->cb.used_undef (pfile, pfile->directive_line, node);
}
}
+ if (pfile->cb.used)
+ pfile->cb.used (pfile, pfile->directive_line, node);
check_eol (pfile, false);
}
}
if (node)
{
- skip = node->type == NT_MACRO;
+ /* Do not treat conditional macros as being defined. This is due to
+ the powerpc and spu ports using conditional macros for 'vector',
+ 'bool', and 'pixel' to act as conditional keywords. This messes
+ up tests like #ifndef bool. */
+ skip = (node->type == NT_MACRO
+ && ((node->flags & NODE_CONDITIONAL) == 0));
_cpp_mark_macro_used (node);
if (!(node->flags & NODE_USED))
{
node->flags |= NODE_USED;
if (node->type == NT_MACRO)
{
+ if ((node->flags & NODE_BUILTIN)
+ && pfile->cb.user_builtin_macro)
+ pfile->cb.user_builtin_macro (pfile, node);
if (pfile->cb.used_define)
pfile->cb.used_define (pfile, pfile->directive_line, node);
}
pfile->cb.used_undef (pfile, pfile->directive_line, node);
}
}
+ if (pfile->cb.used)
+ pfile->cb.used (pfile, pfile->directive_line, node);
check_eol (pfile, false);
}
}
run_directive (pfile, T_UNDEF, buf, len);
}
-/* Like lex_macro_node, but read the input from STR. */
-static cpp_hashnode *
-lex_macro_node_from_str (cpp_reader *pfile, const char *str)
-{
- size_t len = strlen (str);
- uchar *buf = (uchar *) alloca (len + 1);
- cpp_hashnode *node;
-
- memcpy (buf, str, len);
- buf[len] = '\n';
- cpp_push_buffer (pfile, buf, len, true);
- node = lex_macro_node (pfile, true);
- _cpp_pop_buffer (pfile);
-
- return node;
-}
-
-/* If STR is a defined macro, return its definition node, else return NULL. */
-cpp_macro *
-cpp_push_definition (cpp_reader *pfile, const char *str)
-{
- cpp_hashnode *node = lex_macro_node_from_str (pfile, str);
- if (node && node->type == NT_MACRO)
- return node->value.macro;
- else
- return NULL;
-}
-
-/* Replace a previous definition DFN of the macro STR. If DFN is NULL,
- then the macro should be undefined. */
-void
-cpp_pop_definition (cpp_reader *pfile, const char *str, cpp_macro *dfn)
+/* Replace a previous definition DEF of the macro STR. If DEF is NULL,
+ or first element is zero, then the macro should be undefined. */
+static void
+cpp_pop_definition (cpp_reader *pfile, struct def_pragma_macro *c)
{
- cpp_hashnode *node = lex_macro_node_from_str (pfile, str);
+ cpp_hashnode *node = _cpp_lex_identifier (pfile, c->name);
if (node == NULL)
return;
if (node->type != NT_VOID)
_cpp_free_definition (node);
- if (dfn)
- {
- node->type = NT_MACRO;
- node->value.macro = dfn;
- if (! ustrncmp (NODE_NAME (node), DSC ("__STDC_")))
- node->flags |= NODE_WARN;
-
- if (pfile->cb.define)
- pfile->cb.define (pfile, pfile->directive_line, node);
- }
+ if (c->is_undef)
+ return;
+ {
+ size_t namelen;
+ const uchar *dn;
+ cpp_hashnode *h = NULL;
+ cpp_buffer *nbuf;
+
+ namelen = ustrcspn (c->definition, "( \n");
+ h = cpp_lookup (pfile, c->definition, namelen);
+ dn = c->definition + namelen;
+
+ h->type = NT_VOID;
+ h->flags &= ~(NODE_POISONED|NODE_BUILTIN|NODE_DISABLED|NODE_USED);
+ nbuf = cpp_push_buffer (pfile, dn, ustrchr (dn, '\n') - dn, true);
+ if (nbuf != NULL)
+ {
+ _cpp_clean_line (pfile);
+ nbuf->sysp = 1;
+ if (!_cpp_create_definition (pfile, h))
+ abort ();
+ _cpp_pop_buffer (pfile);
+ }
+ else
+ abort ();
+ h->value.macro->line = c->line;
+ h->value.macro->syshdr = c->syshdr;
+ h->value.macro->used = c->used;
+ }
}
/* Process the string STR as if it appeared as the body of a #assert. */
cpp_buffer *buffer = pfile->buffer;
struct _cpp_file *inc = buffer->file;
struct if_stack *ifs;
+ const unsigned char *to_free;
/* Walk back up the conditional stack till we reach its level at
entry to this file, issuing error messages. */
/* _cpp_do_file_change expects pfile->buffer to be the new one. */
pfile->buffer = buffer->prev;
+ to_free = buffer->to_free;
free (buffer->notes);
/* Free the buffer object now; we may want to push a new buffer
if (inc)
{
- _cpp_pop_file_buffer (pfile, inc);
+ _cpp_pop_file_buffer (pfile, inc, to_free);
_cpp_do_file_change (pfile, LC_LEAVE, 0, 0, 0);
}