This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Patch for PR c/11234
- From: "Joseph S. Myers" <jsm at polyomino dot org dot uk>
- To: gcc-patches at gcc dot gnu dot org
- Date: Thu, 8 Jan 2004 20:23:40 +0000 (UTC)
- Subject: Patch for PR c/11234
This patch fixes PR c/11234 (nondiagnosis of certain invalid
conversions between function and object pointers). Various places
where GCC itself uses such conversions are changed to use pointers to
function pointers.
Bootstrapped with no regressions on i686-pc-linux-gnu. OK to commit
the patches to except.c, genoutput.c, final.c and recog.h for misuse
of casts between object and function pointers shown up by this patch,
and the patches updating weak-6.c and weak-7.c for the new
diagnostics?
2004-01-08 Joseph S. Myers <jsm@polyomino.org.uk>
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.
* genoutput.c (output_insn_data, process_template): Use pointers
to function pointers rather than function pointers themselves
where conversion to object pointers is required.
* final.c (get_insn_template): Update.
* recog.h (INSN_OUTPUT_FORMAT_FUNCTION): Update comment.
testsuite:
2004-01-08 Joseph S. Myers <jsm@polyomino.org.uk>
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.
--- GCC/gcc/c-typeck.c.orig 2004-01-07 22:20:16.000000000 +0000
+++ GCC/gcc/c-typeck.c 2004-01-07 23:16:00.000000000 +0000
@@ -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 r
|| (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)
--- GCC/gcc/except.c.orig 2003-11-15 10:50:35.000000000 +0000
+++ GCC/gcc/except.c 2004-01-08 16:16:56.000000000 +0000
@@ -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;
--- GCC/gcc/final.c.orig 2004-01-07 10:59:53.000000000 +0000
+++ GCC/gcc/final.c 2004-01-08 16:35:58.000000000 +0000
@@ -1607,7 +1607,7 @@ get_insn_template (int code, rtx insn)
case INSN_OUTPUT_FORMAT_FUNCTION:
if (insn == NULL)
abort ();
- return (*(insn_output_fn) output) (recog_data.operand, insn);
+ return (**(insn_output_fn *) output) (recog_data.operand, insn);
default:
abort ();
--- GCC/gcc/genoutput.c.orig 2003-10-06 12:25:12.000000000 +0000
+++ GCC/gcc/genoutput.c 2004-01-08 16:39:11.000000000 +0000
@@ -348,9 +348,11 @@ output_insn_data (void)
}
break;
case INSN_OUTPUT_FORMAT_MULTI:
- case INSN_OUTPUT_FORMAT_FUNCTION:
printf (" (const void *) output_%d,\n", d->code_number);
break;
+ case INSN_OUTPUT_FORMAT_FUNCTION:
+ printf (" (const void *) &output_%d_ptr,\n", d->code_number);
+ break;
default:
abort ();
}
@@ -644,6 +646,8 @@ process_template (struct data *d, const
puts (template + 1);
puts ("}");
+ printf ("static const char * (*output_%d_ptr) (rtx *operands ATTRIBUTE_UNUSED, rtx insn ATTRIBUTE_UNUSED) = &output_%d;\n",
+ d->code_number, d->code_number);
}
/* If the assembler code template starts with a @ it is a newline-separated
--- GCC/gcc/recog.h.orig 2003-12-02 10:26:31.000000000 +0000
+++ GCC/gcc/recog.h 2004-01-08 16:36:10.000000000 +0000
@@ -233,7 +233,7 @@ struct insn_operand_data
#define INSN_OUTPUT_FORMAT_NONE 0 /* abort */
#define INSN_OUTPUT_FORMAT_SINGLE 1 /* const char * */
#define INSN_OUTPUT_FORMAT_MULTI 2 /* const char * const * */
-#define INSN_OUTPUT_FORMAT_FUNCTION 3 /* const char * (*)(...) */
+#define INSN_OUTPUT_FORMAT_FUNCTION 3 /* const char * (**)(...) */
struct insn_data
{
--- GCC/gcc/testsuite/gcc.dg/func-ptr-conv-1.c 2002-08-26 16:21:36.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/func-ptr-conv-1.c 2004-01-07 23:21:42.000000000 +0000
@@ -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 <jsm@polyomino.org.uk> */
+/* { 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;
--- GCC/gcc/testsuite/gcc.dg/weak/weak-6.c.orig 2003-10-04 07:36:45.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/weak/weak-6.c 2004-01-08 19:26:37.000000000 +0000
@@ -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
--- GCC/gcc/testsuite/gcc.dg/weak/weak-7.c.orig 2003-10-04 07:36:45.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/weak/weak-7.c 2004-01-08 19:26:49.000000000 +0000
@@ -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));
--
Joseph S. Myers
jsm@polyomino.org.uk