diff mbox

Fix PR c++/66850 (Adding a forward declaration causes ICE on valid code)

Message ID 1436743897-1520-1-git-send-email-patrick@parcs.ath.cx
State New
Headers show

Commit Message

Patrick Palka July 12, 2015, 11:31 p.m. UTC
This patch attempts resolve the mentioned PR by fixing two underlying
issues:

1.

When a template is first declared we currently take care to set
the DECL_CONTEXT of each of its template template parms to point to it (line
5119 in pt.c:push_template_decl_real).  However, we currently don't do
this for subsequent redeclarations of the template
(push_template_decl_real is only called for the first declaration).
If a DECL_CONTEXT of a template template parm is not set,
lookup_template_class_1 gets confused when it attempts to instantiate
the template template parm.

This patch makes the function redeclare_class_template to also set the
DECL_CONTEXTs of a template template parm.

2.

When the DECL_CONTEXT of a template template parm is not set,
lookup_template_class_1 instead uses current_template_args to synthesize
an argument list instead of using the TI_ARGS of the DECL_CONTEXT.
Using current_template_args is not 100% right, however, since we may not
currently be in the same parameter level that the template template parm
was defined in.  We may be in a deeper parameter level if 1) a nested
template has been defined in the meantime or 2) if a nested parameter
list has been started in the meantime.  Parameter levels that are greater
than the level of the given template template parm are irrelevant.

This patch peels off these irrelevant parameter levels from
current_template_parms before augmenting the argument list in
lookup_template_class_1.

OK to commit after bootstrap + regtest?

gcc/cp/ChangeLog:

	PR c++/66850
	* pt.c (redeclare_class_template): Set the DECL_CONTEXTs of each
	template template parm in the redeclaration.
	(lookup_template_class_1): Peel off irrelevant template levels
	from current_template_parms before augmenting the argument
	list.

gcc/testsuite/ChangeLog:

	PR c++/66850
	* g++.dg/template/pr66850.C: New test.
---
 gcc/cp/pt.c                             | 25 ++++++++++++++++---
 gcc/testsuite/g++.dg/template/pr66850.C | 44 +++++++++++++++++++++++++++++++++
 2 files changed, 66 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/pr66850.C

Comments

Patrick Palka July 12, 2015, 11:35 p.m. UTC | #1
On Sun, Jul 12, 2015 at 7:31 PM, Patrick Palka <patrick@parcs.ath.cx> wrote:
> This patch attempts resolve the mentioned PR by fixing two underlying
> issues:

I should note that there is some overlap between the fixes.
Technically fix #2 is sufficient to resolve the PR, whereas fix #1 can
only resolve the first test case in namespace X below.  But fix #1
seems to be sensible even if it is redundant.
Jason Merrill July 14, 2015, 5:23 p.m. UTC | #2
OK.

Jason
diff mbox

Patch

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 2097963..6bdfd33 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -5297,6 +5297,14 @@  redeclare_class_template (tree type, tree parms)
 	/* Update the new parameters, too; they'll be used as the
 	   parameters for any members.  */
 	TREE_PURPOSE (TREE_VEC_ELT (parms, i)) = tmpl_default;
+
+      /* Give each template template parm in this redeclaration a
+	 DECL_CONTEXT of the template for which they are a parameter.  */
+      if (TREE_CODE (parm) == TEMPLATE_DECL)
+	{
+	  gcc_assert (DECL_CONTEXT (parm) == NULL_TREE);
+	  DECL_CONTEXT (parm) = tmpl;
+	}
     }
 
     return true;
@@ -7749,9 +7757,20 @@  lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
       if (outer)
 	outer = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (outer)));
       else if (current_template_parms)
-	/* This is an argument of the current template, so we haven't set
-	   DECL_CONTEXT yet.  */
-	outer = current_template_args ();
+	{
+	  /* This is an argument of the current template, so we haven't set
+	     DECL_CONTEXT yet.  */
+	  tree relevant_template_parms;
+
+	  /* Parameter levels that are greater than the level of the given
+	     template template parm are irrelevant.  */
+	  relevant_template_parms = current_template_parms;
+	  while (TMPL_PARMS_DEPTH (relevant_template_parms)
+		 != TEMPLATE_TYPE_LEVEL (TREE_TYPE (templ)))
+	    relevant_template_parms = TREE_CHAIN (relevant_template_parms);
+
+	  outer = template_parms_to_args (relevant_template_parms);
+	}
 
       if (outer)
 	arglist = add_to_template_args (outer, arglist);
diff --git a/gcc/testsuite/g++.dg/template/pr66850.C b/gcc/testsuite/g++.dg/template/pr66850.C
new file mode 100644
index 0000000..31c1290
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/pr66850.C
@@ -0,0 +1,44 @@ 
+// PR c++/66850
+// Each namespace contains an otherwise standalone test case, none of which
+// should cause an ICE.
+
+namespace X {
+  template <template <typename U, U> class> struct Sort;
+
+  template <template <typename U, U> class Comparator>
+  struct Sort
+  {
+    template <int I>
+    struct less_than
+    {
+      Comparator<int, I> a;
+    };
+  };
+}
+
+namespace Y {
+  template <typename C, C> struct integral_constant {};
+
+  template <typename T, template <typename U, U> class> struct Sort;
+
+  template <template <typename U, U> class Comparator>
+  struct Sort<int, Comparator>
+  {
+      template <int I> struct less_than:
+          integral_constant<bool, Comparator<int, I>::value> {};
+  };
+}
+
+namespace Z {
+  template <typename T, template <typename U, U> class> struct Sort;
+
+  template <template <typename U, U> class Comparator>
+  struct Sort<int, Comparator>
+  {
+    template <int I>
+    struct less_than
+    {
+      Comparator<int, I> a;
+    };
+  };
+}