This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]