aboutsummaryrefslogtreecommitdiff
path: root/libcpp/directives.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libcpp/directives.cc')
-rw-r--r--libcpp/directives.cc175
1 files changed, 90 insertions, 85 deletions
diff --git a/libcpp/directives.cc b/libcpp/directives.cc
index 50fa8ace2..bc4a95b 100644
--- a/libcpp/directives.cc
+++ b/libcpp/directives.cc
@@ -141,7 +141,8 @@ static cpp_macro **find_answer (cpp_hashnode *, const cpp_macro *);
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 *);
+static void cpp_pop_definition (cpp_reader *, def_pragma_macro *,
+ cpp_hashnode *);
/* This is the table of directive handlers. All extensions other than
#warning, #include_next, and #import are deprecated. The name is
@@ -2085,55 +2086,95 @@ do_pragma_once (cpp_reader *pfile)
_cpp_mark_file_once_only (pfile, pfile->buffer->file);
}
-/* Handle #pragma push_macro(STRING). */
-static void
-do_pragma_push_macro (cpp_reader *pfile)
+/* Helper for #pragma {push,pop}_macro. Destringize STR and
+ lex it into an identifier, returning the hash node for it. */
+
+static cpp_hashnode *
+lex_identifier_from_string (cpp_reader *pfile, cpp_string str)
{
+ auto src = (const uchar *) memchr (str.text, '"', str.len);
+ gcc_checking_assert (src);
+ ++src;
+ const auto limit = str.text + str.len - 1;
+ gcc_checking_assert (*limit == '"' && limit >= src);
+ const auto ident = XALLOCAVEC (uchar, limit - src + 1);
+ auto dest = ident;
+ while (src != limit)
+ {
+ /* We know there is a character following the backslash. */
+ if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+ src++;
+ *dest++ = *src++;
+ }
+
+ /* We reserved a spot for the newline with the + 1 when allocating IDENT.
+ Push a buffer containing the identifier to lex. */
+ *dest = '\n';
+ cpp_push_buffer (pfile, ident, dest - ident, true);
+ _cpp_clean_line (pfile);
+ pfile->cur_token = _cpp_temp_token (pfile);
+ cpp_token *tok;
+ {
+ /* Suppress diagnostics during lexing so that we silently ignore invalid
+ input, as seems to be the common practice for this pragma. */
+ cpp_auto_suppress_diagnostics suppress {pfile};
+ tok = _cpp_lex_direct (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;
+ if (tok->type != CPP_NAME || pfile->buffer->cur != pfile->buffer->rlimit)
+ node = nullptr;
+ else
+ node = tok->val.node.node;
- txt = get__Pragma_string (pfile);
- if (!txt)
+ _cpp_pop_buffer (pfile);
+ return node;
+}
+
+/* Common processing for #pragma {push,pop}_macro. */
+
+static cpp_hashnode *
+push_pop_macro_common (cpp_reader *pfile, const char *type)
+{
+ const cpp_token *const txt = get__Pragma_string (pfile);
+ ++pfile->keep_tokens;
+ cpp_hashnode *node;
+ if (txt)
{
- location_t 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;
+ node = lex_identifier_from_string (pfile, txt->val.str);
}
- 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)
+ else
{
- /* We know there is a character following the backslash. */
- if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
- src++;
- *dest++ = *src++;
+ node = nullptr;
+ location_t src_loc = pfile->cur_token[-1].src_loc;
+ cpp_error_with_line (pfile, CPP_DL_ERROR, src_loc, 0,
+ "invalid %<#pragma %s_macro%> directive", type);
+ skip_rest_of_line (pfile);
}
- *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);
+ --pfile->keep_tokens;
+ return node;
+}
+
+/* Handle #pragma push_macro(STRING). */
+static void
+do_pragma_push_macro (cpp_reader *pfile)
+{
+ const auto node = push_pop_macro_common (pfile, "push");
+ if (!node)
+ return;
+ const auto c = XCNEW (def_pragma_macro);
+ c->name = xstrdup ((const char *) NODE_NAME (node));
c->next = pfile->pushed_macros;
- node = _cpp_lex_identifier (pfile, c->name);
if (node->type == NT_VOID)
c->is_undef = 1;
else if (node->type == NT_BUILTIN_MACRO)
c->is_builtin = 1;
else
{
- defn = cpp_macro_definition (pfile, node);
- defnlen = ustrlen (defn);
+ const auto defn = cpp_macro_definition (pfile, node);
+ const size_t defnlen = ustrlen (defn);
c->definition = XNEWVEC (uchar, defnlen + 2);
c->definition[defnlen] = '\n';
c->definition[defnlen + 1] = 0;
@@ -2150,50 +2191,24 @@ do_pragma_push_macro (cpp_reader *pfile)
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)
- {
- location_t 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)
+ const auto node = push_pop_macro_common (pfile, "pop");
+ if (!node)
+ return;
+ for (def_pragma_macro *c = pfile->pushed_macros, *l = nullptr; c; c = c->next)
{
- if (!strcmp (c->name, macroname))
+ if (!strcmp (c->name, (const char *) NODE_NAME (node)))
{
if (!l)
pfile->pushed_macros = c->next;
else
l->next = c->next;
- cpp_pop_definition (pfile, c);
+ cpp_pop_definition (pfile, c, node);
free (c->definition);
free (c->name);
free (c);
break;
}
l = c;
- c = c->next;
}
}
@@ -3109,12 +3124,8 @@ cpp_undef (cpp_reader *pfile, const char *macro)
/* 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_pop_definition (cpp_reader *pfile, def_pragma_macro *c, cpp_hashnode *node)
{
- cpp_hashnode *node = _cpp_lex_identifier (pfile, c->name);
- if (node == NULL)
- return;
-
if (pfile->cb.before_define)
pfile->cb.before_define (pfile);
@@ -3136,29 +3147,23 @@ cpp_pop_definition (cpp_reader *pfile, struct def_pragma_macro *c)
}
{
- 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;
-
- nbuf = cpp_push_buffer (pfile, dn, ustrchr (dn, '\n') - dn, true);
+ const auto namelen = ustrcspn (c->definition, "( \n");
+ const auto dn = c->definition + namelen;
+ const auto 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, 0))
+ if (!_cpp_create_definition (pfile, node, 0))
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;
+ node->value.macro->line = c->line;
+ node->value.macro->syshdr = c->syshdr;
+ node->value.macro->used = c->used;
}
}