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]

C++ PATCH for c++/68763 (ICE in verify_unstripped_args)


The problem in this testcase is that the C++ front end modifies the TYPE_PURPOSE of TYPE_ARG_TYPES after a function type has been created and added to the hash table, so a later creation of an equivalent function type won't necessarily find the earlier type. Usually this just means extra copies of function types, but it causes verify_unstripped_types to abort, as it expects strip_typedefs to always return its input for template arguments.

So this modification of Jakub's first patch from the PR modifies strip_typedefs to avoid re-hashing a function type if we think nothing is changing about that type. The problem with his original patch was that it didn't consider attributes or the type itself being a typedef to be a change, and was therefore returning types that still contained typedefs.

Tested x86_64-pc-linux-gnu, applying to trunk.

I'm not adding the testcase at this point, because it is huge and depends on boost. Any thoughts about how to deal with the test?
commit db13eaa81c01d232a92449004f76f9d640321f1e
Author: Jason Merrill <jason@redhat.com>
Date:   Sun Jan 31 14:58:04 2016 +0100

    	PR c++/68763
    
    	* tree.c (strip_typedefs) [FUNCTION_TYPE]: Avoid building a new
    	function type if nothing is changing.

diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index d4cf310..2bf37bca 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1314,7 +1314,22 @@ strip_typedefs (tree t, bool *remove_attributes)
     case FUNCTION_TYPE:
     case METHOD_TYPE:
       {
-	tree arg_types = NULL, arg_node, arg_type;
+	tree arg_types = NULL, arg_node, arg_node2, arg_type;
+	bool changed;
+
+	/* Because we stomp on TREE_PURPOSE of TYPE_ARG_TYPES in many places
+	   around the compiler (e.g. cp_parser_late_parsing_default_args), we
+	   can't expect that re-hashing a function type will find a previous
+	   equivalent type, so try to reuse the input type if nothing has
+	   changed.  If the type is itself a variant, that will change.  */
+	bool is_variant = typedef_variant_p (t);
+	if (remove_attributes
+	    && (TYPE_ATTRIBUTES (t) || TYPE_USER_ALIGN (t)))
+	  is_variant = true;
+
+	type = strip_typedefs (TREE_TYPE (t), remove_attributes);
+	changed = type != TREE_TYPE (t) || is_variant;
+
 	for (arg_node = TYPE_ARG_TYPES (t);
 	     arg_node;
 	     arg_node = TREE_CHAIN (arg_node))
@@ -1324,11 +1339,27 @@ strip_typedefs (tree t, bool *remove_attributes)
 	    arg_type = strip_typedefs (TREE_VALUE (arg_node),
 				       remove_attributes);
 	    gcc_assert (arg_type);
+	    if (arg_type == TREE_VALUE (arg_node) && !changed)
+	      continue;
 
-	    arg_types =
-	      tree_cons (TREE_PURPOSE (arg_node), arg_type, arg_types);
+	    if (!changed)
+	      {
+		changed = true;
+		for (arg_node2 = TYPE_ARG_TYPES (t);
+		     arg_node2 != arg_node;
+		     arg_node2 = TREE_CHAIN (arg_node2))
+		  arg_types
+		    = tree_cons (TREE_PURPOSE (arg_node2),
+				 TREE_VALUE (arg_node2), arg_types);
+	      }
+
+	    arg_types
+	      = tree_cons (TREE_PURPOSE (arg_node), arg_type, arg_types);
 	  }
 
+	if (!changed)
+	  return t;
+
 	if (arg_types)
 	  arg_types = nreverse (arg_types);
 
@@ -1337,7 +1368,6 @@ strip_typedefs (tree t, bool *remove_attributes)
 	if (arg_node)
 	  arg_types = chainon (arg_types, void_list_node);
 
-	type = strip_typedefs (TREE_TYPE (t), remove_attributes);
 	if (TREE_CODE (t) == METHOD_TYPE)
 	  {
 	    tree class_type = TREE_TYPE (TREE_VALUE (arg_types));

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