[C++ PATCH] Fix FUNCTION_TYPE hashing problem (PR c++/33506)

Jakub Jelinek jakub@redhat.com
Thu Sep 20 04:02:00 GMT 2007


Hi!

The attached testcase issues incorrect diagnostics on valid code.
The problem seems to be caused by type hashing.
For attributes that require function type (nonnull, warn_unused_result,
sentinel, regparm, ...) decl_attributes changes the type (either
*decl itself or TREE_TYPE (*decl)) to one returned from
build_type_attribute_variant, which uses a hash table.  Unfortunately,
TYPE_LANG_SLOT_1 is not hashed (the generic code doesn't know how to
hash it anyway), so if there has been the same FUNCTION_TYPE already
with the same arguments and same attributes, but different
TYPE_RAISES_EXCEPTIONS, during attribute additions suddenly throw ()
is lost or we get some unrelated throw list from some other prototype.
One possibility to fix this is to compare TYPE_LANG_SLOT_1 (just
as a pointer) in type_hash_eq (but we risk creating too much garbage
in that case), another is to use a langhook in attribs.c, which
for C++ would be cp_build_type_attribute_variant, below is implemented
another approach, which in cplus_decl_attributes remembers the type
and if TYPE_RAISES_EXCEPTIONS changed, fix it up using
build_exception_variant.

Testing in progress on x86_64-linux, ok for trunk/4.2 if that succeeds?

2007-09-20  Jakub Jelinek  <jakub@redhat.com>

	PR c++/33506
	* decl2.c (cplus_decl_attributes): Restore TYPE_RAISES_EXCEPTIONS
	if decl_attributes changed it.

	* g++.dg/ext/attrib29.C: New test.

--- gcc/cp/decl2.c.jj	2007-09-19 12:23:29.000000000 +0200
+++ gcc/cp/decl2.c	2007-09-20 01:43:26.000000000 +0200
@@ -1070,6 +1070,8 @@ save_template_attributes (tree *attr_p, 
 void
 cplus_decl_attributes (tree *decl, tree attributes, int flags)
 {
+  tree oldfntype = NULL_TREE;
+
   if (*decl == NULL_TREE || *decl == void_type_node
       || *decl == error_mark_node
       || attributes == NULL_TREE)
@@ -1085,8 +1087,28 @@ cplus_decl_attributes (tree *decl, tree 
   if (TREE_CODE (*decl) == TEMPLATE_DECL)
     decl = &DECL_TEMPLATE_RESULT (*decl);
 
+  if (TREE_CODE (*decl) == FUNCTION_TYPE)
+    oldfntype = *decl;
+  else if (DECL_P (*decl) && TREE_CODE (TREE_TYPE (*decl)) == FUNCTION_TYPE)
+    oldfntype = TREE_TYPE (*decl);
+
   decl_attributes (decl, attributes, flags);
 
+  if (oldfntype)
+    {
+      if (TREE_CODE (*decl) == FUNCTION_TYPE
+	  && TYPE_RAISES_EXCEPTIONS (*decl)
+	     != TYPE_RAISES_EXCEPTIONS (oldfntype))
+	*decl
+	  = build_exception_variant (*decl,
+				     TYPE_RAISES_EXCEPTIONS (oldfntype));
+      else if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (*decl))
+	       != TYPE_RAISES_EXCEPTIONS (oldfntype))
+	TREE_TYPE (*decl)
+	  = build_exception_variant (TREE_TYPE (*decl),
+				     TYPE_RAISES_EXCEPTIONS (oldfntype));
+    }
+
   if (TREE_CODE (*decl) == TYPE_DECL)
     SET_IDENTIFIER_TYPE_VALUE (DECL_NAME (*decl), TREE_TYPE (*decl));
 }
--- gcc/testsuite/g++.dg/ext/attrib29.C.jj	2007-09-20 01:46:45.000000000 +0200
+++ gcc/testsuite/g++.dg/ext/attrib29.C	2007-09-20 01:46:13.000000000 +0200
@@ -0,0 +1,10 @@
+// PR c++/33506
+// { dg-do compile }
+
+extern int f1 (char *) __attribute__ ((warn_unused_result));
+extern int f2 (char *) throw () __attribute__ ((warn_unused_result));
+extern int f2 (char *) throw ();
+
+extern int f3 (char *) __attribute__ ((nonnull (1)));
+extern int f4 (char *) throw () __attribute__ ((nonnull (1)));
+extern int f4 (char *) throw ();

	Jakub



More information about the Gcc-patches mailing list