This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PATCH to function pointer attribute handling
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 19 Aug 2003 23:33:42 -0400
- Subject: PATCH to function pointer attribute handling
Forcing memory variables to be copied into regs before use on the tree-ssa
branch broke gcc.dg/sibcall-5.c because we used
build_type_variant (type, 0, 0)
to generate the (function pointer) type of the temporary, which stripped
the regparm attribute from the pointed-to type. This is wrong;
int (*)(int, int)
and
int (*)(int, int) __attribute__ ((regparm (2)))
should not have the same TYPE_MAIN_VALUE, any more than "int *" and "const
int *" do. Fixed by the decl_attributes change below.
The get_qualified_type change was my first attempt to fix this failure; it
isn't necessary, but also seems correct. Changing the cv-quals of a type
should not also change the attributes.
Tested athlon-pc-linux-gnu, applied to tree-ssa. Currently testing on the
trunk.
2003-08-19 Jason Merrill <jason@redhat.com>
* attribs.c (decl_attributes): Rebuild the function pointer type after
changing the target type.
* tree.c (get_qualified_type): Also check that the attributes match.
*** ./tree.c.~1~ Tue Aug 19 14:38:35 2003
--- ./tree.c Tue Aug 19 17:07:43 2003
*************** get_qualified_type (tree type, int type_
*** 2846,2852 ****
preserve the TYPE_NAME, since there is code that depends on this. */
for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
if (TYPE_QUALS (t) == type_quals && TYPE_NAME (t) == TYPE_NAME (type)
! && TYPE_CONTEXT (t) == TYPE_CONTEXT (type))
return t;
return NULL_TREE;
--- 2846,2853 ----
preserve the TYPE_NAME, since there is code that depends on this. */
for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
if (TYPE_QUALS (t) == type_quals && TYPE_NAME (t) == TYPE_NAME (type)
! && TYPE_CONTEXT (t) == TYPE_CONTEXT (type)
! && attribute_list_equal (TYPE_ATTRIBUTES (t), TYPE_ATTRIBUTES (type)))
return t;
return NULL_TREE;
*** ./attribs.c.~1~ Tue Aug 19 14:38:34 2003
--- ./attribs.c Tue Aug 19 17:07:44 2003
*************** decl_attributes (tree *node, tree attrib
*** 162,167 ****
--- 162,168 ----
tree *anode = node;
const struct attribute_spec *spec = NULL;
bool no_add_attrs = 0;
+ tree fn_ptr_tmp = NULL_TREE;
size_t i;
for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
*************** decl_attributes (tree *node, tree attrib
*** 230,238 ****
&& (TREE_CODE (TREE_TYPE (*anode)) == FUNCTION_TYPE
|| TREE_CODE (TREE_TYPE (*anode)) == METHOD_TYPE))
{
! if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
! *anode = build_type_copy (*anode);
! anode = &TREE_TYPE (*anode);
}
else if (flags & (int) ATTR_FLAG_FUNCTION_NEXT)
{
--- 231,248 ----
&& (TREE_CODE (TREE_TYPE (*anode)) == FUNCTION_TYPE
|| TREE_CODE (TREE_TYPE (*anode)) == METHOD_TYPE))
{
! /* OK, this is a bit convoluted. We can't just make a copy
! of the pointer type and modify its TREE_TYPE, because if
! we change the attributes of the target type the pointer
! type needs to have a different TYPE_MAIN_VARIANT. So we
! pull out the target type now, frob it as appropriate, and
! rebuild the pointer type later.
!
! This would all be simpler if attributes were part of the
! declarator, grumble grumble. */
! fn_ptr_tmp = TREE_TYPE (*anode);
! anode = &fn_ptr_tmp;
! flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
}
else if (flags & (int) ATTR_FLAG_FUNCTION_NEXT)
{
*************** decl_attributes (tree *node, tree attrib
*** 299,304 ****
--- 309,327 ----
old_attrs));
}
}
+
+ if (fn_ptr_tmp)
+ {
+ /* Rebuild the function pointer type and put it in the
+ appropriate place. */
+ fn_ptr_tmp = build_pointer_type (fn_ptr_tmp);
+ if (DECL_P (*node))
+ TREE_TYPE (*node) = fn_ptr_tmp;
+ else if (TREE_CODE (*node) == POINTER_TYPE)
+ *node = fn_ptr_tmp;
+ else
+ abort ();
+ }
}
return returned_attrs;