diff options
author | Jakub Jelinek <jakub@gcc.gnu.org> | 2008-01-25 10:01:27 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2008-01-25 10:01:27 +0100 |
commit | 765d600ac5d94a978c00cd791c95ea75d1673e66 (patch) | |
tree | bd03a307239e9c5c965e1cf60415fca9659096aa /libcpp/macro.c | |
parent | 1525f2c3a5627b3fd3754c36cbcc7d855f7107cf (diff) | |
download | gcc-765d600ac5d94a978c00cd791c95ea75d1673e66.zip gcc-765d600ac5d94a978c00cd791c95ea75d1673e66.tar.gz gcc-765d600ac5d94a978c00cd791c95ea75d1673e66.tar.bz2 |
re PR preprocessor/34692 (Internal error with pragma in macro)
PR preprocessor/34692
* macro.c (collect_args): Add pragma_buff argument. Push
CPP_PRAGMA ... CPP_PRAGMA_EOL tokens to *pragma_buff, rather
than into arguments. Reset prevent_expansion and parsing_args
state at CPP_PRAGMA_EOL/CPP_EOF.
(funlike_invocation_p): Add pragma_buff argument, pass it through
to collect_args.
(enter_macro_context): Add result argument. Adjust
funlike_invocation_p caller. Emit all deferred pragma tokens
gathered during collect_args before the expansion, add a padding
token. Return 2 instead of 1 if any pragma tokens were prepended.
(cpp_get_token): If enter_macro_context returns 2, don't return
a padding token, instead cycle to grab CPP_PRAGMA token.
* directives.c (_cpp_handle_directive): If was_parsing_args
in deferred pragma, leave parsing_args and prevent_expansion as is.
* gcc.dg/cpp/pr34692.c: New test.
* gcc.dg/gomp/pr34692.c: New test.
From-SVN: r131819
Diffstat (limited to 'libcpp/macro.c')
-rw-r--r-- | libcpp/macro.c | 111 |
1 files changed, 97 insertions, 14 deletions
diff --git a/libcpp/macro.c b/libcpp/macro.c index 3a3bf41..fd624b1 100644 --- a/libcpp/macro.c +++ b/libcpp/macro.c @@ -41,11 +41,13 @@ struct macro_arg /* Macro expansion. */ -static int enter_macro_context (cpp_reader *, cpp_hashnode *); +static int enter_macro_context (cpp_reader *, cpp_hashnode *, + const cpp_token *); static int builtin_macro (cpp_reader *, cpp_hashnode *); static void push_ptoken_context (cpp_reader *, cpp_hashnode *, _cpp_buff *, const cpp_token **, unsigned int); -static _cpp_buff *collect_args (cpp_reader *, const cpp_hashnode *); +static _cpp_buff *collect_args (cpp_reader *, const cpp_hashnode *, + _cpp_buff **); static cpp_context *next_context (cpp_reader *); static const cpp_token *padding_token (cpp_reader *, const cpp_token *); static void expand_arg (cpp_reader *, macro_arg *); @@ -55,7 +57,8 @@ static void paste_all_tokens (cpp_reader *, const cpp_token *); static bool paste_tokens (cpp_reader *, const cpp_token **, const cpp_token *); static void replace_args (cpp_reader *, cpp_hashnode *, cpp_macro *, macro_arg *); -static _cpp_buff *funlike_invocation_p (cpp_reader *, cpp_hashnode *); +static _cpp_buff *funlike_invocation_p (cpp_reader *, cpp_hashnode *, + _cpp_buff **); static bool create_iso_definition (cpp_reader *, cpp_macro *); /* #define directive parsing and handling. */ @@ -575,9 +578,12 @@ _cpp_arguments_ok (cpp_reader *pfile, cpp_macro *macro, const cpp_hashnode *node invocation. Assumes the opening parenthesis has been processed. If there is an error, emits an appropriate diagnostic and returns NULL. Each argument is terminated by a CPP_EOF token, for the - future benefit of expand_arg(). */ + future benefit of expand_arg(). If there are any deferred + #pragma directives among macro arguments, store pointers to the + CPP_PRAGMA ... CPP_PRAGMA_EOL tokens into *PRAGMA_BUFF buffer. */ static _cpp_buff * -collect_args (cpp_reader *pfile, const cpp_hashnode *node) +collect_args (cpp_reader *pfile, const cpp_hashnode *node, + _cpp_buff **pragma_buff) { _cpp_buff *buff, *base_buff; cpp_macro *macro; @@ -645,6 +651,51 @@ collect_args (cpp_reader *pfile, const cpp_hashnode *node) else if (token->type == CPP_EOF || (token->type == CPP_HASH && token->flags & BOL)) break; + else if (token->type == CPP_PRAGMA) + { + cpp_token *newtok = _cpp_temp_token (pfile); + + /* CPP_PRAGMA token lives in directive_result, which will + be overwritten on the next directive. */ + *newtok = *token; + token = newtok; + do + { + if (*pragma_buff == NULL + || BUFF_ROOM (*pragma_buff) < sizeof (cpp_token *)) + { + _cpp_buff *next; + if (*pragma_buff == NULL) + *pragma_buff + = _cpp_get_buff (pfile, 32 * sizeof (cpp_token *)); + else + { + next = *pragma_buff; + *pragma_buff + = _cpp_get_buff (pfile, + (BUFF_FRONT (*pragma_buff) + - (*pragma_buff)->base) * 2); + (*pragma_buff)->next = next; + } + } + *(const cpp_token **) BUFF_FRONT (*pragma_buff) = token; + BUFF_FRONT (*pragma_buff) += sizeof (cpp_token *); + if (token->type == CPP_PRAGMA_EOL) + break; + token = cpp_get_token (pfile); + } + while (token->type != CPP_EOF); + + /* In deferred pragmas parsing_args and prevent_expansion + had been changed, reset it. */ + pfile->state.parsing_args = 2; + pfile->state.prevent_expansion = 1; + + if (token->type == CPP_EOF) + break; + else + continue; + } arg->first[ntokens++] = token; } @@ -709,9 +760,11 @@ collect_args (cpp_reader *pfile, const cpp_hashnode *node) /* Search for an opening parenthesis to the macro of NODE, in such a way that, if none is found, we don't lose the information in any intervening padding tokens. If we find the parenthesis, collect - the arguments and return the buffer containing them. */ + the arguments and return the buffer containing them. PRAGMA_BUFF + argument is the same as in collect_args. */ static _cpp_buff * -funlike_invocation_p (cpp_reader *pfile, cpp_hashnode *node) +funlike_invocation_p (cpp_reader *pfile, cpp_hashnode *node, + _cpp_buff **pragma_buff) { const cpp_token *token, *padding = NULL; @@ -728,7 +781,7 @@ funlike_invocation_p (cpp_reader *pfile, cpp_hashnode *node) if (token->type == CPP_OPEN_PAREN) { pfile->state.parsing_args = 2; - return collect_args (pfile, node); + return collect_args (pfile, node, pragma_buff); } /* CPP_EOF can be the end of macro arguments, or the end of the @@ -749,9 +802,13 @@ funlike_invocation_p (cpp_reader *pfile, cpp_hashnode *node) /* Push the context of a macro with hash entry NODE onto the context stack. If we can successfully expand the macro, we push a context containing its yet-to-be-rescanned replacement list and return one. - Otherwise, we don't push a context and return zero. */ + If there were additionally any unexpanded deferred #pragma directives + among macro arguments, push another context containing the + pragma tokens before the yet-to-be-rescanned replacement list + and return two. Otherwise, we don't push a context and return zero. */ static int -enter_macro_context (cpp_reader *pfile, cpp_hashnode *node) +enter_macro_context (cpp_reader *pfile, cpp_hashnode *node, + const cpp_token *result) { /* The presence of a macro invalidates a file's controlling macro. */ pfile->mi_valid = false; @@ -762,6 +819,7 @@ enter_macro_context (cpp_reader *pfile, cpp_hashnode *node) if (! (node->flags & NODE_BUILTIN)) { cpp_macro *macro = node->value.macro; + _cpp_buff *pragma_buff = NULL; if (macro->fun_like) { @@ -770,7 +828,7 @@ enter_macro_context (cpp_reader *pfile, cpp_hashnode *node) pfile->state.prevent_expansion++; pfile->keep_tokens++; pfile->state.parsing_args = 1; - buff = funlike_invocation_p (pfile, node); + buff = funlike_invocation_p (pfile, node, &pragma_buff); pfile->state.parsing_args = 0; pfile->keep_tokens--; pfile->state.prevent_expansion--; @@ -782,6 +840,9 @@ enter_macro_context (cpp_reader *pfile, cpp_hashnode *node) "function-like macro \"%s\" must be used with arguments in traditional C", NODE_NAME (node)); + if (pragma_buff) + _cpp_release_buff (pfile, pragma_buff); + return 0; } @@ -798,6 +859,25 @@ enter_macro_context (cpp_reader *pfile, cpp_hashnode *node) if (macro->paramc == 0) _cpp_push_token_context (pfile, node, macro->exp.tokens, macro->count); + if (pragma_buff) + { + if (!pfile->state.in_directive) + _cpp_push_token_context (pfile, NULL, + padding_token (pfile, result), 1); + do + { + _cpp_buff *tail = pragma_buff->next; + pragma_buff->next = NULL; + push_ptoken_context (pfile, NULL, pragma_buff, + (const cpp_token **) pragma_buff->base, + ((const cpp_token **) BUFF_FRONT (pragma_buff) + - (const cpp_token **) pragma_buff->base)); + pragma_buff = tail; + } + while (pragma_buff != NULL); + return 2; + } + return 1; } @@ -1144,14 +1224,17 @@ cpp_get_token (cpp_reader *pfile) if (!(node->flags & NODE_DISABLED)) { + int ret; /* If not in a macro context, and we're going to start an expansion, record the location. */ if (can_set && !context->macro) pfile->invocation_location = result->src_loc; - if (!pfile->state.prevent_expansion - && enter_macro_context (pfile, node)) + if (pfile->state.prevent_expansion) + break; + ret = enter_macro_context (pfile, node, result); + if (ret) { - if (pfile->state.in_directive) + if (pfile->state.in_directive || ret == 2) continue; return padding_token (pfile, result); } |