summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2016-02-05 04:43:17 -0800
committerH.J. Lu <hjl.tools@gmail.com>2016-05-27 14:33:31 -0700
commit13f536cdc68f64a3f2d986a98fcb33e97deca7f4 (patch)
tree2c3772c078161667c2001b32650dc1640a0db8ef
parentee9eba49c5c7f1d194edc5ecedb383fe09418cfc (diff)
downloadgcc-13f536cdc68f64a3f2d986a98fcb33e97deca7f4.tar.gz
Rebuild array with the updated function pointer type
When we apply function attribute to array of function pointer, we need to rebuild array with the updated function pointer type. gcc/ PR c/68637 * attribs.c (decl_attributes): Rebuild array with the updated function pointer type. gcc/testsuite/ PR c/68637 * gcc.target/i386/pr68637-1.c: New test. * gcc.target/i386/pr68637-2.c: Likewise.
-rw-r--r--gcc/attribs.c18
-rw-r--r--gcc/testsuite/gcc.target/i386/pr68637-1.c10
-rw-r--r--gcc/testsuite/gcc.target/i386/pr68637-2.c25
3 files changed, 52 insertions, 1 deletions
diff --git a/gcc/attribs.c b/gcc/attribs.c
index 9a886214ec4..c5cc3c5faba 100644
--- a/gcc/attribs.c
+++ b/gcc/attribs.c
@@ -494,9 +494,18 @@ decl_attributes (tree *node, tree attributes, int flags)
flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
}
+ tree array_type = (TREE_CODE (*anode) == ARRAY_TYPE
+ ? *anode
+ : NULL_TREE);
+
if (spec->function_type_required && TREE_CODE (*anode) != FUNCTION_TYPE
&& TREE_CODE (*anode) != METHOD_TYPE)
{
+ /* We need to rebuid array with the updated function pointer
+ type later. */
+ if (array_type)
+ *anode = TREE_TYPE (*anode);
+
if (TREE_CODE (*anode) == POINTER_TYPE
&& (TREE_CODE (TREE_TYPE (*anode)) == FUNCTION_TYPE
|| TREE_CODE (TREE_TYPE (*anode)) == METHOD_TYPE))
@@ -617,7 +626,14 @@ decl_attributes (tree *node, tree attributes, int flags)
if (fn_ptr_quals)
fn_ptr_tmp = build_qualified_type (fn_ptr_tmp, fn_ptr_quals);
if (DECL_P (*node))
- TREE_TYPE (*node) = fn_ptr_tmp;
+ {
+ if (array_type)
+ TREE_TYPE (*node)
+ = build_array_type (fn_ptr_tmp,
+ TYPE_DOMAIN (array_type));
+ else
+ TREE_TYPE (*node) = fn_ptr_tmp;
+ }
else
{
gcc_assert (TREE_CODE (*node) == POINTER_TYPE);
diff --git a/gcc/testsuite/gcc.target/i386/pr68637-1.c b/gcc/testsuite/gcc.target/i386/pr68637-1.c
new file mode 100644
index 00000000000..b1661fd49b2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr68637-1.c
@@ -0,0 +1,10 @@
+/* { dg-do run { target ia32 } } */
+/* { dg-additional-sources pr68637-2.c } */
+
+extern void (*bar[]) (int, int) __attribute__ ((regparm (2)));
+
+void
+foo (void)
+{
+ bar[0] (1, 2);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr68637-2.c b/gcc/testsuite/gcc.target/i386/pr68637-2.c
new file mode 100644
index 00000000000..7d9654d3070
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr68637-2.c
@@ -0,0 +1,25 @@
+/* { dg-do compile { target ia32 } } */
+
+static void
+__attribute__ ((regparm (2)))
+bar0 (int i, int j)
+{
+ if (i != 1 || j != 2)
+ __builtin_abort ();
+}
+
+typedef void (*func_t) (int, int) __attribute__ ((regparm (2)));
+
+func_t bar[] =
+{
+ bar0,
+};
+
+extern void foo (void);
+
+int
+main ()
+{
+ foo ();
+ return 0;
+}