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
This commit is contained in:
Jakub Jelinek 2015-03-23 09:02:39 +01:00 committed by Jakub Jelinek
parent 30c931de07
commit fb136e35c7
9 changed files with 266 additions and 18 deletions

View File

@ -1,3 +1,11 @@
2015-03-23 Jakub Jelinek <jakub@redhat.com>
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 <pault@gcc.gnu.org>
Mikael Morin <mikael@gcc.gnu.org>

View File

@ -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;
}

View File

@ -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 } */

View File

@ -0,0 +1,5 @@
/* PR preprocessor/65238 */
/* { dg-do run } */
/* { dg-options "-traditional-cpp" } */
#include "../../../c-c++-common/cpp/pr65238-1.c"

View File

@ -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 } */

View File

@ -1,3 +1,22 @@
2015-03-23 Jakub Jelinek <jakub@redhat.com>
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

View File

@ -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--;

View File

@ -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);

View File

@ -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)