From: Jakub Jelinek Date: Mon, 23 Mar 2015 08:02:39 +0000 (+0100) Subject: re PR preprocessor/65238 (__has_attribute is not handled properly with -traditional... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=fb136e35c77e0374112189e3283c9ecf1e83abb1;p=gcc.git re PR preprocessor/65238 (__has_attribute is not handled properly with -traditional-cpp.) PR preprocessor/65238 * internal.h (_cpp_scan_out_logical_line): Add third argument. * directives.c (prepare_directive_trad): Pass false to it. * traditional.c (_cpp_read_logical_line_trad, _cpp_create_trad_definition): Likewise. (struct fun_macro): Add paramc field. (fun_like_macro): New function. (maybe_start_funlike): Handle NODE_BUILTIN macros. Initialize macro->paramc field. (save_argument): Use macro->paramc instead of macro->node->value.macro->paramc. (push_replacement_text): Formatting fix. (recursive_macro): Use fun_like_macro helper. (_cpp_scan_out_logical_line): Likewise. Add BUILTIN_MACRO_ARG argument. Initialize fmacro.paramc field. Handle builtin function-like macros. * c-c++-common/cpp/pr65238-1.c: New test. * gcc.dg/cpp/pr65238-2.c: New test. * gcc.dg/cpp/trad/pr65238-3.c: New test. * gcc.dg/cpp/trad/pr65238-4.c: New test. From-SVN: r221587 --- diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 50d869112e2..9b84418bc81 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2015-03-23 Jakub Jelinek + + PR preprocessor/65238 + * c-c++-common/cpp/pr65238-1.c: New test. + * gcc.dg/cpp/pr65238-2.c: New test. + * gcc.dg/cpp/trad/pr65238-3.c: New test. + * gcc.dg/cpp/trad/pr65238-4.c: New test. + 2015-03-23 Paul Thomas Mikael Morin diff --git a/gcc/testsuite/c-c++-common/cpp/pr65238-1.c b/gcc/testsuite/c-c++-common/cpp/pr65238-1.c new file mode 100644 index 00000000000..6d6346535ab --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/pr65238-1.c @@ -0,0 +1,53 @@ +/* PR preprocessor/65238 */ +/* { dg-do run } */ + +#define A unused +#define B A +#define C B +#define D __has_attribute(unused) +#define E __has_attribute(C) +#define F(X) __has_attribute(X) +#if !__has_attribute(unused) +#error unused attribute not supported - 1 +#endif +#if !__has_attribute(C) +#error unused attribute not supported - 2 +#endif +#if !D +#error unused attribute not supported - 3 +#endif +#if !E +#error unused attribute not supported - 4 +#endif +#if !F(unused) +#error unused attribute not supported - 5 +#endif +#if !F(C) +#error unused attribute not supported - 6 +#endif +int a = __has_attribute (unused) + __has_attribute (C) + D + E + F (unused) + F (C); +int b = __has_attribute (unused); +int c = __has_attribute (C); +int d = D; +int e = E; +int f = F (unused); +int g = F (C); +int h = __has_attribute ( + unused +) + __has_attribute ( + +C) + F ( +unused + +) + F +( +C +); + +int +main () +{ + if (a != 6 || b != 1 || c != 1 || d != 1 || e != 1 || f != 1 || g != 1 || h != 4) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/cpp/pr65238-2.c b/gcc/testsuite/gcc.dg/cpp/pr65238-2.c new file mode 100644 index 00000000000..c6a7aecddeb --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/pr65238-2.c @@ -0,0 +1,18 @@ +/* PR preprocessor/65238 */ +/* { dg-do preprocess } */ + +#if __has_attribute( +#endif +#if __has_attribute(unused +#endif +#if __has_attribute(unused, unused) +#endif +#if __has_attribute(__has_attribute(unused)) +#endif + +/* { dg-error "macro .__has_attribute. requires an identifier" "" {target "*-*-*"} 4 } */ +/* { dg-error "missing ... after .__has_attribute." "" {target "*-*-*"} 6 } */ +/* { dg-error "missing ... after .__has_attribute." "" {target "*-*-*"} 8 } */ +/* { dg-error "missing binary operator before token .unused." "" {target "*-*-*"} 8 } */ +/* { dg-error "macro .__has_attribute. requires an identifier" "" {target "*-*-*"} 10 } */ +/* { dg-error "missing ... in expression" "" {target "*-*-*"} 10 } */ diff --git a/gcc/testsuite/gcc.dg/cpp/trad/pr65238-3.c b/gcc/testsuite/gcc.dg/cpp/trad/pr65238-3.c new file mode 100644 index 00000000000..949dc005a1f --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/trad/pr65238-3.c @@ -0,0 +1,5 @@ +/* PR preprocessor/65238 */ +/* { dg-do run } */ +/* { dg-options "-traditional-cpp" } */ + +#include "../../../c-c++-common/cpp/pr65238-1.c" diff --git a/gcc/testsuite/gcc.dg/cpp/trad/pr65238-4.c b/gcc/testsuite/gcc.dg/cpp/trad/pr65238-4.c new file mode 100644 index 00000000000..cf2f449133c --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/trad/pr65238-4.c @@ -0,0 +1,19 @@ +/* PR preprocessor/65238 */ +/* { dg-do preprocess } */ +/* { dg-options "-traditional-cpp" } */ + +#if __has_attribute( +#endif +#if __has_attribute(unused +#endif +#if __has_attribute(unused, unused) +#endif +#if __has_attribute(__has_attribute(unused)) +#endif + +/* { dg-error "unterminated argument list invoking macro .__has_attribute." "" {target "*-*-*"} 5 } */ +/* { dg-error "#if with no expression" "" {target "*-*-*"} 5 } */ +/* { dg-error "unterminated argument list invoking macro .__has_attribute." "" {target "*-*-*"} 7 } */ +/* { dg-error "macro .__has_attribute. passed 2 arguments, but takes just 1" "" {target "*-*-*"} 9 } */ +/* { dg-error "missing ... in expression" "" {target "*-*-*"} 9 } */ +/* { dg-error "macro .__has_attribute. requires an identifier" "" {target "*-*-*"} 11 } */ diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog index c7599495282..daaa11ea127 100644 --- a/libcpp/ChangeLog +++ b/libcpp/ChangeLog @@ -1,3 +1,22 @@ +2015-03-23 Jakub Jelinek + + PR preprocessor/65238 + * internal.h (_cpp_scan_out_logical_line): Add third argument. + * directives.c (prepare_directive_trad): Pass false to it. + * traditional.c (_cpp_read_logical_line_trad, + _cpp_create_trad_definition): Likewise. + (struct fun_macro): Add paramc field. + (fun_like_macro): New function. + (maybe_start_funlike): Handle NODE_BUILTIN macros. Initialize + macro->paramc field. + (save_argument): Use macro->paramc instead of + macro->node->value.macro->paramc. + (push_replacement_text): Formatting fix. + (recursive_macro): Use fun_like_macro helper. + (_cpp_scan_out_logical_line): Likewise. Add BUILTIN_MACRO_ARG + argument. Initialize fmacro.paramc field. Handle builtin + function-like macros. + 2015-03-16 Edward Smith-Rowland <3dw4rd@verizon.net> PR c++/64626 diff --git a/libcpp/directives.c b/libcpp/directives.c index 37cd109ed8a..2a824e6ed3f 100644 --- a/libcpp/directives.c +++ b/libcpp/directives.c @@ -346,7 +346,7 @@ prepare_directive_trad (cpp_reader *pfile) if (no_expand) pfile->state.prevent_expansion++; - _cpp_scan_out_logical_line (pfile, NULL); + _cpp_scan_out_logical_line (pfile, NULL, false); if (no_expand) pfile->state.prevent_expansion--; diff --git a/libcpp/internal.h b/libcpp/internal.h index 96ccc19e447..c2d08168945 100644 --- a/libcpp/internal.h +++ b/libcpp/internal.h @@ -708,7 +708,7 @@ extern void _cpp_preprocess_dir_only (cpp_reader *, const struct _cpp_dir_only_callbacks *); /* In traditional.c. */ -extern bool _cpp_scan_out_logical_line (cpp_reader *, cpp_macro *); +extern bool _cpp_scan_out_logical_line (cpp_reader *, cpp_macro *, bool); extern bool _cpp_read_logical_line_trad (cpp_reader *); extern void _cpp_overlay_buffer (cpp_reader *pfile, const unsigned char *, size_t); diff --git a/libcpp/traditional.c b/libcpp/traditional.c index e51986ef14c..e96b4f94727 100644 --- a/libcpp/traditional.c +++ b/libcpp/traditional.c @@ -62,6 +62,9 @@ struct fun_macro /* The line the macro name appeared on. */ source_location line; + /* Number of parameters. */ + unsigned int paramc; + /* Zero-based index of argument being currently lexed. */ unsigned int argc; }; @@ -304,24 +307,41 @@ _cpp_read_logical_line_trad (cpp_reader *pfile) if (pfile->buffer->need_line && !_cpp_get_fresh_line (pfile)) return false; } - while (!_cpp_scan_out_logical_line (pfile, NULL) || pfile->state.skipping); + while (!_cpp_scan_out_logical_line (pfile, NULL, false) + || pfile->state.skipping); return pfile->buffer != NULL; } +/* Return true if NODE is a fun_like macro. */ +static inline bool +fun_like_macro (cpp_hashnode *node) +{ + if (node->flags & NODE_BUILTIN) + return node->value.builtin == BT_HAS_ATTRIBUTE; + else + return node->value.macro->fun_like; +} + /* Set up state for finding the opening '(' of a function-like macro. */ static void -maybe_start_funlike (cpp_reader *pfile, cpp_hashnode *node, const uchar *start, struct fun_macro *macro) +maybe_start_funlike (cpp_reader *pfile, cpp_hashnode *node, const uchar *start, + struct fun_macro *macro) { - unsigned int n = node->value.macro->paramc + 1; + unsigned int n; + if (node->flags & NODE_BUILTIN) + n = 1; + else + n = node->value.macro->paramc; if (macro->buff) _cpp_release_buff (pfile, macro->buff); - macro->buff = _cpp_get_buff (pfile, n * sizeof (size_t)); + macro->buff = _cpp_get_buff (pfile, (n + 1) * sizeof (size_t)); macro->args = (size_t *) BUFF_FRONT (macro->buff); macro->node = node; macro->offset = start - pfile->out.base; + macro->paramc = n; macro->argc = 0; } @@ -330,7 +350,7 @@ static void save_argument (struct fun_macro *macro, size_t offset) { macro->argc++; - if (macro->argc <= macro->node->value.macro->paramc) + if (macro->argc <= macro->paramc) macro->args[macro->argc] = offset; } @@ -340,9 +360,13 @@ save_argument (struct fun_macro *macro, size_t offset) If MACRO is non-NULL, then we are scanning the replacement list of MACRO, and we call save_replacement_text() every time we meet an - argument. */ + argument. + + If BUILTIN_MACRO_ARG is true, this is called to macro expand + arguments of builtin function-like macros. */ bool -_cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro) +_cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro, + bool builtin_macro_arg) { bool result = true; cpp_context *context; @@ -359,14 +383,18 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro) fmacro.node = NULL; fmacro.offset = 0; fmacro.line = 0; + fmacro.paramc = 0; fmacro.argc = 0; quote = 0; header_ok = pfile->state.angled_headers; CUR (pfile->context) = pfile->buffer->cur; RLIMIT (pfile->context) = pfile->buffer->rlimit; - pfile->out.cur = pfile->out.base; - pfile->out.first_line = pfile->line_table->highest_line; + if (!builtin_macro_arg) + { + pfile->out.cur = pfile->out.base; + pfile->out.first_line = pfile->line_table->highest_line; + } /* start_of_input_line is needed to make sure that directives really, really start at the first character of the line. */ start_of_input_line = pfile->buffer->cur; @@ -379,6 +407,7 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro) for (;;) { if (!context->prev + && !builtin_macro_arg && cur >= pfile->buffer->notes[pfile->buffer->cur_note].pos) { pfile->buffer->cur = cur; @@ -410,6 +439,8 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro) /* Omit the newline from the output buffer. */ pfile->out.cur = out - 1; pfile->buffer->cur = cur; + if (builtin_macro_arg) + goto done; pfile->buffer->need_line = true; CPP_INCREMENT_LINE (pfile, 0); @@ -489,8 +520,7 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro) { /* Macros invalidate MI optimization. */ pfile->mi_valid = false; - if (! (node->flags & NODE_BUILTIN) - && node->value.macro->fun_like) + if (fun_like_macro (node)) { maybe_start_funlike (pfile, node, out_start, &fmacro); lex_state = ls_fun_open; @@ -572,6 +602,103 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro) paren_depth--; if (lex_state == ls_fun_close && paren_depth == 0) { + if (fmacro.node->flags & NODE_BUILTIN) + { + /* Handle builtin function-like macros like + __has_attribute. The already parsed arguments + are put into a buffer, which is then preprocessed + and the result is fed to _cpp_push_text_context + with disabled expansion, where the ISO preprocessor + parses it. While in traditional preprocessing + macro arguments aren't immediately expanded, they in + the end are because the macro with replaced arguments + is preprocessed again. For the builtin function-like + macros we need the argument immediately though, + if we don't preprocess them, they would behave + very differently from ISO preprocessor handling + of those builtin macros. So, this handling is + more similar to traditional preprocessing of + #if directives, where we also keep preprocessing + until everything is expanded, and then feed the + result with disabled expansion to ISO preprocessor + for handling the directives. */ + lex_state = ls_none; + save_argument (&fmacro, out - pfile->out.base); + cpp_macro m; + memset (&m, '\0', sizeof (m)); + m.paramc = fmacro.paramc; + if (_cpp_arguments_ok (pfile, &m, fmacro.node, + fmacro.argc)) + { + size_t len = fmacro.args[1] - fmacro.args[0]; + uchar *buf; + + /* Remove the macro's invocation from the + output, and push its replacement text. */ + pfile->out.cur = pfile->out.base + fmacro.offset; + CUR (context) = cur; + buf = _cpp_unaligned_alloc (pfile, len + 2); + buf[0] = '('; + memcpy (buf + 1, pfile->out.base + fmacro.args[0], + len); + buf[len + 1] = '\n'; + + const unsigned char *ctx_rlimit = RLIMIT (context); + const unsigned char *saved_cur = pfile->buffer->cur; + const unsigned char *saved_rlimit + = pfile->buffer->rlimit; + const unsigned char *saved_line_base + = pfile->buffer->line_base; + bool saved_need_line = pfile->buffer->need_line; + cpp_buffer *saved_overlaid_buffer + = pfile->overlaid_buffer; + pfile->buffer->cur = buf; + pfile->buffer->line_base = buf; + pfile->buffer->rlimit = buf + len + 1; + pfile->buffer->need_line = false; + pfile->overlaid_buffer = pfile->buffer; + bool saved_in_directive = pfile->state.in_directive; + pfile->state.in_directive = true; + cpp_context *saved_prev_context = context->prev; + context->prev = NULL; + + _cpp_scan_out_logical_line (pfile, NULL, true); + + pfile->state.in_directive = saved_in_directive; + check_output_buffer (pfile, 1); + *pfile->out.cur = '\n'; + pfile->buffer->cur = pfile->out.base + fmacro.offset; + pfile->buffer->line_base = pfile->buffer->cur; + pfile->buffer->rlimit = pfile->out.cur; + CUR (context) = pfile->buffer->cur; + RLIMIT (context) = pfile->buffer->rlimit; + + pfile->state.prevent_expansion++; + const uchar *text + = _cpp_builtin_macro_text (pfile, fmacro.node); + pfile->state.prevent_expansion--; + + context->prev = saved_prev_context; + pfile->buffer->cur = saved_cur; + pfile->buffer->rlimit = saved_rlimit; + pfile->buffer->line_base = saved_line_base; + pfile->buffer->need_line = saved_need_line; + pfile->overlaid_buffer = saved_overlaid_buffer; + pfile->out.cur = pfile->out.base + fmacro.offset; + CUR (context) = cur; + RLIMIT (context) = ctx_rlimit; + len = ustrlen (text); + buf = _cpp_unaligned_alloc (pfile, len + 1); + memcpy (buf, text, len); + buf[len] = '\n'; + text = buf; + _cpp_push_text_context (pfile, fmacro.node, + text, len); + goto new_context; + } + break; + } + cpp_macro *m = fmacro.node->value.macro; m->used = 1; @@ -588,8 +715,7 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro) { /* Remove the macro's invocation from the output, and push its replacement text. */ - pfile->out.cur = (pfile->out.base - + fmacro.offset); + pfile->out.cur = pfile->out.base + fmacro.offset; CUR (context) = cur; replace_args_and_push (pfile, &fmacro); goto new_context; @@ -711,7 +837,7 @@ push_replacement_text (cpp_reader *pfile, cpp_hashnode *node) len = ustrlen (text); buf = _cpp_unaligned_alloc (pfile, len + 1); memcpy (buf, text, len); - buf[len]='\n'; + buf[len] = '\n'; text = buf; } else @@ -742,7 +868,7 @@ recursive_macro (cpp_reader *pfile, cpp_hashnode *node) detect true recursion; instead we assume any expansion more than 20 deep since the first invocation of this macro must be recursing. */ - if (recursing && node->value.macro->fun_like) + if (recursing && fun_like_macro (node)) { size_t depth = 0; cpp_context *context = pfile->context; @@ -1080,7 +1206,7 @@ _cpp_create_trad_definition (cpp_reader *pfile, cpp_macro *macro) CPP_OPTION (pfile, discard_comments_in_macro_exp)); pfile->state.prevent_expansion++; - _cpp_scan_out_logical_line (pfile, macro); + _cpp_scan_out_logical_line (pfile, macro, false); pfile->state.prevent_expansion--; if (!macro)