diff mbox

C++ PATCH for c++/59614 (compile hog with lots of templates)

Message ID 52CD9D2E.2030002@redhat.com
State New
Headers show

Commit Message

Jason Merrill Jan. 8, 2014, 6:47 p.m. UTC
I was forgetting that recursing into template arguments would in turn 
recurse into their template arguments, leading to quadratic behavior. 
So, look at template arguments only once and add any inherited tags to 
the instantiated type.

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

Patch

commit f97c952a82d54a4cf0fc4583560de78589fa5664
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Jan 7 17:19:20 2014 -0500

    	PR c++/59614
    	* class.c (abi_tag_data): Add tags field.
    	(check_abi_tags): Initialize it.
    	(find_abi_tags_r): Support collecting missing tags.
    	(mark_type_abi_tags): Don't look at template args.
    	(inherit_targ_abi_tags): New.
    	(check_bases_and_members): Use it.
    	* cp-tree.h (ABI_TAG_IMPLICIT): New.
    	* mangle.c (write_abi_tags): Check it.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index c961b22..0c3ce47 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -1340,14 +1340,20 @@  struct abi_tag_data
 {
   tree t;
   tree subob;
+  // error_mark_node to get diagnostics; otherwise collect missing tags here
+  tree tags;
 };
 
 static tree
-find_abi_tags_r (tree *tp, int */*walk_subtrees*/, void *data)
+find_abi_tags_r (tree *tp, int *walk_subtrees, void *data)
 {
   if (!OVERLOAD_TYPE_P (*tp))
     return NULL_TREE;
 
+  /* walk_tree shouldn't be walking into any subtrees of a RECORD_TYPE
+     anyway, but let's make sure of it.  */
+  *walk_subtrees = false;
+
   if (tree attributes = lookup_attribute ("abi_tag", TYPE_ATTRIBUTES (*tp)))
     {
       struct abi_tag_data *p = static_cast<struct abi_tag_data*>(data);
@@ -1358,7 +1364,20 @@  find_abi_tags_r (tree *tp, int */*walk_subtrees*/, void *data)
 	  tree id = get_identifier (TREE_STRING_POINTER (tag));
 	  if (!IDENTIFIER_MARKED (id))
 	    {
-	      if (TYPE_P (p->subob))
+	      if (p->tags != error_mark_node)
+		{
+		  /* We're collecting tags from template arguments.  */
+		  tree str = build_string (IDENTIFIER_LENGTH (id),
+					   IDENTIFIER_POINTER (id));
+		  p->tags = tree_cons (NULL_TREE, str, p->tags);
+		  ABI_TAG_IMPLICIT (p->tags) = true;
+
+		  /* Don't inherit this tag multiple times.  */
+		  IDENTIFIER_MARKED (id) = true;
+		}
+
+	      /* Otherwise we're diagnosing missing tags.  */
+	      else if (TYPE_P (p->subob))
 		{
 		  warning (OPT_Wabi_tag, "%qT does not have the %E abi tag "
 			   "that base %qT has", p->t, tag, p->subob);
@@ -1397,22 +1416,6 @@  mark_type_abi_tags (tree t, bool val)
 	  IDENTIFIER_MARKED (id) = val;
 	}
     }
-
-  /* Also mark ABI tags from template arguments.  */
-  if (CLASSTYPE_TEMPLATE_INFO (t))
-    {
-      tree args = CLASSTYPE_TI_ARGS (t);
-      for (int i = 0; i < TMPL_ARGS_DEPTH (args); ++i)
-	{
-	  tree level = TMPL_ARGS_LEVEL (args, i+1);
-	  for (int j = 0; j < TREE_VEC_LENGTH (level); ++j)
-	    {
-	      tree arg = TREE_VEC_ELT (level, j);
-	      if (CLASS_TYPE_P (arg))
-		mark_type_abi_tags (arg, val);
-	    }
-	}
-    }
 }
 
 /* Check that class T has all the abi tags that subobject SUBOB has, or
@@ -1424,13 +1427,50 @@  check_abi_tags (tree t, tree subob)
   mark_type_abi_tags (t, true);
 
   tree subtype = TYPE_P (subob) ? subob : TREE_TYPE (subob);
-  struct abi_tag_data data = { t, subob };
+  struct abi_tag_data data = { t, subob, error_mark_node };
 
   cp_walk_tree_without_duplicates (&subtype, find_abi_tags_r, &data);
 
   mark_type_abi_tags (t, false);
 }
 
+void
+inherit_targ_abi_tags (tree t)
+{
+  if (CLASSTYPE_TEMPLATE_INFO (t) == NULL_TREE)
+    return;
+
+  mark_type_abi_tags (t, true);
+
+  tree args = CLASSTYPE_TI_ARGS (t);
+  struct abi_tag_data data = { t, NULL_TREE, NULL_TREE };
+  for (int i = 0; i < TMPL_ARGS_DEPTH (args); ++i)
+    {
+      tree level = TMPL_ARGS_LEVEL (args, i+1);
+      for (int j = 0; j < TREE_VEC_LENGTH (level); ++j)
+	{
+	  tree arg = TREE_VEC_ELT (level, j);
+	  data.subob = arg;
+	  cp_walk_tree_without_duplicates (&arg, find_abi_tags_r, &data);
+	}
+    }
+
+  // If we found some tags on our template arguments, add them to our
+  // abi_tag attribute.
+  if (data.tags)
+    {
+      tree attr = lookup_attribute ("abi_tag", TYPE_ATTRIBUTES (t));
+      if (attr)
+	TREE_VALUE (attr) = chainon (data.tags, TREE_VALUE (attr));
+      else
+	TYPE_ATTRIBUTES (t)
+	  = tree_cons (get_identifier ("abi_tag"), data.tags,
+		       TYPE_ATTRIBUTES (t));
+    }
+
+  mark_type_abi_tags (t, false);
+}
+
 /* Run through the base classes of T, updating CANT_HAVE_CONST_CTOR_P,
    and NO_CONST_ASN_REF_P.  Also set flag bits in T based on
    properties of the bases.  */
@@ -5431,6 +5471,9 @@  check_bases_and_members (tree t)
   bool saved_nontrivial_dtor;
   tree fn;
 
+  /* Pick up any abi_tags from our template arguments before checking.  */
+  inherit_targ_abi_tags (t);
+
   /* By default, we use const reference arguments and generate default
      constructors.  */
   cant_have_const_ctor = 0;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index bdae500..96af562f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -65,6 +65,7 @@  c-common.h, not after.
       TARGET_EXPR_IMPLICIT_P (in TARGET_EXPR)
       TEMPLATE_PARM_PARAMETER_PACK (in TEMPLATE_PARM_INDEX)
       ATTR_IS_DEPENDENT (in the TREE_LIST for an attribute)
+      ABI_TAG_IMPLICIT (in the TREE_LIST for the argument of abi_tag)
       CONSTRUCTOR_IS_DIRECT_INIT (in CONSTRUCTOR)
       LAMBDA_EXPR_CAPTURES_THIS_P (in LAMBDA_EXPR)
       DECLTYPE_FOR_LAMBDA_CAPTURE (in DECLTYPE_TYPE)
@@ -2589,6 +2590,10 @@  struct GTY((variable_size)) lang_decl {
    must be applied at instantiation time.  */
 #define ATTR_IS_DEPENDENT(NODE) TREE_LANG_FLAG_0 (TREE_LIST_CHECK (NODE))
 
+/* In a TREE_LIST in the argument of attribute abi_tag, indicates that the tag
+   was inherited from a template parameter, not explicitly indicated.  */
+#define ABI_TAG_IMPLICIT(NODE) TREE_LANG_FLAG_0 (TREE_LIST_CHECK (NODE))
+
 extern tree decl_shadowed_for_var_lookup (tree);
 extern void decl_shadowed_for_var_insert (tree, tree);
 
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index d6650d3..add73cf 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -1341,6 +1341,8 @@  write_abi_tags (tree tags)
 
   for (tree t = tags; t; t = TREE_CHAIN (t))
     {
+      if (ABI_TAG_IMPLICIT (t))
+	continue;
       tree str = TREE_VALUE (t);
       vec_safe_push (vec, str);
     }
diff --git a/gcc/testsuite/g++.dg/abi/abi-tag5.C b/gcc/testsuite/g++.dg/abi/abi-tag5.C
index de55802..95e367e 100644
--- a/gcc/testsuite/g++.dg/abi/abi-tag5.C
+++ b/gcc/testsuite/g++.dg/abi/abi-tag5.C
@@ -1,6 +1,7 @@ 
 // { dg-options -Wabi-tag }
+// { dg-final { scan-assembler "_Z1f1BI1AB3fooE" } }
 
 struct __attribute__ ((abi_tag ("foo"))) A { };
 template <class T> struct B: T { };
 
-B<A> b;
+void f(B<A>) {}