diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 95c1eaa9d09..89e7a2230e5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2004-01-09 Joseph S. Myers + + PR c/11234 + * c-typeck.c (build_c_cast): If pedantic, warn for conversions + between function and object pointers. + (digest_init): When comparing a pointer to function type to the + target type, only apply TREE_TYPE once to the pointer to function + type. + * except.c (for_each_eh_label_1): Treat data as a pointer to a + function pointer rather than casting it to a function pointer. + (for_each_eh_label): Update caller. + * recog.h (struct insn_data): Use a struct or union for output. + * genoutput.c (output_insn_data): Update. + * final.c (get_insn_template): Update. + 2004-01-09 Mark Mitchell * expr.h (expand_expr): Make it a macro, not a function. diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 6d18f7ef098..ec00801a824 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -3125,6 +3125,25 @@ build_c_cast (tree type, tree expr) warning ("dereferencing type-punned pointer will break strict-aliasing rules"); } + /* If pedantic, warn for conversions between function and object + pointer types, except for converting a null pointer constant + to function pointer type. */ + if (pedantic + && TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (otype)) == FUNCTION_TYPE + && TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE) + pedwarn ("ISO C forbids conversion of function pointer to object pointer type"); + + if (pedantic + && TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE + && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE + && !(integer_zerop (value) && TREE_TYPE (otype) == void_type_node + && TREE_CODE (expr) != NOP_EXPR)) + pedwarn ("ISO C forbids conversion of object pointer to function pointer type"); + ovalue = value; /* Replace a nonvolatile const static variable with its value. */ if (optimize && TREE_CODE (value) == VAR_DECL) @@ -4088,9 +4107,12 @@ digest_init (tree type, tree init, int require_constant) || (code == VECTOR_TYPE && comptypes (TREE_TYPE (inside_init), type, COMPARE_STRICT)) || (code == POINTER_TYPE - && (TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE - || TREE_CODE (TREE_TYPE (inside_init)) == FUNCTION_TYPE) + && TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE && comptypes (TREE_TYPE (TREE_TYPE (inside_init)), + TREE_TYPE (type), COMPARE_STRICT)) + || (code == POINTER_TYPE + && TREE_CODE (TREE_TYPE (inside_init)) == FUNCTION_TYPE + && comptypes (TREE_TYPE (inside_init), TREE_TYPE (type), COMPARE_STRICT)))) { if (code == POINTER_TYPE) diff --git a/gcc/except.c b/gcc/except.c index 5958eae290f..1468d3b909f 100644 --- a/gcc/except.c +++ b/gcc/except.c @@ -1,6 +1,6 @@ /* Implements exception handling. Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. Contributed by Mike Stump . This file is part of GCC. @@ -2430,14 +2430,14 @@ void for_each_eh_label (void (*callback) (rtx)) { htab_traverse (cfun->eh->exception_handler_label_map, for_each_eh_label_1, - (void *)callback); + (void *) &callback); } static int for_each_eh_label_1 (void **pentry, void *data) { struct ehl_map_entry *entry = *(struct ehl_map_entry **)pentry; - void (*callback) (rtx) = (void (*) (rtx)) data; + void (*callback) (rtx) = *(void (**) (rtx)) data; (*callback) (entry->label); return 1; diff --git a/gcc/final.c b/gcc/final.c index ea9aa4bbb48..fbbff317d5e 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -1,6 +1,6 @@ /* Convert RTL to assembler code and output it, for GNU compiler. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, - 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -1591,17 +1591,16 @@ final (rtx first, FILE *file, int optimize, int prescan) const char * get_insn_template (int code, rtx insn) { - const void *output = insn_data[code].output; switch (insn_data[code].output_format) { case INSN_OUTPUT_FORMAT_SINGLE: - return (const char *) output; + return insn_data[code].output.single; case INSN_OUTPUT_FORMAT_MULTI: - return ((const char *const *) output)[which_alternative]; + return insn_data[code].output.multi[which_alternative]; case INSN_OUTPUT_FORMAT_FUNCTION: if (insn == NULL) abort (); - return (*(insn_output_fn) output) (recog_data.operand, insn); + return (*insn_data[code].output.function) (recog_data.operand, insn); default: abort (); diff --git a/gcc/genoutput.c b/gcc/genoutput.c index 6a2e0244491..9e27b276d0c 100644 --- a/gcc/genoutput.c +++ b/gcc/genoutput.c @@ -1,6 +1,6 @@ /* Generate code from to output assembler insns as recognized from rtl. Copyright (C) 1987, 1988, 1992, 1994, 1995, 1997, 1998, 1999, 2000, 2002, - 2003 Free Software Foundation, Inc. + 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -286,6 +286,7 @@ output_insn_data (void) break; } + printf ("#if GCC_VERSION >= 2007\n__extension__\n#endif\n"); printf ("\nconst struct insn_data insn_data[] = \n{\n"); for (d = idata; d; d = d->next) @@ -322,13 +323,22 @@ output_insn_data (void) switch (d->output_format) { case INSN_OUTPUT_FORMAT_NONE: - printf (" 0,\n"); + printf ("#if HAVE_DESIGNATED_INITIALIZERS\n"); + printf (" { 0 },\n"); + printf ("#else\n"); + printf (" { 0, 0, 0 },\n"); + printf ("#endif\n"); break; case INSN_OUTPUT_FORMAT_SINGLE: { const char *p = d->template; char prev = 0; + printf ("#if HAVE_DESIGNATED_INITIALIZERS\n"); + printf (" { .single =\n"); + printf ("#else\n"); + printf (" {\n"); + printf ("#endif\n"); printf (" \""); while (*p) { @@ -345,11 +355,26 @@ output_insn_data (void) ++p; } printf ("\",\n"); + printf ("#if HAVE_DESIGNATED_INITIALIZERS\n"); + printf (" },\n"); + printf ("#else\n"); + printf (" 0, 0 },\n"); + printf ("#endif\n"); } break; case INSN_OUTPUT_FORMAT_MULTI: + printf ("#if HAVE_DESIGNATED_INITIALIZERS\n"); + printf (" { .multi = output_%d },\n", d->code_number); + printf ("#else\n"); + printf (" { 0, output_%d, 0 },\n", d->code_number); + printf ("#endif\n"); + break; case INSN_OUTPUT_FORMAT_FUNCTION: - printf (" (const void *) output_%d,\n", d->code_number); + printf ("#if HAVE_DESIGNATED_INITIALIZERS\n"); + printf (" { .function = output_%d },\n", d->code_number); + printf ("#else\n"); + printf (" { 0, 0, output_%d },\n", d->code_number); + printf ("#endif\n"); break; default: abort (); diff --git a/gcc/recog.h b/gcc/recog.h index 749c64b4d90..a36c89655e6 100644 --- a/gcc/recog.h +++ b/gcc/recog.h @@ -1,5 +1,5 @@ /* Declarations for interface to insn recognizer and insn-output.c. - Copyright (C) 1987, 1996, 1997, 1998, 1999, 2000, 2001, 2003 + Copyright (C) 1987, 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -238,7 +238,19 @@ struct insn_operand_data struct insn_data { const char *const name; - const void *output; +#if HAVE_DESIGNATED_INITIALIZERS + union { + const char *single; + const char *const *multi; + insn_output_fn function; + } output; +#else + struct { + const char *single; + const char *const *multi; + insn_output_fn function; + } output; +#endif const insn_gen_fn genfun; const struct insn_operand_data *const operand; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 6b905bc442b..fa4e007f374 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2004-01-09 Joseph S. Myers + + PR c/11234 + * gcc.dg/func-ptr-conv-1.c: New test. + * gcc.dg/weak/weak-6.c, gcc.dg/weak/weak-7.c: Update. + 2004-01-09 Kazu Hirata PR target/13380. diff --git a/gcc/testsuite/gcc.dg/func-ptr-conv-1.c b/gcc/testsuite/gcc.dg/func-ptr-conv-1.c new file mode 100644 index 00000000000..4e42e5fe117 --- /dev/null +++ b/gcc/testsuite/gcc.dg/func-ptr-conv-1.c @@ -0,0 +1,56 @@ +/* Conversions between function and object pointers are not permitted + in any version of ISO C, even with casts, except for the special + case of converting a null pointer constant to function pointer + type. Likewise, comparisons between function and object pointers + are not permitted. PR c/11234. */ +/* Origin: Joseph Myers */ +/* { dg-do compile } */ +/* { dg-options "-pedantic" } */ + +void f(void); + +void *v1 = f; /* { dg-warning "pointer" "bad conversion" } */ +void *v2 = &f; /* { dg-warning "pointer" "bad conversion" } */ +void *v3 = (void *)f; /* { dg-warning "pointer" "bad conversion" } */ +void *v4 = (void *)&f; /* { dg-warning "pointer" "bad conversion" } */ +void *v5; +char *c1 = f; /* { dg-warning "pointer" "bad conversion" } */ +char *c2 = &f; /* { dg-warning "pointer" "bad conversion" } */ +char *c3 = (char *)f; /* { dg-warning "pointer" "bad conversion" } */ +char *c4 = (char *)&f; /* { dg-warning "pointer" "bad conversion" } */ +char *c5; +void (*fp)(void); +int a; + +void +g(void) +{ + v5 = f; /* { dg-warning "pointer" "bad conversion" } */ + v5 = &f; /* { dg-warning "pointer" "bad conversion" } */ + v5 = (void *)f; /* { dg-warning "pointer" "bad conversion" } */ + v5 = (void *)&f; /* { dg-warning "pointer" "bad conversion" } */ + c5 = f; /* { dg-warning "pointer" "bad conversion" } */ + c5 = &f; /* { dg-warning "pointer" "bad conversion" } */ + c5 = (char *)f; /* { dg-warning "pointer" "bad conversion" } */ + c5 = (char *)&f; /* { dg-warning "pointer" "bad conversion" } */ + fp = v5; /* { dg-warning "pointer" "bad conversion" } */ + fp = c5; /* { dg-warning "pointer" "bad conversion" } */ + fp = (void (*)(void))v5; /* { dg-warning "pointer" "bad conversion" } */ + fp = (void (*)(void))c5; /* { dg-warning "pointer" "bad conversion" } */ + (a ? f : v3); /* { dg-warning "pointer" "bad conversion" } */ + (a ? v2 : fp); /* { dg-warning "pointer" "bad conversion" } */ + /* The following are OK. */ + fp = 0; + fp = (void *)0; + fp = 0L; + fp = (void (*)(void))0; + fp = (void (*)(void))(void *)0; + (a ? f : 0); + (a ? f : (void *)0); + (a ? (void *)0 : fp); + (a ? 0 : fp); +} + +/* The following are OK. */ +void (*fp2)(void) = 0; +void (*fp3)(void) = (void *)0; diff --git a/gcc/testsuite/gcc.dg/weak/weak-6.c b/gcc/testsuite/gcc.dg/weak/weak-6.c index 531c581dc26..711003ccd03 100644 --- a/gcc/testsuite/gcc.dg/weak/weak-6.c +++ b/gcc/testsuite/gcc.dg/weak/weak-6.c @@ -3,5 +3,5 @@ extern void * foo (void); void * foo (void) { return (void *)foo; } /* { dg-error "precede" } */ - +/* { dg-error "function pointer" "pointer conversion" { target *-*-* } 5 } */ #pragma weak foo diff --git a/gcc/testsuite/gcc.dg/weak/weak-7.c b/gcc/testsuite/gcc.dg/weak/weak-7.c index bf2bbb95635..7c4a4dc7c25 100644 --- a/gcc/testsuite/gcc.dg/weak/weak-7.c +++ b/gcc/testsuite/gcc.dg/weak/weak-7.c @@ -3,5 +3,5 @@ extern void * foo (void); void * foo (void) { return (void *)foo; } /* { dg-error "precede" } */ - +/* { dg-error "function pointer" "pointer conversion" { target *-*-* } 5 } */ extern void * foo (void) __attribute__((weak));