public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] PR c++/50852 - loose template parameter comparison
@ 2011-11-17 21:56 Dodji Seketeli
  2012-01-17 19:03 ` Jason Merrill
  2012-04-12 21:08 ` [PATCH] PR c++/50852 - loose template parameter comparison Jason Merrill
  0 siblings, 2 replies; 18+ messages in thread
From: Dodji Seketeli @ 2011-11-17 21:56 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches

Hello,

In the example of the patch below the two U parameters of template C
and D compare equal, so the two A<X::a-1> types also compare equal.
When we lookup up A<X::a-1> inside struct D, lookup_template_class_1
actually yields the A<X::a-1> that is inside struct C.

This is a problem because when substituting the arguments
{B<A1>, 3} for the parameters of the typedef X (in tsubst), we end up
considering the parameters {U, V} of X in struct C instead of considering the
parameters {U, int d} of X in struct D.  This leads to an ICE as the
argument '3' doesn't match the parameter V.

A possible way of seeing the root cause of this issue is that two
template parameters that have the same type, same index and level, same
number of sibling parameters but belong to template parameter lists of
"different kinds" are comparing equal.

I am moving away from considering the number of sibling parameters for
parameter identity and considering a hash of the sibling parameters
instead.

That hash is different from what iterative_hash_template_arg does in
two ways.

It doesn't take in account the level of a given template parameter.
Otherwise it would for instance consider the two Us (and thus the two
f) below as different:

    template<class T>
    struct S {
      template<class U>
      void f();
    };

    template<>
    template<U>
    void
    S<int>::f()
    {
    }

When hashing a template template parameter TT, it only hashes the
parameters of TT.  It doesn't hash the TEMPLATE_DECL of TT itself.
Otherwise the two TTs below (and thus the two f) would be considered
different, as they are effectively represented by two different
TEMPLATE_DECLs:

    template<template<class U> class TT>
    struct S {
      void f();
    };

    template<template<class U> class TT>
    void
    S<TT>::f()
    {
    }

Bootstrapped and tested on x86_64-unknown-linux-gnu against trunk.

gcc/cp/

	PR c++/50852 - loose template parameter comparison
	* cp-tree.h (template_parm_index_s::sibling_hash): Rename
	num_siblings members into this.
	(TEMPLATE_PARM_SIBLINGS_HASH): Renamed TEMPLATE_PARM_NUM_SIBLINGS
	into this.
	(process_template_parm): Remove num_sibling_parms parameter.
	* pt.c 	(iterative_hash_template_parms)
	(iterative_hash_template_parm_index_no_level): New static
	functions.
	(fixup_template_parms): Calculate the hash of the parameters and
	use that during fixup.
	(fixup_template_parm): Use sibling hash instead of number of
	parameters.  Calculate and use hash for parameters of template
	template parameters.
	(build_template_parm_index, fixup_template_type_parm_type)
	(fixup_template_parm_index): Replace use of num_sibling_parms with
	use of siblings_hash.  Adjust comments.
	(process_template_parm): Remove num_template_parms parm.
	(reduce_template_parm_level): Adjust call to
	build_template_parm_index.
	* tree.c (cp_tree_equal): Use TEMPLATE_PARM_SIBLINGS_HASH instead
	of TEMPLATE_PARM_NUM_SIBLINGS
	* typeck.c (comp_template_parms_position): Likewise.  Update
	comment.
	* parser.c (cp_parser_template_parameter_list): Adjust call to
	process_template_parm.

gcc/testsuite/

	PR c++/50852 - loose template parameter comparison
	* g++.dg/template/canon-type-14.C: New test case.
---
 gcc/cp/cp-tree.h                              |   14 ++-
 gcc/cp/parser.c                               |    3 +-
 gcc/cp/pt.c                                   |  130 ++++++++++++++++++-------
 gcc/cp/tree.c                                 |    4 +-
 gcc/cp/typeck.c                               |    8 +-
 gcc/testsuite/g++.dg/template/canon-type-14.C |   16 +++
 6 files changed, 126 insertions(+), 49 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/canon-type-14.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b306976..da8f179 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -244,7 +244,11 @@ struct GTY(()) template_parm_index_s {
   int index;
   int level;
   int orig_level;
-  int num_siblings;
+  /* This hash value captures the types and the number of sibling
+     parameters this parameter belongs to.  If two template parameters
+     have a different siblings_hash, it means they don't belong to
+     compatible lists of template parameters.  */
+  hashval_t siblings_hash;
   tree decl;
 };
 typedef struct template_parm_index_s template_parm_index;
@@ -4472,9 +4476,9 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
 	((template_parm_index*)TEMPLATE_PARM_INDEX_CHECK (NODE))
 #define TEMPLATE_PARM_IDX(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->index)
 #define TEMPLATE_PARM_LEVEL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->level)
-/* The Number of sibling parms this template parm has.  */
-#define TEMPLATE_PARM_NUM_SIBLINGS(NODE) \
-  (TEMPLATE_PARM_INDEX_CAST (NODE)->num_siblings)
+/* A hash value for the sibling parms this template parm has.  */
+#define TEMPLATE_PARM_SIBLINGS_HASH(NODE) \
+  (TEMPLATE_PARM_INDEX_CAST (NODE)->siblings_hash)
 #define TEMPLATE_PARM_DESCENDANTS(NODE) (TREE_CHAIN (NODE))
 #define TEMPLATE_PARM_ORIG_LEVEL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->orig_level)
 #define TEMPLATE_PARM_DECL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->decl)
@@ -5242,7 +5246,7 @@ extern void append_type_to_template_for_access_check (tree, tree, tree,
 extern tree splice_late_return_type		(tree, tree);
 extern bool is_auto				(const_tree);
 extern tree process_template_parm		(tree, location_t, tree, 
-						 bool, bool, unsigned);
+						 bool, bool);
 extern tree end_template_parm_list		(tree);
 void fixup_template_parms (void);
 extern void end_template_decl			(void);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index fc8f3c8..f777590 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -11883,8 +11883,7 @@ cp_parser_template_parameter_list (cp_parser* parser)
 						parm_loc,
 						parameter,
 						is_non_type,
-						is_parameter_pack,
-						0);
+						is_parameter_pack);
       else
        {
          tree err_parm = build_tree_list (parameter, parameter);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 9738026..5a8b1bd 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -148,7 +148,7 @@ static tree convert_template_argument (tree, tree, tree,
 static int for_each_template_parm (tree, tree_fn_t, void*,
 				   struct pointer_set_t*, bool);
 static tree expand_template_argument_pack (tree);
-static tree build_template_parm_index (int, int, int, int, tree, tree);
+static tree build_template_parm_index (int, int, int, hashval_t, tree, tree);
 static bool inline_needs_template_parms (tree);
 static void push_inline_template_parms_recursive (tree, int);
 static tree retrieve_local_specialization (tree);
@@ -205,9 +205,11 @@ static tree listify_autos (tree, tree);
 static tree template_parm_to_arg (tree t);
 static bool arg_from_parm_pack_p (tree, tree);
 static tree current_template_args (void);
-static tree fixup_template_type_parm_type (tree, int);
-static tree fixup_template_parm_index (tree, tree, int);
+static tree fixup_template_type_parm_type (tree, hashval_t);
+static tree fixup_template_parm_index (tree, tree, hashval_t);
 static tree tsubst_template_parm (tree, tree, tsubst_flags_t);
+static hashval_t iterative_hash_template_parms (tree, hashval_t);
+static hashval_t iterative_hash_template_parm_index_no_level (tree, hashval_t);
 
 /* Make the current scope suitable for access checking when we are
    processing T.  T can be FUNCTION_DECL for instantiated function
@@ -1648,6 +1650,62 @@ iterative_hash_template_arg (tree arg, hashval_t val)
   return 0;
 }
 
+/* Calculate a hash value for a template parameter index without
+   taking the level of the index into account.  This is a subroutine
+   of iteratite_hash_template_parms.  */
+
+static hashval_t
+iterative_hash_template_parm_index_no_level (tree index, hashval_t val)
+{
+  enum tree_code code;
+  gcc_assert (TREE_CODE (index) == TEMPLATE_PARM_INDEX);
+
+  code = TREE_CODE (TREE_TYPE (TEMPLATE_PARM_DECL (index)));
+  val = iterative_hash_object (code, val);
+  return iterative_hash_object (TEMPLATE_PARM_IDX (index), val);
+}
+
+/* Calculate a hash value for a vector of template parameters.  This
+   hash value does not consider the level of the parameters.  PARMVEC
+   is a TREE_VEC of template parameters; each parameter is a TREE_LIST
+   which TREE_VALUE contains the actual parameter.  */
+
+static hashval_t
+iterative_hash_template_parms (tree parmvec, hashval_t val)
+{
+  int i;
+
+  if (parmvec == NULL_TREE || parmvec == error_mark_node)
+    return val;
+
+  for (i = 0; i < TREE_VEC_LENGTH (parmvec); ++i)
+    {
+      tree parm_desc = TREE_VEC_ELT (parmvec, i);
+      tree parm;
+
+      if (parm_desc == error_mark_node || parm_desc == NULL_TREE)
+	continue;
+
+      gcc_assert (TREE_CODE (parm_desc) == TREE_LIST);
+
+      parm = TREE_VALUE (parm_desc);
+      if (TREE_CODE (parm) == TYPE_DECL)
+	val = iterative_hash_template_parm_index_no_level
+	  (TEMPLATE_TYPE_PARM_INDEX (TREE_TYPE (parm)), val);
+      else if (TREE_CODE (parm) == TEMPLATE_DECL)
+	val = iterative_hash_template_parms
+	  (INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (parm)), val);
+      else if (TREE_CODE (parm) == PARM_DECL)
+	val = iterative_hash_template_parm_index_no_level
+	  (DECL_INITIAL (parm), val);
+      else
+	gcc_assert (parm == error_mark_node);
+    }
+
+  return val;
+}
+
+
 /* Unregister the specialization SPEC as a specialization of TMPL.
    Replace it with NEW_SPEC, if NEW_SPEC is non-NULL.  Returns true
    if the SPEC was listed as a specialization of TMPL.
@@ -3399,14 +3457,14 @@ check_template_shadow (tree decl)
 }
 
 /* Return a new TEMPLATE_PARM_INDEX with the indicated INDEX, LEVEL,
-   ORIG_LEVEL, DECL, and TYPE.  NUM_SIBLINGS is the total number of
-   template parameters.  */
+   ORIG_LEVEL, DECL, and TYPE.  SIBLINGS_HASH is the hash of the
+   list of template parameters.  */
 
 static tree
 build_template_parm_index (int index,
 			   int level,
 			   int orig_level,
-			   int num_siblings,
+			   hashval_t siblings_hash,
 			   tree decl,
 			   tree type)
 {
@@ -3414,7 +3472,7 @@ build_template_parm_index (int index,
   TEMPLATE_PARM_IDX (t) = index;
   TEMPLATE_PARM_LEVEL (t) = level;
   TEMPLATE_PARM_ORIG_LEVEL (t) = orig_level;
-  TEMPLATE_PARM_NUM_SIBLINGS (t) = num_siblings;
+  TEMPLATE_PARM_SIBLINGS_HASH (t) = siblings_hash;
   TEMPLATE_PARM_DECL (t) = decl;
   TREE_TYPE (t) = type;
   TREE_CONSTANT (t) = TREE_CONSTANT (decl);
@@ -3480,7 +3538,7 @@ reduce_template_parm_level (tree index, tree type, int levels, tree args,
       t = build_template_parm_index (TEMPLATE_PARM_IDX (index),
 				     TEMPLATE_PARM_LEVEL (index) - levels,
 				     TEMPLATE_PARM_ORIG_LEVEL (index),
-				     TEMPLATE_PARM_NUM_SIBLINGS (index),
+				     TEMPLATE_PARM_SIBLINGS_HASH (index),
 				     decl, type);
       TEMPLATE_PARM_DESCENDANTS (index) = t;
       TEMPLATE_PARM_PARAMETER_PACK (t) 
@@ -3500,16 +3558,11 @@ reduce_template_parm_level (tree index, tree type, int levels, tree args,
    to the LIST being built.  This new parameter is a non-type
    parameter iff IS_NON_TYPE is true. This new parameter is a
    parameter pack iff IS_PARAMETER_PACK is true.  The location of PARM
-   is in PARM_LOC. NUM_TEMPLATE_PARMS is the size of the template
-   parameter list PARM belongs to. This is used used to create a
-   proper canonical type for the type of PARM that is to be created,
-   iff PARM is a type.  If the size is not known, this parameter shall
-   be set to 0.  */
+   is in PARM_LOC.  */
 
 tree
 process_template_parm (tree list, location_t parm_loc, tree parm,
-		       bool is_non_type, bool is_parameter_pack,
-		       unsigned num_template_parms)
+		       bool is_non_type, bool is_parameter_pack)
 {
   tree decl = 0;
   tree defval;
@@ -3584,7 +3637,7 @@ process_template_parm (tree list, location_t parm_loc, tree parm,
       DECL_INITIAL (parm) = DECL_INITIAL (decl)
 	= build_template_parm_index (idx, processing_template_decl,
 				     processing_template_decl,
-				     num_template_parms,
+				     /*sibling_hash=*/0,
 				     decl, TREE_TYPE (parm));
 
       TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)) 
@@ -3618,7 +3671,7 @@ process_template_parm (tree list, location_t parm_loc, tree parm,
       TEMPLATE_TYPE_PARM_INDEX (t)
 	= build_template_parm_index (idx, processing_template_decl,
 				     processing_template_decl,
-				     num_template_parms,
+				     /*sibling_hash=*/0,
 				     decl, TREE_TYPE (parm));
       TEMPLATE_TYPE_PARAMETER_PACK (t) = is_parameter_pack;
       TYPE_CANONICAL (t) = canonical_type_parameter (t);
@@ -3670,12 +3723,12 @@ end_template_parm_list (tree parms)
      3/ From now on, T is going to be what lookups referring to the
      name of TYPE will return. No lookup should return TYPE anymore.
 
-   NUM_PARMS is the new number of sibling parms TYPE belongs to.
+   SIBLING_HASH is the hash value of the sibling parms TYPE belongs to.
 
    This is a subroutine of fixup_template_parms.  */
 
 static tree
-fixup_template_type_parm_type (tree type, int num_parms)
+fixup_template_type_parm_type (tree type, hashval_t siblings_hash)
 {
   tree orig_idx = TEMPLATE_TYPE_PARM_INDEX (type), idx;
   tree t;
@@ -3685,7 +3738,7 @@ fixup_template_type_parm_type (tree type, int num_parms)
   tree decl;
 
   /* Do not fix up the type twice.  */
-  if (orig_idx && TEMPLATE_PARM_NUM_SIBLINGS (orig_idx) != 0)
+  if (orig_idx && TEMPLATE_PARM_SIBLINGS_HASH (orig_idx) != 0)
     return type;
 
   t = copy_type (type);
@@ -3699,7 +3752,7 @@ fixup_template_type_parm_type (tree type, int num_parms)
   idx = build_template_parm_index (TEMPLATE_PARM_IDX (orig_idx),
 				   TEMPLATE_PARM_LEVEL (orig_idx),
 				   TEMPLATE_PARM_ORIG_LEVEL (orig_idx),
-				   num_parms,
+				   siblings_hash,
 				   decl, t);
   TEMPLATE_PARM_DESCENDANTS (idx) = TEMPLATE_PARM_DESCENDANTS (orig_idx);
   TEMPLATE_PARM_PARAMETER_PACK (idx) = TEMPLATE_PARM_PARAMETER_PACK (orig_idx);
@@ -3723,8 +3776,8 @@ fixup_template_type_parm_type (tree type, int num_parms)
 /* Create and return a new TEMPLATE_PARM_INDEX that is almost
    identical to I, but that is fixed up as to:
 
-   1/ carry the number of sibling parms (NUM_PARMS) of the template
-   parm represented by I.
+   1/ carry the hash of the sibling parms (SIBLINGS_HASH) of the
+   template parm represented by I.
 
    2/ replace all references to template parm types declared before I
    (in the same template parm list as I) by references to template
@@ -3735,14 +3788,14 @@ fixup_template_type_parm_type (tree type, int num_parms)
    This is a subroutine of fixup_template_parms.  */
 
 static tree
-fixup_template_parm_index (tree i, tree args, int num_parms)
+fixup_template_parm_index (tree i, tree args, hashval_t siblings_hash)
 {
   tree index, decl, type;
 
   if (i == NULL_TREE
       || TREE_CODE (i) != TEMPLATE_PARM_INDEX
       /* Do not fix up the index twice.  */
-      || (TEMPLATE_PARM_NUM_SIBLINGS (i) != 0))
+      || (TEMPLATE_PARM_SIBLINGS_HASH (i) != 0))
     return i;
 
   decl = TEMPLATE_PARM_DECL (i);
@@ -3751,7 +3804,7 @@ fixup_template_parm_index (tree i, tree args, int num_parms)
   index = build_template_parm_index (TEMPLATE_PARM_IDX (i),
 				     TEMPLATE_PARM_LEVEL (i),
 				     TEMPLATE_PARM_ORIG_LEVEL (i),
-				     num_parms,
+				     siblings_hash,
 				     decl, type);
 
   TEMPLATE_PARM_DESCENDANTS (index) = TEMPLATE_PARM_DESCENDANTS (i);
@@ -3774,9 +3827,9 @@ fixup_template_parm_index (tree i, tree args, int num_parms)
    performed during the fixup. PARM_DESC is a TREE_LIST which
    TREE_VALUE is the template parameter and its TREE_PURPOSE is the
    default argument of the template parm if any. IDX is the index of
-   the template parameter, starting at 0. NUM_PARMS is the number of
-   template parameters in the set PARM_DESC belongs to. ARGLIST is a
-   TREE_VEC containing the full set of template parameters in a form
+   the template parameter, starting at 0.  SIBLINGS_HASH is the hash
+   value of the template parameters PARM_DESC belongs to.  ARGLIST is
+   a TREE_VEC containing the full set of template parameters in a form
    suitable to be passed to substs functions as their ARGS
    argument. This is what current_template_args returns for a given
    template. The innermost vector of args in ARGLIST is the set of
@@ -3786,7 +3839,7 @@ fixup_template_parm_index (tree i, tree args, int num_parms)
 static void
 fixup_template_parm (tree parm_desc,
 		     int idx,
-		     int num_parms,
+		     int siblings_hash,
 		     tree arglist)
 {
   tree parm = TREE_VALUE (parm_desc);
@@ -3802,7 +3855,7 @@ fixup_template_parm (tree parm_desc,
 	 template parms into the default argument of this
 	 parameter.  */
       tree t =
-	fixup_template_type_parm_type (TREE_TYPE (parm), num_parms);
+	fixup_template_type_parm_type (TREE_TYPE (parm), siblings_hash);
       TREE_TYPE (parm) = t;
 
       TREE_VEC_ELT (fixedup_args, idx) = template_parm_to_arg (parm_desc);
@@ -3813,6 +3866,7 @@ fixup_template_parm (tree parm_desc,
 	 be interesting.  */
       tree tparms, targs, innermost_args, t;
       int j;
+      hashval_t hash;
 
       /* First, fix up the parms of the template template parm
 	 because the parms are involved in defining the new canonical
@@ -3835,6 +3889,7 @@ fixup_template_parm (tree parm_desc,
 	 template parameters and use that as arguments for the
 	 tsubsting function.  */
       tparms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (parm));
+      hash = iterative_hash_template_parms (tparms, 0);
 
       /* This will contain the innermost parms of PARM into which
 	 we have substituted so far.  */
@@ -3856,13 +3911,12 @@ fixup_template_parm (tree parm_desc,
 	    template_parm_to_arg (parameter);
 
 	  fixup_template_parm (parameter, j,
-			       TREE_VEC_LENGTH (tparms),
-			       targs);
+			       hash, targs);
 	}
 
       /* Now fix up the type of the template template parm.  */
 
-      t = fixup_template_type_parm_type (TREE_TYPE (parm), num_parms);
+      t = fixup_template_type_parm_type (TREE_TYPE (parm), siblings_hash);
       TREE_TYPE (parm) = t;
 
       TREE_VEC_ELT (fixedup_args, idx) =
@@ -3902,7 +3956,7 @@ fixup_template_parm (tree parm_desc,
 	 fixup the type of PUSHED_DECL as well and luckily
 	 fixup_template_parm_index does it for us too.  */
       tree fixed_up_index =
-	fixup_template_parm_index (index, arglist, num_parms);
+	fixup_template_parm_index (index, arglist, siblings_hash);
 
       DECL_INITIAL (pushed_decl) = DECL_INITIAL (parm) = fixed_up_index;
 
@@ -3933,6 +3987,7 @@ fixup_template_parms (void)
   tree parameter_vec;
   tree fixedup_args;
   int i, num_parms;
+  hashval_t hash = 0;
 
   parameter_vec = INNERMOST_TEMPLATE_PARMS (current_template_parms);
   if (parameter_vec == NULL_TREE)
@@ -3951,10 +4006,13 @@ fixup_template_parms (void)
   arglist = current_template_args ();
   arglist = add_outermost_template_args (arglist, fixedup_args);
 
+  /* Calculate a hash value for PARAMETER_VEC.  */
+  hash = iterative_hash_template_parms (parameter_vec, hash);
+
   /* Let's do the proper fixup now.  */
   for (i = 0; i < num_parms; ++i)
     fixup_template_parm (TREE_VEC_ELT (parameter_vec, i),
-			 i, num_parms, arglist);
+			 i, hash, arglist);
 }
 
 /* end_template_decl is called after a template declaration is seen.  */
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 841029f..892fe02 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2308,8 +2308,8 @@ cp_tree_equal (tree t1, tree t2)
 				BASELINK_FUNCTIONS (t2)));
 
     case TEMPLATE_PARM_INDEX:
-      if (TEMPLATE_PARM_NUM_SIBLINGS (t1)
-	  != TEMPLATE_PARM_NUM_SIBLINGS (t2))
+      if (TEMPLATE_PARM_SIBLINGS_HASH (t1)
+	  != TEMPLATE_PARM_SIBLINGS_HASH (t2))
 	return false;
       return (TEMPLATE_PARM_IDX (t1) == TEMPLATE_PARM_IDX (t2)
 	      && TEMPLATE_PARM_LEVEL (t1) == TEMPLATE_PARM_LEVEL (t2)
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 722cec5..d482433 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1136,10 +1136,10 @@ comp_template_parms_position (tree t1, tree t2)
   index1 = TEMPLATE_TYPE_PARM_INDEX (TYPE_MAIN_VARIANT (t1));
   index2 = TEMPLATE_TYPE_PARM_INDEX (TYPE_MAIN_VARIANT (t2));
 
-  /* If T1 and T2 belong to template parm lists of different size,
-     let's assume they are different.  */
-  if (TEMPLATE_PARM_NUM_SIBLINGS (index1)
-      != TEMPLATE_PARM_NUM_SIBLINGS (index2))
+  /* If T1 and T2 belong to incompatible template parm lists, let's
+     assume they are different.  */
+  if (TEMPLATE_PARM_SIBLINGS_HASH (index1)
+      != TEMPLATE_PARM_SIBLINGS_HASH (index2))
     return false;
 
   /* Then compare their relative position.  */
diff --git a/gcc/testsuite/g++.dg/template/canon-type-14.C b/gcc/testsuite/g++.dg/template/canon-type-14.C
new file mode 100644
index 0000000..804fe1e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/canon-type-14.C
@@ -0,0 +1,16 @@
+// Origin PR c++/50852
+
+template<int d> class A;
+template<class T> struct B {typedef int K;typedef int L;};
+template<class U,class V> struct C
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W;
+};
+
+template<class U,int d> struct D
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W;// { dg-error "a|is not a member of|D<B<A<1> >, 3>::X" }
+};
+template class D<B<A<1> >,3>;
-- 
1.7.6.4

-- 
		Dodji

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] PR c++/50852 - loose template parameter comparison
  2011-11-17 21:56 [PATCH] PR c++/50852 - loose template parameter comparison Dodji Seketeli
@ 2012-01-17 19:03 ` Jason Merrill
  2012-01-24  9:45   ` Dodji Seketeli
  2012-04-12 21:08 ` [PATCH] PR c++/50852 - loose template parameter comparison Jason Merrill
  1 sibling, 1 reply; 18+ messages in thread
From: Jason Merrill @ 2012-01-17 19:03 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: GCC Patches

On 11/17/2011 04:21 PM, Dodji Seketeli wrote:
> +      parm = TREE_VALUE (parm_desc);
> +      if (TREE_CODE (parm) == TYPE_DECL)
> +	val = iterative_hash_template_parm_index_no_level
> +	  (TEMPLATE_TYPE_PARM_INDEX (TREE_TYPE (parm)), val);
> +      else if (TREE_CODE (parm) == TEMPLATE_DECL)
> +	val = iterative_hash_template_parms
> +	  (INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (parm)), val);
> +      else if (TREE_CODE (parm) == PARM_DECL)
> +	val = iterative_hash_template_parm_index_no_level
> +	  (DECL_INITIAL (parm), val);

It looks like type and non-type parameters will get the same hash here. 
  You also need to hash the type of a non-type parameter, so that two 
non-type parameters of different types are considered different.

And I don't see any strategy for dealing with hash collisions.

How about if we just store a pointer to the template parameter list and 
do comp_template_parms?  Since we normally use TYPE_CANONICAL to compare 
template parameters, this shouldn't be a significant bottleneck.  If 
canonical_type_parameter gets slow we can mess with hashes there instead 
of the current O(N) linked list lookup.

Jason

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] PR c++/50852 - loose template parameter comparison
  2012-01-17 19:03 ` Jason Merrill
@ 2012-01-24  9:45   ` Dodji Seketeli
  2012-01-26 21:43     ` Jason Merrill
  0 siblings, 1 reply; 18+ messages in thread
From: Dodji Seketeli @ 2012-01-24  9:45 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches

> How about if we just store a pointer to the template parameter list
> and do comp_template_parms?

I tried a variation of this approach below.  My understanding is that
comp_template_parms wouldn't work as is, at least because it can lead to
an endless recursion:

Suppose we start comparing the first template parm P of a vector V of
parameters against another template parm P'.  We compare the kind,
level and position of P and P'.  Then we move on to comparing their
siblings, via comp_template_parms.  That will, at some point compare,
P and P' again.

So I have added a new COMPARE_NO_SIBLINGS flag to the other COMPARE_*
flag that are passed as a last argument (named STRICT) to
structural_comptypes and comptypes, to prevent that endless recursion.

A drawback with this is that all the comparisons that happen from
inside structural_comptypes must take the STRICT parameter to avoid
that recursion.  This makes quite a lot of changes, even if they are
almost mechanical.  I tried to think of a better way to handle this,
but alas.

Also, it occurred that storing a pointer to the full template
parameter list was not really appropriate e.g for cases where tsubst
reduces the level of a given template parameter.  A pointer to just
the innermost vector of siblings of the template parameter was enough.
I thus extracted a comp_template_parm_levels to compare just a level
(a vector) of template parameters against another one.

As for the possible performance regression, I couldn't notice any
slowdown in in full bootstrap time, or in compiling some local
templated c++ code here.

Bootstrapped and tested on x86_64-unknown-linux-gnu against trunk.

gcc/cp/

	PR c++/50852
	* cp-tree.h (struct template_parm_index_s)<num_siblings>: Remove.
	(struct template_parm_index_s)<siblings>: New member.
	(TEMPLATE_PARM_SIBLINGS): New accessor macro.
	(process_template_parm): Change the integer num_siblings parm into
	a tree siblings parm.
	(comp_template_parms_siblings, comp_template_parm_levels)
	(comp_template_parms_real, comp_template_args_real)
	(same_type_ignoring_top_level_qualifiers_real_p): Declare new
	functions.
	(compare_trees): Declare new function.
	* pt.c (build_template_parm_index, fixup_template_type_parm_type)
	(fixup_template_parm_index, build_template_parm_index)
	(fixup_template_parm_index, process_template_parm)
	(fixup_template_type_parm_type, fixup_template_parm): Change the
	integer num_siblings parm into a tree siblings parm.  Update
	comments.
	(comp_template_parm_levels): Define new function.
	(comp_template_parms_real): Take an additional parm to control
	comparison.  Factorize this out of ...
	(comp_template_parms): ... this.
	(reduce_template_parm_level): Use TEMPLATE_PARM_SIBLINGS instead
	of TEMPLATE_PARM_NUM_SIBLINGS.
	(template_args_equal_real): Take an additional parm to control
	comparison.  Use template_args_equal_real instead of
	template_args_equal.  Factorize this out of ...
	(template_args_equal): ... this.
	(comp_template_args_real): Take an additional parm to control
	comparison.  Renamed from comp_template_args_with_info.  Make this
	public.
	(comp_template_args, unify_pack_expansion): Adjust.
	* tree.c (compare_trees): Factorized this out of cp_tree_equal.
	Take a comparison control parameter. Use tree comparison functions
	that take a comparison control parm.
	(cp_tree_equal): Use the factorized compare_trees.
	* typeck.c (compparms_real): Take a comparison control parameter.
	Split out of ...
	(compparms): ... this.
	(comp_template_parms_siblings): Define new function.
	(comp_template_parms_position): Take an additional parameter to
	control the comparison.  Use the new comp_template_parms_siblings.
	(structural_comptypes): Use type comparison routines variants that
	take the comparison control parm.
	(same_type_ignoring_top_level_qualifiers_real_p): Take an
	additional parm to control comparison.  USe comptypes instead of
	comptypes.  Factorize out of ...
	(same_type_ignoring_top_level_qualifiers_p): ... this.

gcc/testsuite/

	PR c++/50852
	* g++.dg/template/typedef39.C: New test.
	* g++.dg/template/typedef40.C: Likewise.
	* g++.dg/template/typedef41.C: Likewise.
---
 gcc/cp/cp-tree.h                          |   25 +++-
 gcc/cp/pt.c                               |  226 ++++++++++++++++++-----------
 gcc/cp/tree.c                             |  113 +++++++++------
 gcc/cp/typeck.c                           |  174 +++++++++++++++++------
 gcc/testsuite/g++.dg/template/typedef39.C |   16 ++
 gcc/testsuite/g++.dg/template/typedef40.C |   22 +++
 gcc/testsuite/g++.dg/template/typedef41.C |   19 +++
 7 files changed, 416 insertions(+), 179 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/typedef39.C
 create mode 100644 gcc/testsuite/g++.dg/template/typedef40.C
 create mode 100644 gcc/testsuite/g++.dg/template/typedef41.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ccad644..e2c36a1 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -246,7 +246,9 @@ struct GTY(()) template_parm_index_s {
   int index;
   int level;
   int orig_level;
-  int num_siblings;
+  /* A TREE_VEC containing the set of parms this parameter belongs
+     to. */
+  tree siblings;
   tree decl;
 };
 typedef struct template_parm_index_s template_parm_index;
@@ -4471,6 +4473,9 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
 				   structural. The actual comparison
 				   will be identical to
 				   COMPARE_STRICT.  */
+#define COMPARE_NO_SIBLINGS   16 /* When comparing template
+				    parameters, don't consider their
+				    siblings.  */
 
 /* Used with push_overloaded_decl.  */
 #define PUSH_GLOBAL	     0  /* Push the DECL into namespace scope,
@@ -4504,9 +4509,10 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
 	((template_parm_index*)TEMPLATE_PARM_INDEX_CHECK (NODE))
 #define TEMPLATE_PARM_IDX(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->index)
 #define TEMPLATE_PARM_LEVEL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->level)
-/* The Number of sibling parms this template parm has.  */
-#define TEMPLATE_PARM_NUM_SIBLINGS(NODE) \
-  (TEMPLATE_PARM_INDEX_CAST (NODE)->num_siblings)
+/* A TREE_VEC containing the sibling parameters for a given template
+   parm.  */
+#define TEMPLATE_PARM_SIBLINGS(NODE) \
+  (TEMPLATE_PARM_INDEX_CAST (NODE)->siblings)
 #define TEMPLATE_PARM_DESCENDANTS(NODE) (TREE_CHAIN (NODE))
 #define TEMPLATE_PARM_ORIG_LEVEL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->orig_level)
 #define TEMPLATE_PARM_DECL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->decl)
@@ -5275,7 +5281,7 @@ extern void append_type_to_template_for_access_check (tree, tree, tree,
 extern tree splice_late_return_type		(tree, tree);
 extern bool is_auto				(const_tree);
 extern tree process_template_parm		(tree, location_t, tree, 
-						 bool, bool, unsigned);
+						 bool, bool, tree);
 extern tree end_template_parm_list		(tree);
 void fixup_template_parms (void);
 extern void end_template_decl			(void);
@@ -5302,6 +5308,9 @@ extern void do_type_instantiation		(tree, tree, tsubst_flags_t);
 extern bool always_instantiate_p		(tree);
 extern void maybe_instantiate_noexcept		(tree);
 extern tree instantiate_decl			(tree, int, bool);
+extern bool comp_template_parms_siblings        (tree, tree, int);
+extern int comp_template_parm_levels            (const_tree, const_tree, int);
+extern int comp_template_parms_real		(const_tree, const_tree, int);
 extern int comp_template_parms			(const_tree, const_tree);
 extern bool uses_parameter_packs                (tree);
 extern bool template_parameter_pack_p           (const_tree);
@@ -5316,6 +5325,8 @@ extern int template_class_depth			(tree);
 extern int is_specialization_of			(tree, tree);
 extern bool is_specialization_of_friend		(tree, tree);
 extern tree get_pattern_parm			(tree, tree);
+extern int comp_template_args_real              (tree, tree, tree *,
+						 tree *, int);
 extern int comp_template_args			(tree, tree);
 extern tree maybe_process_partial_specialization (tree);
 extern tree most_specialized_instantiation	(tree);
@@ -5694,6 +5705,7 @@ extern tree lvalue_type				(tree);
 extern tree error_type				(tree);
 extern int varargs_function_p			(const_tree);
 extern bool really_overloaded_fn		(tree);
+extern bool compare_trees                       (tree, tree, int);
 extern bool cp_tree_equal			(tree, tree);
 extern tree no_linkage_check			(tree, bool);
 extern void debug_binfo				(tree);
@@ -5754,6 +5766,9 @@ extern int type_unknown_p			(const_tree);
 enum { ce_derived, ce_normal, ce_exact };
 extern bool comp_except_specs			(const_tree, const_tree, int);
 extern bool comptypes				(tree, tree, int);
+extern bool same_type_ignoring_top_level_qualifiers_real_p (tree type1,
+							    tree type2,
+							    int strict);
 extern bool same_type_ignoring_top_level_qualifiers_p (tree, tree);
 extern bool compparms				(const_tree, const_tree);
 extern int comp_cv_qualification		(const_tree, const_tree);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index a4460f1..a71b45e 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -148,7 +148,7 @@ static tree convert_template_argument (tree, tree, tree,
 static int for_each_template_parm (tree, tree_fn_t, void*,
 				   struct pointer_set_t*, bool);
 static tree expand_template_argument_pack (tree);
-static tree build_template_parm_index (int, int, int, int, tree, tree);
+static tree build_template_parm_index (int, int, int, tree, tree, tree);
 static bool inline_needs_template_parms (tree);
 static void push_inline_template_parms_recursive (tree, int);
 static tree retrieve_local_specialization (tree);
@@ -183,6 +183,7 @@ static tree try_class_unification (tree, tree, tree, tree, bool);
 static int coerce_template_template_parms (tree, tree, tsubst_flags_t,
 					   tree, tree);
 static bool template_template_parm_bindings_ok_p (tree, tree);
+static int template_args_equal_real (tree, tree, int);
 static int template_args_equal (tree, tree);
 static void tsubst_default_arguments (tree);
 static tree for_each_template_parm_r (tree *, int *, void *);
@@ -205,8 +206,8 @@ static tree listify_autos (tree, tree);
 static tree template_parm_to_arg (tree t);
 static bool arg_from_parm_pack_p (tree, tree);
 static tree current_template_args (void);
-static tree fixup_template_type_parm_type (tree, int);
-static tree fixup_template_parm_index (tree, tree, int);
+static tree fixup_template_type_parm_type (tree, tree);
+static tree fixup_template_parm_index (tree, tree, tree);
 static tree tsubst_template_parm (tree, tree, tsubst_flags_t);
 
 /* Make the current scope suitable for access checking when we are
@@ -2696,11 +2697,56 @@ check_explicit_specialization (tree declarator,
 }
 
 /* Returns 1 iff PARMS1 and PARMS2 are identical sets of template
+   parameters of a given level, represented by a TREE_VEC of
+   TREE_LIST.  The TREE_VALUE of each TREE_LIST represents a given
+   template parameter.  STRICT controls how the comparison is done.
+   It has the same meaning as the last parameter of the comptypes
+   function.  */
+
+int
+comp_template_parm_levels (const_tree parms_level1,
+			   const_tree parms_level2,
+			   int strict)
+{
+  int i;
+  gcc_assert (TREE_CODE (parms_level1) == TREE_VEC);
+  gcc_assert (TREE_CODE (parms_level2) == TREE_VEC);
+
+  if (TREE_VEC_LENGTH (parms_level1) != TREE_VEC_LENGTH (parms_level2))
+    return 0;
+
+  for (i = 0; i < TREE_VEC_LENGTH (parms_level2); ++i)
+    {
+      tree parm1 = TREE_VALUE (TREE_VEC_ELT (parms_level1, i));
+      tree parm2 = TREE_VALUE (TREE_VEC_ELT (parms_level2, i));
+
+      /* If either of the template parameters are invalid, assume
+	 they match for the sake of error recovery. */
+      if (parm1 == error_mark_node || parm2 == error_mark_node)
+	return 1;
+
+      if (TREE_CODE (parm1) != TREE_CODE (parm2))
+	return 0;
+
+      if (TREE_CODE (parm1) == TEMPLATE_TYPE_PARM
+	  && (TEMPLATE_TYPE_PARAMETER_PACK (parm1)
+	      == TEMPLATE_TYPE_PARAMETER_PACK (parm2)))
+	continue;
+      else if (!comptypes (TREE_TYPE (parm1), TREE_TYPE (parm2), strict))
+	return 0;
+    }
+  return 1;
+}
+
+/* Returns 1 iff PARMS1 and PARMS2 are identical sets of template
    parameters.  These are represented in the same format used for
-   DECL_TEMPLATE_PARMS.  */
+   DECL_TEMPLATE_PARMS.  STRICT controls how the comparison is done.
+   Its semantics are the same as the last parameter of comptypes.  */
 
 int
-comp_template_parms (const_tree parms1, const_tree parms2)
+comp_template_parms_real (const_tree parms1,
+			  const_tree parms2,
+			  int strict)
 {
   const_tree p1;
   const_tree p2;
@@ -2714,37 +2760,20 @@ comp_template_parms (const_tree parms1, const_tree parms2)
     {
       tree t1 = TREE_VALUE (p1);
       tree t2 = TREE_VALUE (p2);
-      int i;
 
-      gcc_assert (TREE_CODE (t1) == TREE_VEC);
-      gcc_assert (TREE_CODE (t2) == TREE_VEC);
-
-      if (TREE_VEC_LENGTH (t1) != TREE_VEC_LENGTH (t2))
+      if (!comp_template_parm_levels (t1, t2, strict))
 	return 0;
-
-      for (i = 0; i < TREE_VEC_LENGTH (t2); ++i)
-	{
-          tree parm1 = TREE_VALUE (TREE_VEC_ELT (t1, i));
-          tree parm2 = TREE_VALUE (TREE_VEC_ELT (t2, i));
-
-          /* If either of the template parameters are invalid, assume
-             they match for the sake of error recovery. */
-          if (parm1 == error_mark_node || parm2 == error_mark_node)
-            return 1;
-
-	  if (TREE_CODE (parm1) != TREE_CODE (parm2))
-	    return 0;
-
-	  if (TREE_CODE (parm1) == TEMPLATE_TYPE_PARM
-              && (TEMPLATE_TYPE_PARAMETER_PACK (parm1)
-                  == TEMPLATE_TYPE_PARAMETER_PACK (parm2)))
-	    continue;
-	  else if (!same_type_p (TREE_TYPE (parm1), TREE_TYPE (parm2)))
-	    return 0;
-	}
     }
 
-  if ((p1 != NULL_TREE) != (p2 != NULL_TREE))
+  /*  Don't compare depths template parms levels when we are in the
+      process of comparing siblings of a given template parm.  This is
+      because the TEMPLATE_PARM_SIBLINGS property of a template parm
+      which level has been reduced by tsubst still points to the
+      original siblings, which level is greater; while comparing those
+      siblings with another set of siblings, considering their depths
+      can lead to errors.  */
+  if (!(strict & COMPARE_NO_SIBLINGS)
+      && (p1 != NULL_TREE) != (p2 != NULL_TREE))
     /* One set of parameters has more parameters lists than the
        other.  */
     return 0;
@@ -2752,6 +2781,17 @@ comp_template_parms (const_tree parms1, const_tree parms2)
   return 1;
 }
 
+/* Returns 1 iff PARMS1 and PARMS2 are identical sets of template
+   parameters.  These are represented in the same format used for
+   DECL_TEMPLATE_PARMS.  */
+
+int
+comp_template_parms (const_tree parms1, const_tree parms2)
+{
+  return comp_template_parms_real (parms1, parms2,
+				   COMPARE_STRICT);
+}
+
 /* Determine whether PARM is a parameter pack.  */
 
 bool 
@@ -3414,14 +3454,14 @@ check_template_shadow (tree decl)
 }
 
 /* Return a new TEMPLATE_PARM_INDEX with the indicated INDEX, LEVEL,
-   ORIG_LEVEL, DECL, and TYPE.  NUM_SIBLINGS is the total number of
-   template parameters.  */
+   ORIG_LEVEL, DECL, and TYPE.  SIBLINGS is a TREE_VEC containing the
+   set of parameters the current template parameter belongs to.  */
 
 static tree
 build_template_parm_index (int index,
 			   int level,
 			   int orig_level,
-			   int num_siblings,
+			   tree siblings,
 			   tree decl,
 			   tree type)
 {
@@ -3429,7 +3469,7 @@ build_template_parm_index (int index,
   TEMPLATE_PARM_IDX (t) = index;
   TEMPLATE_PARM_LEVEL (t) = level;
   TEMPLATE_PARM_ORIG_LEVEL (t) = orig_level;
-  TEMPLATE_PARM_NUM_SIBLINGS (t) = num_siblings;
+  TEMPLATE_PARM_SIBLINGS (t) = siblings;
   TEMPLATE_PARM_DECL (t) = decl;
   TREE_TYPE (t) = type;
   TREE_CONSTANT (t) = TREE_CONSTANT (decl);
@@ -3495,7 +3535,7 @@ reduce_template_parm_level (tree index, tree type, int levels, tree args,
       t = build_template_parm_index (TEMPLATE_PARM_IDX (index),
 				     TEMPLATE_PARM_LEVEL (index) - levels,
 				     TEMPLATE_PARM_ORIG_LEVEL (index),
-				     TEMPLATE_PARM_NUM_SIBLINGS (index),
+				     TEMPLATE_PARM_SIBLINGS (index),
 				     decl, type);
       TEMPLATE_PARM_DESCENDANTS (index) = t;
       TEMPLATE_PARM_PARAMETER_PACK (t) 
@@ -3515,16 +3555,16 @@ reduce_template_parm_level (tree index, tree type, int levels, tree args,
    to the LIST being built.  This new parameter is a non-type
    parameter iff IS_NON_TYPE is true. This new parameter is a
    parameter pack iff IS_PARAMETER_PACK is true.  The location of PARM
-   is in PARM_LOC. NUM_TEMPLATE_PARMS is the size of the template
-   parameter list PARM belongs to. This is used used to create a
+   is in PARM_LOC.  SIBLING_PARMS is a TREE_VEC containing the set of
+   template parameters PARM belongs to.  This is used used to create a
    proper canonical type for the type of PARM that is to be created,
-   iff PARM is a type.  If the size is not known, this parameter shall
-   be set to 0.  */
+   iff PARM is a type.  If the set of parameters is not known, this
+   parameter shall be set to NULL_TREE.  */
 
 tree
 process_template_parm (tree list, location_t parm_loc, tree parm,
 		       bool is_non_type, bool is_parameter_pack,
-		       unsigned num_template_parms)
+		       tree sibling_parms)
 {
   tree decl = 0;
   tree defval;
@@ -3599,7 +3639,7 @@ process_template_parm (tree list, location_t parm_loc, tree parm,
       DECL_INITIAL (parm) = DECL_INITIAL (decl)
 	= build_template_parm_index (idx, processing_template_decl,
 				     processing_template_decl,
-				     num_template_parms,
+				     sibling_parms,
 				     decl, TREE_TYPE (parm));
 
       TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)) 
@@ -3633,7 +3673,7 @@ process_template_parm (tree list, location_t parm_loc, tree parm,
       TEMPLATE_TYPE_PARM_INDEX (t)
 	= build_template_parm_index (idx, processing_template_decl,
 				     processing_template_decl,
-				     num_template_parms,
+				     sibling_parms,
 				     decl, TREE_TYPE (parm));
       TEMPLATE_TYPE_PARAMETER_PACK (t) = is_parameter_pack;
       TYPE_CANONICAL (t) = canonical_type_parameter (t);
@@ -3676,21 +3716,21 @@ end_template_parm_list (tree parms)
 /* Create a new type almost identical to TYPE but which has the
    following differences:
 
-     1/ T has a new TEMPLATE_PARM_INDEX that carries the new number of
-     template sibling parameters of T.
+     1/ T has a new TEMPLATE_PARM_INDEX that carries the set of
+     sibling template parameters of T.
 
-     2/ T has a new canonical type that matches the new number
-     of sibling parms.
+     2/ T has a new canonical type that matches the set of sibling
+     parms.
 
      3/ From now on, T is going to be what lookups referring to the
-     name of TYPE will return. No lookup should return TYPE anymore.
+     name of TYPE will return.  No lookup should return TYPE anymore.
 
-   NUM_PARMS is the new number of sibling parms TYPE belongs to.
+   SIBLING_PARMS is the set of sibling parms TYPE belongs to.
 
    This is a subroutine of fixup_template_parms.  */
 
 static tree
-fixup_template_type_parm_type (tree type, int num_parms)
+fixup_template_type_parm_type (tree type, tree sibling_parms)
 {
   tree orig_idx = TEMPLATE_TYPE_PARM_INDEX (type), idx;
   tree t;
@@ -3700,7 +3740,7 @@ fixup_template_type_parm_type (tree type, int num_parms)
   tree decl;
 
   /* Do not fix up the type twice.  */
-  if (orig_idx && TEMPLATE_PARM_NUM_SIBLINGS (orig_idx) != 0)
+  if (orig_idx && TEMPLATE_PARM_SIBLINGS (orig_idx) != NULL_TREE)
     return type;
 
   t = copy_type (type);
@@ -3714,7 +3754,7 @@ fixup_template_type_parm_type (tree type, int num_parms)
   idx = build_template_parm_index (TEMPLATE_PARM_IDX (orig_idx),
 				   TEMPLATE_PARM_LEVEL (orig_idx),
 				   TEMPLATE_PARM_ORIG_LEVEL (orig_idx),
-				   num_parms,
+				   sibling_parms,
 				   decl, t);
   TEMPLATE_PARM_DESCENDANTS (idx) = TEMPLATE_PARM_DESCENDANTS (orig_idx);
   TEMPLATE_PARM_PARAMETER_PACK (idx) = TEMPLATE_PARM_PARAMETER_PACK (orig_idx);
@@ -3738,26 +3778,26 @@ fixup_template_type_parm_type (tree type, int num_parms)
 /* Create and return a new TEMPLATE_PARM_INDEX that is almost
    identical to I, but that is fixed up as to:
 
-   1/ carry the number of sibling parms (NUM_PARMS) of the template
+   1/ carry the set of sibling parms (SIBLING_PARMS) of the template
    parm represented by I.
 
    2/ replace all references to template parm types declared before I
    (in the same template parm list as I) by references to template
-   parm types contained in ARGS. ARGS should contain the list of
+   parm types contained in ARGS.  ARGS should contain the list of
    template parms that have been fixed up so far, in a form suitable
    to be passed to tsubst.
 
    This is a subroutine of fixup_template_parms.  */
 
 static tree
-fixup_template_parm_index (tree i, tree args, int num_parms)
+fixup_template_parm_index (tree i, tree args, tree sibling_parms)
 {
   tree index, decl, type;
 
   if (i == NULL_TREE
       || TREE_CODE (i) != TEMPLATE_PARM_INDEX
       /* Do not fix up the index twice.  */
-      || (TEMPLATE_PARM_NUM_SIBLINGS (i) != 0))
+      || (TEMPLATE_PARM_SIBLINGS (i) != NULL_TREE))
     return i;
 
   decl = TEMPLATE_PARM_DECL (i);
@@ -3766,7 +3806,7 @@ fixup_template_parm_index (tree i, tree args, int num_parms)
   index = build_template_parm_index (TEMPLATE_PARM_IDX (i),
 				     TEMPLATE_PARM_LEVEL (i),
 				     TEMPLATE_PARM_ORIG_LEVEL (i),
-				     num_parms,
+				     sibling_parms,
 				     decl, type);
 
   TEMPLATE_PARM_DESCENDANTS (index) = TEMPLATE_PARM_DESCENDANTS (i);
@@ -3789,8 +3829,8 @@ fixup_template_parm_index (tree i, tree args, int num_parms)
    performed during the fixup. PARM_DESC is a TREE_LIST which
    TREE_VALUE is the template parameter and its TREE_PURPOSE is the
    default argument of the template parm if any. IDX is the index of
-   the template parameter, starting at 0. NUM_PARMS is the number of
-   template parameters in the set PARM_DESC belongs to. ARGLIST is a
+   the template parameter, starting at 0. SIBLING_PARMS is the set of
+   template parameters the PARM_DESC belongs to. ARGLIST is a
    TREE_VEC containing the full set of template parameters in a form
    suitable to be passed to substs functions as their ARGS
    argument. This is what current_template_args returns for a given
@@ -3801,7 +3841,7 @@ fixup_template_parm_index (tree i, tree args, int num_parms)
 static void
 fixup_template_parm (tree parm_desc,
 		     int idx,
-		     int num_parms,
+		     tree sibling_parms,
 		     tree arglist)
 {
   tree parm = TREE_VALUE (parm_desc);
@@ -3817,7 +3857,7 @@ fixup_template_parm (tree parm_desc,
 	 template parms into the default argument of this
 	 parameter.  */
       tree t =
-	fixup_template_type_parm_type (TREE_TYPE (parm), num_parms);
+	fixup_template_type_parm_type (TREE_TYPE (parm), sibling_parms);
       TREE_TYPE (parm) = t;
 
       TREE_VEC_ELT (fixedup_args, idx) = template_parm_to_arg (parm_desc);
@@ -3871,13 +3911,12 @@ fixup_template_parm (tree parm_desc,
 	    template_parm_to_arg (parameter);
 
 	  fixup_template_parm (parameter, j,
-			       TREE_VEC_LENGTH (tparms),
-			       targs);
+			       tparms, targs);
 	}
 
       /* Now fix up the type of the template template parm.  */
 
-      t = fixup_template_type_parm_type (TREE_TYPE (parm), num_parms);
+      t = fixup_template_type_parm_type (TREE_TYPE (parm), sibling_parms);
       TREE_TYPE (parm) = t;
 
       TREE_VEC_ELT (fixedup_args, idx) =
@@ -3917,7 +3956,7 @@ fixup_template_parm (tree parm_desc,
 	 fixup the type of PUSHED_DECL as well and luckily
 	 fixup_template_parm_index does it for us too.  */
       tree fixed_up_index =
-	fixup_template_parm_index (index, arglist, num_parms);
+	fixup_template_parm_index (index, arglist, sibling_parms);
 
       DECL_INITIAL (pushed_decl) = DECL_INITIAL (parm) = fixed_up_index;
 
@@ -3969,7 +4008,7 @@ fixup_template_parms (void)
   /* Let's do the proper fixup now.  */
   for (i = 0; i < num_parms; ++i)
     fixup_template_parm (TREE_VEC_ELT (parameter_vec, i),
-			 i, num_parms, arglist);
+			 i, parameter_vec, arglist);
 }
 
 /* end_template_decl is called after a template declaration is seen.  */
@@ -6928,10 +6967,12 @@ coerce_template_parms (tree parms,
   return new_inner_args;
 }
 
-/* Returns 1 if template args OT and NT are equivalent.  */
+/* Returns 1 if template args OT and NT are equivalent.  STRICT
+   controls how the comparison is done, with the same semantics as
+   for the last parameter of comptypes.  */
 
 static int
-template_args_equal (tree ot, tree nt)
+template_args_equal_real (tree ot, tree nt, int strict)
 {
   if (nt == ot)
     return 1;
@@ -6940,13 +6981,16 @@ template_args_equal (tree ot, tree nt)
 
   if (TREE_CODE (nt) == TREE_VEC)
     /* For member templates */
-    return TREE_CODE (ot) == TREE_VEC && comp_template_args (ot, nt);
+    return (TREE_CODE (ot) == TREE_VEC
+	    && comp_template_args_real (ot, nt, NULL, NULL, strict));
   else if (PACK_EXPANSION_P (ot))
     return (PACK_EXPANSION_P (nt)
-	    && template_args_equal (PACK_EXPANSION_PATTERN (ot),
-				    PACK_EXPANSION_PATTERN (nt))
-	    && template_args_equal (PACK_EXPANSION_EXTRA_ARGS (ot),
-				    PACK_EXPANSION_EXTRA_ARGS (nt)));
+	    && template_args_equal_real (PACK_EXPANSION_PATTERN (ot),
+					 PACK_EXPANSION_PATTERN (nt),
+					 strict)
+	    && template_args_equal_real (PACK_EXPANSION_EXTRA_ARGS (ot),
+					 PACK_EXPANSION_EXTRA_ARGS (nt),
+					 strict));
   else if (ARGUMENT_PACK_P (ot))
     {
       int i, len;
@@ -6961,8 +7005,9 @@ template_args_equal (tree ot, tree nt)
       if (TREE_VEC_LENGTH (npack) != len)
 	return 0;
       for (i = 0; i < len; ++i)
-	if (!template_args_equal (TREE_VEC_ELT (opack, i),
-				  TREE_VEC_ELT (npack, i)))
+	if (!template_args_equal_real (TREE_VEC_ELT (opack, i),
+				       TREE_VEC_ELT (npack, i),
+				       strict))
 	  return 0;
       return 1;
     }
@@ -6976,23 +7021,32 @@ template_args_equal (tree ot, tree nt)
       ot = ARGUMENT_PACK_SELECT_FROM_PACK (ot);
       if (nt && TREE_CODE (nt) == ARGUMENT_PACK_SELECT)
 	nt = ARGUMENT_PACK_SELECT_FROM_PACK (nt);
-      return template_args_equal (ot, nt);
+      return template_args_equal_real (ot, nt, strict);
     }
   else if (TYPE_P (nt))
-    return TYPE_P (ot) && same_type_p (ot, nt);
+    return TYPE_P (ot) && comptypes (ot, nt, strict);
   else if (TREE_CODE (ot) == TREE_VEC || TYPE_P (ot))
     return 0;
   else
     return cp_tree_equal (ot, nt);
 }
 
+/* Returns 1 if template args OT and NT are equivalent.  */
+
+static int
+template_args_equal (tree ot, tree nt)
+{
+  return template_args_equal_real (ot, nt, COMPARE_STRICT);
+}
+
 /* Returns 1 iff the OLDARGS and NEWARGS are in fact identical sets of
    template arguments.  Returns 0 otherwise, and updates OLDARG_PTR and
    NEWARG_PTR with the offending arguments if they are non-NULL.  */
 
-static int
-comp_template_args_with_info (tree oldargs, tree newargs,
-			      tree *oldarg_ptr, tree *newarg_ptr)
+int
+comp_template_args_real (tree oldargs, tree newargs,
+			 tree *oldarg_ptr, tree *newarg_ptr,
+			 int strict)
 {
   int i;
 
@@ -7010,7 +7064,7 @@ comp_template_args_with_info (tree oldargs, tree newargs,
       tree nt = TREE_VEC_ELT (newargs, i);
       tree ot = TREE_VEC_ELT (oldargs, i);
 
-      if (! template_args_equal (ot, nt))
+      if (! template_args_equal_real (ot, nt, strict))
 	{
 	  if (oldarg_ptr != NULL)
 	    *oldarg_ptr = ot;
@@ -7028,7 +7082,8 @@ comp_template_args_with_info (tree oldargs, tree newargs,
 int
 comp_template_args (tree oldargs, tree newargs)
 {
-  return comp_template_args_with_info (oldargs, newargs, NULL, NULL);
+  return comp_template_args_real (oldargs, newargs,
+				  NULL, NULL, COMPARE_STRICT);
 }
 
 static void
@@ -16085,8 +16140,9 @@ unify_pack_expansion (tree tparms, tree targs, tree packed_parms,
 	  tree bad_old_arg = NULL_TREE, bad_new_arg = NULL_TREE;
 	  tree old_args = ARGUMENT_PACK_ARGS (old_pack);
 
-	  if (!comp_template_args_with_info (old_args, new_args,
-					     &bad_old_arg, &bad_new_arg))
+	  if (!comp_template_args_real (old_args, new_args,
+					&bad_old_arg, &bad_new_arg,
+					COMPARE_STRICT))
 	    /* Inconsistent unification of this parameter pack.  */
 	    return unify_parameter_pack_inconsistent (explain_p,
 						      bad_old_arg,
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index bf8bc05..197df7d 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2157,10 +2157,14 @@ decl_anon_ns_mem_p (const_tree decl)
 }
 
 /* Return truthvalue of whether T1 is the same tree structure as T2.
-   Return 1 if they are the same. Return 0 if they are different.  */
+   STRICT controls how the comparison is done, with the same semantics
+   as the for the last parameter of comptypes.  Please make sure that
+   any type or tree comparison function used in this function is a
+   variant that takes this STRICT parameter.  Return 1 if they are the
+   same. Return 0 if they are different.  */
 
 bool
-cp_tree_equal (tree t1, tree t2)
+compare_trees (tree t1, tree t2, int strict)
 {
   enum tree_code code1, code2;
 
@@ -2206,14 +2210,14 @@ cp_tree_equal (tree t1, tree t2)
 				     TREE_FIXED_CST (t2));
 
     case COMPLEX_CST:
-      return cp_tree_equal (TREE_REALPART (t1), TREE_REALPART (t2))
-	&& cp_tree_equal (TREE_IMAGPART (t1), TREE_IMAGPART (t2));
+      return compare_trees (TREE_REALPART (t1), TREE_REALPART (t2), strict)
+	&& compare_trees (TREE_IMAGPART (t1), TREE_IMAGPART (t2), strict);
 
     case CONSTRUCTOR:
       /* We need to do this when determining whether or not two
 	 non-type pointer to member function template arguments
 	 are the same.  */
-      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))
+      if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict)
 	  || CONSTRUCTOR_NELTS (t1) != CONSTRUCTOR_NELTS (t2))
 	return false;
       {
@@ -2222,22 +2226,22 @@ cp_tree_equal (tree t1, tree t2)
 	FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t1), i, field, value)
 	  {
 	    constructor_elt *elt2 = CONSTRUCTOR_ELT (t2, i);
-	    if (!cp_tree_equal (field, elt2->index)
-		|| !cp_tree_equal (value, elt2->value))
+	    if (!compare_trees (field, elt2->index, strict)
+		|| !compare_trees (value, elt2->value, strict))
 	      return false;
 	  }
       }
       return true;
 
     case TREE_LIST:
-      if (!cp_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2)))
+      if (!compare_trees (TREE_PURPOSE (t1), TREE_PURPOSE (t2), strict))
 	return false;
-      if (!cp_tree_equal (TREE_VALUE (t1), TREE_VALUE (t2)))
+      if (!compare_trees (TREE_VALUE (t1), TREE_VALUE (t2), strict))
 	return false;
-      return cp_tree_equal (TREE_CHAIN (t1), TREE_CHAIN (t2));
+      return compare_trees (TREE_CHAIN (t1), TREE_CHAIN (t2), strict);
 
     case SAVE_EXPR:
-      return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+      return compare_trees (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0), strict);
 
     case CALL_EXPR:
       {
@@ -2248,14 +2252,14 @@ cp_tree_equal (tree t1, tree t2)
 	tree name1 = dependent_name (CALL_EXPR_FN (t1));
 	tree name2 = dependent_name (CALL_EXPR_FN (t2));
 	if (!(name1 && name2 && name1 == name2)
-	    && !cp_tree_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2)))
+	    && !compare_trees (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2), strict))
 	  return false;
 	for (arg1 = first_call_expr_arg (t1, &iter1),
 	       arg2 = first_call_expr_arg (t2, &iter2);
 	     arg1 && arg2;
 	     arg1 = next_call_expr_arg (&iter1),
 	       arg2 = next_call_expr_arg (&iter2))
-	  if (!cp_tree_equal (arg1, arg2))
+	  if (!compare_trees (arg1, arg2, strict))
 	    return false;
 	if (arg1 || arg2)
 	  return false;
@@ -2277,28 +2281,30 @@ cp_tree_equal (tree t1, tree t2)
 	else if (TREE_CODE (o2) == VAR_DECL && DECL_NAME (o2) == NULL_TREE
 		 && !DECL_RTL_SET_P (o2))
 	  /*Nop*/;
-	else if (!cp_tree_equal (o1, o2))
+	else if (!compare_trees (o1, o2, strict))
 	  return false;
 
-	return cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
+	return compare_trees (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1),
+			      strict);
       }
 
     case WITH_CLEANUP_EXPR:
-      if (!cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)))
+      if (!compare_trees (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0), strict))
 	return false;
-      return cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t1, 1));
+      return compare_trees (TREE_OPERAND (t1, 1), TREE_OPERAND (t1, 1), strict);
 
     case COMPONENT_REF:
       if (TREE_OPERAND (t1, 1) != TREE_OPERAND (t2, 1))
 	return false;
-      return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+      return compare_trees (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0),
+			    strict);
 
     case PARM_DECL:
       /* For comparing uses of parameters in late-specified return types
 	 with an out-of-class definition of the function, but can also come
 	 up for expressions that involve 'this' in a member function
 	 template.  */
-      if (same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+      if (comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	{
 	  if (DECL_ARTIFICIAL (t1) ^ DECL_ARTIFICIAL (t2))
 	    return false;
@@ -2321,26 +2327,25 @@ cp_tree_equal (tree t1, tree t2)
       return (BASELINK_BINFO (t1) == BASELINK_BINFO (t2)
 	      && BASELINK_ACCESS_BINFO (t1) == BASELINK_ACCESS_BINFO (t2)
 	      && BASELINK_QUALIFIED_P (t1) == BASELINK_QUALIFIED_P (t2)
-	      && cp_tree_equal (BASELINK_FUNCTIONS (t1),
-				BASELINK_FUNCTIONS (t2)));
+	      && compare_trees (BASELINK_FUNCTIONS (t1),
+				BASELINK_FUNCTIONS (t2), strict));
 
     case TEMPLATE_PARM_INDEX:
-      if (TEMPLATE_PARM_NUM_SIBLINGS (t1)
-	  != TEMPLATE_PARM_NUM_SIBLINGS (t2))
+      if (!(TEMPLATE_PARM_IDX (t1) == TEMPLATE_PARM_IDX (t2)
+	    && TEMPLATE_PARM_LEVEL (t1) == TEMPLATE_PARM_LEVEL (t2)
+	    && (TEMPLATE_PARM_PARAMETER_PACK (t1)
+		== TEMPLATE_PARM_PARAMETER_PACK (t2))
+	    && comptypes (TREE_TYPE (TEMPLATE_PARM_DECL (t1)),
+			  TREE_TYPE (TEMPLATE_PARM_DECL (t2)), strict)))
 	return false;
-      return (TEMPLATE_PARM_IDX (t1) == TEMPLATE_PARM_IDX (t2)
-	      && TEMPLATE_PARM_LEVEL (t1) == TEMPLATE_PARM_LEVEL (t2)
-	      && (TEMPLATE_PARM_PARAMETER_PACK (t1)
-		  == TEMPLATE_PARM_PARAMETER_PACK (t2))
-	      && same_type_p (TREE_TYPE (TEMPLATE_PARM_DECL (t1)),
-			      TREE_TYPE (TEMPLATE_PARM_DECL (t2))));
+      return comp_template_parms_siblings (t1, t2, strict);
 
     case TEMPLATE_ID_EXPR:
       {
 	unsigned ix;
 	tree vec1, vec2;
 
-	if (!cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)))
+	if (!compare_trees (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0), strict))
 	  return false;
 	vec1 = TREE_OPERAND (t1, 1);
 	vec2 = TREE_OPERAND (t2, 1);
@@ -2352,8 +2357,9 @@ cp_tree_equal (tree t1, tree t2)
 	  return false;
 
 	for (ix = TREE_VEC_LENGTH (vec1); ix--;)
-	  if (!cp_tree_equal (TREE_VEC_ELT (vec1, ix),
-			      TREE_VEC_ELT (vec2, ix)))
+	  if (!compare_trees (TREE_VEC_ELT (vec1, ix),
+			      TREE_VEC_ELT (vec2, ix),
+			      strict))
 	    return false;
 
 	return true;
@@ -2368,16 +2374,17 @@ cp_tree_equal (tree t1, tree t2)
 	if (TREE_CODE (o1) != TREE_CODE (o2))
 	  return false;
 	if (TYPE_P (o1))
-	  return same_type_p (o1, o2);
+	  return comptypes (o1, o2, strict);
 	else
-	  return cp_tree_equal (o1, o2);
+	  return compare_trees (o1, o2, strict);
       }
 
     case MODOP_EXPR:
       {
 	tree t1_op1, t2_op1;
 
-	if (!cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)))
+	if (!compare_trees (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0),
+			    strict))
 	  return false;
 
 	t1_op1 = TREE_OPERAND (t1, 1);
@@ -2385,7 +2392,7 @@ cp_tree_equal (tree t1, tree t2)
 	if (TREE_CODE (t1_op1) != TREE_CODE (t2_op1))
 	  return false;
 
-	return cp_tree_equal (TREE_OPERAND (t1, 2), TREE_OPERAND (t2, 2));
+	return compare_trees (TREE_OPERAND (t1, 2), TREE_OPERAND (t2, 2), strict);
       }
 
     case PTRMEM_CST:
@@ -2394,18 +2401,18 @@ cp_tree_equal (tree t1, tree t2)
       if (PTRMEM_CST_MEMBER (t1) != PTRMEM_CST_MEMBER (t2))
 	return false;
 
-      return same_type_p (PTRMEM_CST_CLASS (t1), PTRMEM_CST_CLASS (t2));
+      return comptypes (PTRMEM_CST_CLASS (t1), PTRMEM_CST_CLASS (t2), strict);
 
     case OVERLOAD:
       if (OVL_FUNCTION (t1) != OVL_FUNCTION (t2))
 	return false;
-      return cp_tree_equal (OVL_CHAIN (t1), OVL_CHAIN (t2));
+      return compare_trees (OVL_CHAIN (t1), OVL_CHAIN (t2), strict);
 
     case TRAIT_EXPR:
       if (TRAIT_EXPR_KIND (t1) != TRAIT_EXPR_KIND (t2))
 	return false;
-      return same_type_p (TRAIT_EXPR_TYPE1 (t1), TRAIT_EXPR_TYPE1 (t2))
-	&& same_type_p (TRAIT_EXPR_TYPE2 (t1), TRAIT_EXPR_TYPE2 (t2));
+      return comptypes (TRAIT_EXPR_TYPE1 (t1), TRAIT_EXPR_TYPE1 (t2), strict)
+	&& comptypes (TRAIT_EXPR_TYPE2 (t1), TRAIT_EXPR_TYPE2 (t2), strict);
 
     case CAST_EXPR:
     case STATIC_CAST_EXPR:
@@ -2414,16 +2421,18 @@ cp_tree_equal (tree t1, tree t2)
     case DYNAMIC_CAST_EXPR:
     case IMPLICIT_CONV_EXPR:
     case NEW_EXPR:
-      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+      if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	return false;
       /* Now compare operands as usual.  */
       break;
 
     case DEFERRED_NOEXCEPT:
-      return (cp_tree_equal (DEFERRED_NOEXCEPT_PATTERN (t1),
-			     DEFERRED_NOEXCEPT_PATTERN (t2))
-	      && comp_template_args (DEFERRED_NOEXCEPT_ARGS (t1),
-				     DEFERRED_NOEXCEPT_ARGS (t2)));
+      return (compare_trees (DEFERRED_NOEXCEPT_PATTERN (t1),
+			     DEFERRED_NOEXCEPT_PATTERN (t2),
+			     strict)
+	      && comp_template_args_real (DEFERRED_NOEXCEPT_ARGS (t1),
+					  DEFERRED_NOEXCEPT_ARGS (t2),
+					  NULL, NULL, strict));
       break;
 
     default:
@@ -2448,14 +2457,15 @@ cp_tree_equal (tree t1, tree t2)
 	  return false;
 
 	for (i = 0; i < n; ++i)
-	  if (!cp_tree_equal (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i)))
+	  if (!compare_trees (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i),
+			      strict))
 	    return false;
 
 	return true;
       }
 
     case tcc_type:
-      return same_type_p (t1, t2);
+      return comptypes (t1, t2, strict);
     default:
       gcc_unreachable ();
     }
@@ -2463,6 +2473,15 @@ cp_tree_equal (tree t1, tree t2)
   return false;
 }
 
+/* Return truthvalue of whether T1 is the same tree structure as T2.
+   Return 1 if they are the same. Return 0 if they are different.  */
+
+bool
+cp_tree_equal (tree t1, tree t2)
+{
+  return compare_trees (t1, t2, COMPARE_STRICT);
+}
+
 /* The type of ARG when used as an lvalue.  */
 
 tree
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 91e7a0a..781683f 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -53,6 +53,7 @@ static tree rationalize_conditional_expr (enum tree_code, tree,
 static int comp_ptr_ttypes_real (tree, tree, int);
 static bool comp_except_types (tree, tree, bool);
 static bool comp_array_types (const_tree, const_tree, bool);
+static bool compparms_real (const_tree, const_tree, int);
 static tree pointer_diff (tree, tree, tree);
 static tree get_delta_difference (tree, tree, bool, bool, tsubst_flags_t);
 static void casts_away_constness_r (tree *, tree *);
@@ -1119,13 +1120,56 @@ comp_array_types (const_tree t1, const_tree t2, bool allow_redeclaration)
   return true;
 }
 
+/* Return true iff the two instances of TEMPLATE_PARM_INDEX are
+   equivalent.  STRICT controls how the comparison is done, with the
+   same semantics as the last parameter of comptypes.  */
+
+bool
+comp_template_parms_siblings (tree index1,
+			      tree index2,
+			      int strict)
+{
+  tree siblings1, siblings2;
+
+  gcc_assert (index1 != NULL_TREE 
+	      && index2 != NULL_TREE
+	      && TREE_CODE (index1) == TREE_CODE (index2)
+	      && TREE_CODE (index1) == TEMPLATE_PARM_INDEX);
+
+  if (strict & COMPARE_NO_SIBLINGS)
+    return true;
+
+  siblings1 = TEMPLATE_PARM_SIBLINGS (index1);
+  siblings2 = TEMPLATE_PARM_SIBLINGS (index2);
+    
+  if (siblings1 == siblings2)
+    return true;
+
+  /* If T1 and T2 belong to different template parm lists let's assume
+     they are different.  */
+
+  if ((siblings1 != NULL_TREE) != (siblings2 != NULL_TREE))
+    return false;
+
+  if (TREE_VEC_LENGTH (siblings1) != TREE_VEC_LENGTH (siblings2))
+    return false;
+
+  if (!comp_template_parm_levels (siblings1, siblings2,
+				  strict | COMPARE_NO_SIBLINGS))
+    return false;
+
+  return true;
+}
+
 /* Compare the relative position of T1 and T2 into their respective
    template parameter list.
-   T1 and T2 must be template parameter types.
+   T1 and T2 must be template parameter types.  STRICT controls how
+   the comparison is done, with the same semantics as the for the last
+   parameter of comptypes.
    Return TRUE if T1 and T2 have the same position, FALSE otherwise.  */
 
 static bool
-comp_template_parms_position (tree t1, tree t2)
+comp_template_parms_position (tree t1, tree t2, int strict)
 {
   tree index1, index2;
   gcc_assert (t1 && t2
@@ -1137,19 +1181,26 @@ comp_template_parms_position (tree t1, tree t2)
   index1 = TEMPLATE_TYPE_PARM_INDEX (TYPE_MAIN_VARIANT (t1));
   index2 = TEMPLATE_TYPE_PARM_INDEX (TYPE_MAIN_VARIANT (t2));
 
-  /* If T1 and T2 belong to template parm lists of different size,
-     let's assume they are different.  */
-  if (TEMPLATE_PARM_NUM_SIBLINGS (index1)
-      != TEMPLATE_PARM_NUM_SIBLINGS (index2))
-    return false;
-
-  /* Then compare their relative position.  */
+  /* Compare their relative position.  */
   if (TEMPLATE_PARM_IDX (index1) != TEMPLATE_PARM_IDX (index2)
-      || TEMPLATE_PARM_LEVEL (index1) != TEMPLATE_PARM_LEVEL (index2)
       || (TEMPLATE_PARM_PARAMETER_PACK (index1)
 	  != TEMPLATE_PARM_PARAMETER_PACK (index2)))
     return false;
 
+  /* Don't compare levels of parms when we are in the process of
+     comparing siblings of a given template parm.  This is because the
+     TEMPLATE_PARM_SIBLINGS property of a template parm which level
+     has been reduced by tsubst still points to the original siblings,
+     which level is greater; while comparing those siblings with
+     another set of siblings, considering their levels can lead to
+     errors. */
+  if (!(strict & COMPARE_NO_SIBLINGS)
+      && (TEMPLATE_PARM_LEVEL (index1) != TEMPLATE_PARM_LEVEL (index2)))
+    return false;
+
+  if (!comp_template_parms_siblings (index1, index2, strict))
+    return false;
+
   return true;
 }
 
@@ -1233,11 +1284,12 @@ structural_comptypes (tree t1, tree t2, int strict)
 
     case TEMPLATE_TEMPLATE_PARM:
     case BOUND_TEMPLATE_TEMPLATE_PARM:
-      if (!comp_template_parms_position (t1, t2))
+      if (!comp_template_parms_position (t1, t2, strict))
 	return false;
-      if (!comp_template_parms
+      if (!comp_template_parms_real
 	  (DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t1)),
-	   DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t2))))
+	   DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t2)),
+	   strict))
 	return false;
       if (TREE_CODE (t1) == TEMPLATE_TEMPLATE_PARM)
 	break;
@@ -1250,7 +1302,9 @@ structural_comptypes (tree t1, tree t2, int strict)
       if (TYPE_TEMPLATE_INFO (t1) && TYPE_TEMPLATE_INFO (t2)
 	  && (TYPE_TI_TEMPLATE (t1) == TYPE_TI_TEMPLATE (t2)
 	      || TREE_CODE (t1) == BOUND_TEMPLATE_TEMPLATE_PARM)
-	  && comp_template_args (TYPE_TI_ARGS (t1), TYPE_TI_ARGS (t2)))
+	  && comp_template_args_real (TYPE_TI_ARGS (t1),
+				      TYPE_TI_ARGS (t2),
+				      NULL, NULL, strict))
 	break;
 
       if ((strict & COMPARE_BASE) && DERIVED_FROM_P (t1, t2))
@@ -1264,7 +1318,7 @@ structural_comptypes (tree t1, tree t2, int strict)
       if (!comptypes (TYPE_OFFSET_BASETYPE (t1), TYPE_OFFSET_BASETYPE (t2),
 		      strict & ~COMPARE_REDECLARATION))
 	return false;
-      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+      if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	return false;
       break;
 
@@ -1276,15 +1330,17 @@ structural_comptypes (tree t1, tree t2, int strict)
     case POINTER_TYPE:
       if (TYPE_MODE (t1) != TYPE_MODE (t2)
 	  || TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2)
-	  || !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+	  || !comptypes (TREE_TYPE (t1), TREE_TYPE (t2),
+			 strict & ~COMPARE_REDECLARATION))
 	return false;
       break;
 
     case METHOD_TYPE:
     case FUNCTION_TYPE:
-      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+      if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	return false;
-      if (!compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2)))
+      if (!compparms_real (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2),
+			   strict))
 	return false;
       break;
 
@@ -1297,43 +1353,48 @@ structural_comptypes (tree t1, tree t2, int strict)
     case TEMPLATE_TYPE_PARM:
       /* If T1 and T2 don't have the same relative position in their
 	 template parameters set, they can't be equal.  */
-      if (!comp_template_parms_position (t1, t2))
+      if (!comp_template_parms_position (t1, t2, strict))
 	return false;
       break;
 
     case TYPENAME_TYPE:
-      if (!cp_tree_equal (TYPENAME_TYPE_FULLNAME (t1),
-			  TYPENAME_TYPE_FULLNAME (t2)))
+      if (!compare_trees (TYPENAME_TYPE_FULLNAME (t1),
+			  TYPENAME_TYPE_FULLNAME (t2),
+			  strict))
 	return false;
       /* Qualifiers don't matter on scopes.  */
-      if (!same_type_ignoring_top_level_qualifiers_p (TYPE_CONTEXT (t1),
-						      TYPE_CONTEXT (t2)))
+      if (!same_type_ignoring_top_level_qualifiers_real_p (TYPE_CONTEXT (t1),
+							   TYPE_CONTEXT (t2),
+							   strict))
 	return false;
       break;
 
     case UNBOUND_CLASS_TEMPLATE:
-      if (!cp_tree_equal (TYPE_IDENTIFIER (t1), TYPE_IDENTIFIER (t2)))
+      if (!compare_trees (TYPE_IDENTIFIER (t1), TYPE_IDENTIFIER (t2),
+			  strict))
 	return false;
-      if (!same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2)))
+      if (!comptypes (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2), strict))
 	return false;
       break;
 
     case COMPLEX_TYPE:
-      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+      if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	return false;
       break;
 
     case VECTOR_TYPE:
       if (TYPE_VECTOR_SUBPARTS (t1) != TYPE_VECTOR_SUBPARTS (t2)
-	  || !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+	  || !comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	return false;
       break;
 
     case TYPE_PACK_EXPANSION:
-      return (same_type_p (PACK_EXPANSION_PATTERN (t1),
-			   PACK_EXPANSION_PATTERN (t2))
-	      && comp_template_args (PACK_EXPANSION_EXTRA_ARGS (t1),
-				     PACK_EXPANSION_EXTRA_ARGS (t2)));
+	return (comptypes (PACK_EXPANSION_PATTERN (t1), 
+			   PACK_EXPANSION_PATTERN (t2),
+			   strict)
+		&& comp_template_args_real (PACK_EXPANSION_EXTRA_ARGS (t1),
+					    PACK_EXPANSION_EXTRA_ARGS (t2),
+					    NULL, NULL, strict));
 
     case DECLTYPE_TYPE:
       if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t1)
@@ -1342,14 +1403,16 @@ structural_comptypes (tree t1, tree t2, int strict)
 	      != DECLTYPE_FOR_LAMBDA_CAPTURE (t2))
 	  || (DECLTYPE_FOR_LAMBDA_PROXY (t1)
 	      != DECLTYPE_FOR_LAMBDA_PROXY (t2))
-          || !cp_tree_equal (DECLTYPE_TYPE_EXPR (t1), 
-                             DECLTYPE_TYPE_EXPR (t2)))
+          || !compare_trees (DECLTYPE_TYPE_EXPR (t1), 
+                             DECLTYPE_TYPE_EXPR (t2),
+			     strict))
         return false;
       break;
 
     case UNDERLYING_TYPE:
-      return same_type_p (UNDERLYING_TYPE_TYPE (t1), 
-			  UNDERLYING_TYPE_TYPE (t2));
+      return comptypes (UNDERLYING_TYPE_TYPE (t1), 
+			UNDERLYING_TYPE_TYPE (t2),
+			strict);
 
     default:
       return false;
@@ -1416,15 +1479,31 @@ comptypes (tree t1, tree t2, int strict)
 }
 
 /* Returns nonzero iff TYPE1 and TYPE2 are the same type, ignoring
-   top-level qualifiers.  */
+   top-level qualifiers.  STRICT controls how the type comparison is
+   done, with the same semantics as for the last parameter of
+   comptypes.  */
 
 bool
-same_type_ignoring_top_level_qualifiers_p (tree type1, tree type2)
+same_type_ignoring_top_level_qualifiers_real_p (tree type1,
+						tree type2,
+						int strict)
 {
   if (type1 == error_mark_node || type2 == error_mark_node)
     return false;
 
-  return same_type_p (TYPE_MAIN_VARIANT (type1), TYPE_MAIN_VARIANT (type2));
+  return comptypes (TYPE_MAIN_VARIANT (type1),
+		    TYPE_MAIN_VARIANT (type2),
+		    strict);
+}
+
+/* Returns nonzero iff TYPE1 and TYPE2 are the same type, ignoring
+   top-level qualifiers.  */
+
+bool
+same_type_ignoring_top_level_qualifiers_p (tree type1, tree type2)
+{
+  return same_type_ignoring_top_level_qualifiers_real_p (type1, type2,
+							 COMPARE_STRICT);
 }
 
 /* Returns 1 if TYPE1 is at least as qualified as TYPE2.  */
@@ -1479,10 +1558,10 @@ comp_cv_qual_signature (tree type1, tree type2)
 /* Return true if two parameter type lists PARMS1 and PARMS2 are
    equivalent in the sense that functions with those parameter types
    can have equivalent types.  The two lists must be equivalent,
-   element by element.  */
+   element by element.  STRICT controls how the comparison is done.  */
 
-bool
-compparms (const_tree parms1, const_tree parms2)
+static bool
+compparms_real (const_tree parms1, const_tree parms2, int strict)
 {
   const_tree t1, t2;
 
@@ -1497,12 +1576,23 @@ compparms (const_tree parms1, const_tree parms2)
 	 they fail to match.  */
       if (!t1 || !t2)
 	return false;
-      if (!same_type_p (TREE_VALUE (t1), TREE_VALUE (t2)))
+      if (!comptypes (TREE_VALUE (t1), TREE_VALUE (t2), strict))
 	return false;
     }
   return true;
 }
 
+/* Return true if two parameter type lists PARMS1 and PARMS2 are
+   equivalent in the sense that functions with those parameter types
+   can have equivalent types.  The two lists must be equivalent,
+   element by element.  */
+
+bool
+compparms (const_tree parms1, const_tree parms2)
+{
+  return compparms_real (parms1, parms2, COMPARE_STRICT);
+}
+
 \f
 /* Process a sizeof or alignof expression where the operand is a
    type.  */
diff --git a/gcc/testsuite/g++.dg/template/typedef39.C b/gcc/testsuite/g++.dg/template/typedef39.C
new file mode 100644
index 0000000..4ee23a6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef39.C
@@ -0,0 +1,16 @@
+// Origin PR c++/50852
+// { dg-do compile }
+
+template<int d> class A;
+template<class T> struct B {typedef int K;typedef int L;};
+template<class U,class V> struct C
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W;
+};
+template<class U,int d> struct D
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W; // { dg-error "not a member" }
+};
+template class D<B<A<1> >,3>;
diff --git a/gcc/testsuite/g++.dg/template/typedef40.C b/gcc/testsuite/g++.dg/template/typedef40.C
new file mode 100644
index 0000000..6cd9766
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef40.C
@@ -0,0 +1,22 @@
+// Origin PR c++/50852
+// { dg-do compile }
+
+template<int d> class A;
+
+template<class T> struct B {typedef int K;typedef int L;};
+template<class U, void(*)(U&), class V> struct C
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W;
+};
+template<class U, void(*)(U&), int d> struct D
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W; // { dg-error "not a member" }
+};
+
+struct S;
+
+void f(B<A<1> >&);
+
+template class D<B<A<1> >, &f, 3>;
diff --git a/gcc/testsuite/g++.dg/template/typedef41.C b/gcc/testsuite/g++.dg/template/typedef41.C
new file mode 100644
index 0000000..17d2feb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef41.C
@@ -0,0 +1,19 @@
+// Origin PR c++/50852
+// { dg-do compile }
+
+template<int d> class A;
+
+template<class T> struct B {typedef int K;typedef int L;};
+template<class U, typename U::K, class V> struct C
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W;
+};
+template<class U, typename U::K, int d> struct D
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W; // { dg-error "not a member" }
+};
+
+
+template class D<B<A<1> >, 0, 3>;
-- 
1.7.6.5


-- 
		Dodji

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] PR c++/50852 - loose template parameter comparison
  2012-01-24  9:45   ` Dodji Seketeli
@ 2012-01-26 21:43     ` Jason Merrill
  2012-01-26 22:16       ` Dodji Seketeli
  2012-03-08 13:22       ` [PATCH] PR c++/50852 - Revisit dependant template parameter Dodji Seketeli
  0 siblings, 2 replies; 18+ messages in thread
From: Jason Merrill @ 2012-01-26 21:43 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: GCC Patches

Hmm...what if rather than trying to ignore levels when comparing, we 
make it so the sibling list always has level 1?

BTW, let's avoid calling a function named *_real directly from client code.

Jason

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] PR c++/50852 - loose template parameter comparison
  2012-01-26 21:43     ` Jason Merrill
@ 2012-01-26 22:16       ` Dodji Seketeli
  2012-01-26 22:52         ` Jason Merrill
  2012-03-08 13:22       ` [PATCH] PR c++/50852 - Revisit dependant template parameter Dodji Seketeli
  1 sibling, 1 reply; 18+ messages in thread
From: Dodji Seketeli @ 2012-01-26 22:16 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches

Jason Merrill <jason@redhat.com> writes:

> Hmm...what if rather than trying to ignore levels when comparing, we
> make it so the sibling list always has level 1?

I am not sure to understand how you'd do that.  You mean that instead of
pointing to the actual vector of innermost template parms,
TEMPLATE_PARM_SIBLINGS would instead point to a vector that is a copy of
the innermost template parms into which we'd have substituted and index
of level 1 for the index of each parm?

> BTW, let's avoid calling a function named *_real directly from client
> code.

Ah, oops sorry. I thought it would be OK as cp-tree.h already has a few
spots of public entry points "overloaded" using that _real suffix.  What
suffix would be best?

-- 
		Dodji

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] PR c++/50852 - loose template parameter comparison
  2012-01-26 22:16       ` Dodji Seketeli
@ 2012-01-26 22:52         ` Jason Merrill
  0 siblings, 0 replies; 18+ messages in thread
From: Jason Merrill @ 2012-01-26 22:52 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: GCC Patches

On 01/26/2012 05:15 PM, Dodji Seketeli wrote:
> Jason Merrill<jason@redhat.com>  writes:
>
>> Hmm...what if rather than trying to ignore levels when comparing, we
>> make it so the sibling list always has level 1?
>
> I am not sure to understand how you'd do that.  You mean that instead of
> pointing to the actual vector of innermost template parms,
> TEMPLATE_PARM_SIBLINGS would instead point to a vector that is a copy of
> the innermost template parms into which we'd have substituted and index
> of level 1 for the index of each parm?

Yes, that's what I was thinking.  Only if they aren't already level 1, 
of course.

>> BTW, let's avoid calling a function named *_real directly from client
>> code.
>
> Ah, oops sorry. I thought it would be OK as cp-tree.h already has a few
> spots of public entry points "overloaded" using that _real suffix.  What
> suffix would be best?

Something that expresses the actual nature of the extra parameter.  The 
problem with _real functions is that often you want to add another 
parameter later, and then what do you call it? :)

Jason

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] PR c++/50852 - Revisit dependant template parameter
  2012-01-26 21:43     ` Jason Merrill
  2012-01-26 22:16       ` Dodji Seketeli
@ 2012-03-08 13:22       ` Dodji Seketeli
  2012-03-08 20:17         ` Jason Merrill
  2012-03-13 21:33         ` Jason Merrill
  1 sibling, 2 replies; 18+ messages in thread
From: Dodji Seketeli @ 2012-03-08 13:22 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches

Hello,

After we discussed a little bit offline about this, I went forward
and updated the patch.

Just to recap, the idea of the patch is to make each
TEMPLATE_TYPE_INDEX have a pointer to the siblings of its level and
consider those siblings during dependant type comparison.

This has 2 main implications.

1/ When comparing siblings of a given template parameter type, we
must avoid recurring into comparing those siblings again, by fear of
and endless recursion.

2/ We must pay some attention in the context of partial instantiation
of member templates.  For instance:

    template<class T> // The level of T here is 1.
    struct S
    {
      template<class U>  struct M {}; //The level of U here is 2.
    };

If we look at S<int>::M, we are partially instantiating M with the set
of arguments {int} (of depth 1) when M would need a set of argument of
depth 2 to be fully instantiated.  In that context, the level of
template<class U> S<int>::M<U> is no more 2, but rather 1.  We say
that U has been level-reduced.

When a template parameter type T is level-reduced to a type Tr, the
siblings pointed to by the TEMPLATE_TYPE_INDEX of Tr needs to be
updated to the new siblings parameters, and Tr needs to fixed-up to
compute its new canonical type.

Point 1/ was already addressed in the previous iteration of this
patch.  This patch amended it to avoid using *_real function names in
the public API.

Point 2/ is mostly what this patch is about and during that journey, I
came across a number of roadblocks that I think are worth presenting
in English in order to share a high level understanding of what the
patch does.

[Fix-up level-reduced parms in template header *and* in its body]

A main difference between fixing up types during the initial parsing
and after level-reduction is that in the later case, we need to update
references to the pre-fix-up type in the pattern of the template so
that they point to the fixed-up type.

To be able to do this, the plan I came up with is:

    2.1/ Make tsubst_template_parms fix up the template parm types that
    have been level reduced.  This amounts to doing the fix-up in the
    template header.

    2.2/ In tsubst_decl, for TEMPLATE_DECL, (this is a context that
    can trigger partial instantiation of a member template) call
    tsubst_template_parms upfront; that is, before anything else.  At
    this point, the level-reduced parm types are fixed-up in the
    template header.

    2.3/ Then I tried to arrange for this: if we ever fix up a
    template parm type T that is the result of level-reducing a parm
    type T_ORIG to level L, any subsequent attempt to level-reduce
    T_ORIG to level L should yield T, thus doing away with the need of
    fixing up the result of subsequent level-reducing T_ORIG to level
    L.

    This appeared to be enough to propagate the fixed-up level-reduced
    type (that got fixed-up in template headers in 2.2) into the
    pattern of a the template - using tsubsting that triggers
    level-reducing there.

    This takes changing the format of TEMPLATE_PARM_DESCENDANTS of the
    T_ORIG to make it roughly contain a TREE_VEC in which each index
    is a level an the element is the fixed-up type (rather, the
    fixed-up TEMPLATE_PARM_INDEX) for that level.  I had to adapt that
    a little bit to introduce a concept similar to canonical types for
    TEMPLATE_PARM_INDEXes; it is useful because it appeared that
    several different pointers to TEMPLATE_PARM_INDEXes can require to
    be considered equivalent.

    2.4/ Do 2.2 in contexts (other than tsubst_decl) that can trigger
    partial instantiation of member templates.  That is, in
    instantiate_class_template_1, tsubst_aggr_type and tsubst (for the
    UNBOUND_CLASS_TEMPLATE case).


[Make friend TYPENAME_TYPE nodes carry a TEMPLATE_DECL when necessary]

It appeared that I couldn't get a handle on the list of template
parameters used in friend declarations like this one:

    template<class T> 
    struct S0
    {
      struct F {};
    };

    template<class T>
    struct S1
    {
      template<class U> friend SO<U>::F; //#1
    };

During partial instantiation of the declaration #1, there was no way I
could access the TEMPLATE_DECL for the TYPENAME_TYPE SO<U>::F because
it is just not created; so I couldn't get the parms of that
TEMPLATE_DECL either, and I couldn't in turn fix up the U in S0<U>.

So I changed the parser to create a TEMPLATE_DECL node in this case.

[Handle fix-up for level-reduced a template parameter pack]

This one confused me quite a little bit.

Consider the test gcc/testsuite/g++.dg/cpp0x/variadic120.C:

    template <class... T> struct tuple;
    template <class T> struct tuple<T> { T t; };

    template <class T, class U> struct pair;
    template<> struct pair<int,double> { };

    template <class... Ts>
    struct A
    {
      template <class... Us,
		class V = tuple<pair<Ts,Us>...> >
      static void f()
      {
	V v;
      }
    };

    int main()
    {
      A<int>::f<double>();
    }

In the partial instantiation of the member template A<int>::f, the
level of the parameter pack Us is NOT reduced, even if it ought to be
considered as morally reduced.  What happens instead is that the pack
expansion tuple<pair<Ts,Us>... remembers the argument list {int},
without changing the level of Us.  Later, when we consider
A<int>::f<double>, the pack expansion has enough arguments ({int,
double}) to be properly instantiated.

This is all fine but it caused me some headaches in
tsubst_pack_expansion.

Let's call Us' the morally reduced version of Us.  Us' and Us look
exactly the same, even though they belong to different template
levels.  To tell them apart one needs to look at the pack expansion
they are part of, to see if it is remembering a set of arguments or
not; like the way tuple<pair<Ts,Us>... remembers {int} above, during
the partial instantiation of template f.

So let's say we fix up Us'.  In the process of that fix-up,
arg_from_parm_pack_p cannot detect that the pre-fix-up Us' is
equivalent to the post-fix-up Us'. It can't even make the difference
between Us and Us'.  So tsubst_pack_expansion would yield a bogus
results on that pack expansion, and that bogus result will go
unnoticed until very late in the deduction process leading to issues
which root cause is hard top spot - at least for me.

So I came up with a new function
arg_from_reduced_and_fixedup_parm_pack_of_expansion_p that takes the
pack expansion in consideration when comparing pre-fix-up Us' and
post-fix-up Us'.  It is not perfect as it only look if the levels and
tree code match.  I believe that to make it perfect, I would need to
add a pointer to TEMPLATE_PARM_INDEX to track the pre-fix-up type it
was built from; this pointer would be updated by the fix-up code.  The
problem is that it would increase the size of TEMPLATE_PARM_INDEX even
more.  So I welcome your input.

[Fix partial instantiation in get_mostly_instantiated_function_type]

In this function, it appeared that we were triggering something like a
partial instantiation but not quite; the substituting was being done
with a full set of N arguments which last P elements were put to
NULL_TREE (instead of having a set N-P arguments) tsubst was
triggering a level-reduction of some template parameters, the
level-reduced parms would have a level of zero.  Which violates the
constraint that levels should be at least 1.  The patch fixes that.

Bootstrapped and tested on x86_64-unknown-linux-gnu against trunk.

gcc/cp/

	PR c++/50852
	* cp-tree.h (struct template_parm_index_s)<num_siblings,orig_level>: Remove.
	(struct template_parm_index_s)<siblings, orig_index>: New members.
	(COMPARE_NO_SIBLINGS): New type comparison control flag.
	(TEMPLATE_PARM_SIBLINGS): New accessor macro.
	(TEMPLATE_PARM_DESCENDANTS): Add comments.
	(TEMPLATE_PARM_ORIG_INDEX): New accessor.
	(TEMPLATE_PARM_ORIG_LEVEL): Rewrite in terms of
	TEMPLATE_PARM_ORIG_INDEX.
	(process_template_parm): Change the integer num_siblings parm into
	a tree siblings parm.
	(comp_template_parms_siblings, comp_template_parm_levels)
	(comp_template_parms_guided, comp_template_args_guided)
	(same_type_ignoring_top_level_qualifiers_guided_p, compare_trees)
	(template_type_parameter_type_p): Declare new functions.
	(fixup_current_template_parms): New, better name for
	fixup_template_parms.
	(fixup_template_parms): Take the set of parameters to fixup in
	parameters.
	* pt.c (arg_from_reduced_and_fixedup_parm_pack_of_expansion_p)
	(get_root_index_same_level)
	(get_template_parameter_level_and_index)
	(add_descendant_to_parm_index, get_descendant_of_parm_index)
	(get_template_parm_index, comp_template_parm_levels)
	(template_parms_to_args, template_type_parameter_type_p): Define
	new functions.
	(current_template_args): Use the new template_parms_to_args
	function.
	(fixup_template_type_parm_type)
	(fixup_template_parm_index, build_template_parm_index)
	(fixup_template_parm_index, process_template_parm)
	(fixup_template_type_parm_type, fixup_template_parm)
	(process_template_parm): Change the integer num_siblings parm into
	a tree siblings parm.  Update comments.
	(build_template_parm_index): Likewise.  Replace ORIG_LEVEL integer
	parm with an ORIG_INDEX tree.  Add a few asserts.
	(get_template_info): Make this more robust and support getting
	template info from TYPENAME_TYPE nodes.
	(comp_template_parms_guided): New function.  Takes an additional
	parm to control comparison.  Factorized out of ...
	(comp_template_parms): ... this.
	(reduce_template_parm_level): Use TEMPLATE_PARM_SIBLINGS instead
	of TEMPLATE_PARM_NUM_SIBLINGS.  Update usage of
	TEMPLATE_PARM_DESCENDANTS.  Use the new
	get_descendant_of_parm_index.
	(template_args_equal_guided): Take an additional parm to control
	comparison.  Use template_args_equal_guided instead of
	template_args_equal.  Factorize this out of ...
	(template_args_equal): ... this.
	(comp_template_args_guided): Take an additional parm to control
	comparison.  Renamed from comp_template_args_with_info.  Make this
	public.
	(comp_template_args, unify_pack_expansion): Adjust.
	(fixup_innermost_template_parms): Transformed former
	fixup_template_parms in to this.  Make it take a set of parms to
	fixup and an arglist.  Update comments.
	(fixup_template_parms): Take the parms to fixup in argument.
	(fixup_current_template_parms): This is the new name for the
	former fixup_template_parms.  It has be re-written in terms of
	fixup_innermost_template_parms.
	* tree.c (compare_trees): Factorized this out of cp_tree_equal.
	Take a comparison control parameter. Use tree comparison functions
	that take a comparison control parm.
	(cp_tree_equal): Use the factorized compare_trees.
	(tsubst_template_parms):  Fixup template parameters that are
	level-reduced.
	(push_template_decl_real): Support declarations of friend template
	represented by TYPENAME_TYPE nodes.
	(instantiate_class_template_1, tsubst_aggr_type, tsubst_decl)
	(tsubst<UNBOUND_CLASS_TEMPLATE>): Call tsubst_template_parms
	upfront to fixup dependant types that are to be level-reduced by a
	possible partial instantiation of a member template.
	(tsubst_pack_expansion): During type fixup, take in account parm
	packs that have been level-reduced.
	(get_mostly_instantiated_function_type): Fix this by setting the
	proper size for the args of tsubst, so that partial instantiation
	happens there.  Otherwise, tsubst indirectly and wrongly calls
	reduce_template_parm_level with a reduced level of 0.
	(make_auto): Adjust for sibling_parms instead of
	num_sibling_parms.
	* typeck.c (compparms_guided): Take a comparison control parameter.
	Split out of ...
	(compparms): ... this.
	(comp_template_parms_siblings): Define new function.
	(comp_template_parms_position): Take an additional parameter to
	control the comparison.  Use the new comp_template_parms_siblings.
	(structural_comptypes): Use type comparison routines variants that
	take the comparison control parm.
	(same_type_ignoring_top_level_qualifiers_guided_p): Take an
	additional parm to control comparison.  Use comptypes instead of
	comptypes.  Factorize out of ...
	(same_type_ignoring_top_level_qualifiers_p): ... this.
	* parser.c (cp_parser_template_parameter_list): Adjust for the
	change to using sibling_parms instead of num_sibling_parms.
	(cp_parser_template_declaration_after_export): Adjust
	to call fixup_current_template_parms instead of
	fixup_template_parms.
	(cp_parser_single_declaration):  Make friend typename declarations
	carry a template info.

gcc/testsuite/

	PR c++/50852
	* g++.dg/template/typedef39.C: New test.
	* g++.dg/template/typedef40.C: Likewise.
	* g++.dg/template/typedef41.C: Likewise.
	* g++.dg/template/crash84.C: This test should actually pass
	without error.
---
 gcc/cp/cp-tree.h                          |   94 +++-
 gcc/cp/parser.c                           |   21 +-
 gcc/cp/pt.c                               |  973 +++++++++++++++++++++++------
 gcc/cp/tree.c                             |  115 ++--
 gcc/cp/typeck.c                           |  162 ++++--
 gcc/testsuite/g++.dg/template/crash84.C   |    8 +-
 gcc/testsuite/g++.dg/template/typedef39.C |   16 +
 gcc/testsuite/g++.dg/template/typedef40.C |   22 +
 gcc/testsuite/g++.dg/template/typedef41.C |   19 +
 9 files changed, 1134 insertions(+), 296 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/typedef39.C
 create mode 100644 gcc/testsuite/g++.dg/template/typedef40.C
 create mode 100644 gcc/testsuite/g++.dg/template/typedef41.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 71573ff..4e4aaec 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -247,8 +247,12 @@ struct GTY(()) template_parm_index_s {
   struct tree_common common;
   int index;
   int level;
-  int orig_level;
-  int num_siblings;
+  /* If the current index was reduced from an original index, keep
+     track of the later using this pointer.  */
+  tree orig_index;
+  /* A TREE_VEC containing the set of parms this parameter belongs
+     to. */
+  tree siblings;
   tree decl;
 };
 typedef struct template_parm_index_s template_parm_index;
@@ -4476,6 +4480,9 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
 				   structural. The actual comparison
 				   will be identical to
 				   COMPARE_STRICT.  */
+#define COMPARE_NO_SIBLINGS   16 /* When comparing template
+				    parameters, don't consider their
+				    siblings.  */
 
 /* Used with push_overloaded_decl.  */
 #define PUSH_GLOBAL	     0  /* Push the DECL into namespace scope,
@@ -4509,11 +4516,69 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
 	((template_parm_index*)TEMPLATE_PARM_INDEX_CHECK (NODE))
 #define TEMPLATE_PARM_IDX(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->index)
 #define TEMPLATE_PARM_LEVEL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->level)
-/* The Number of sibling parms this template parm has.  */
-#define TEMPLATE_PARM_NUM_SIBLINGS(NODE) \
-  (TEMPLATE_PARM_INDEX_CAST (NODE)->num_siblings)
-#define TEMPLATE_PARM_DESCENDANTS(NODE) (TREE_CHAIN (NODE))
-#define TEMPLATE_PARM_ORIG_LEVEL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->orig_level)
+/* A TREE_VEC containing the sibling parameters for a given template
+   parm.  */
+#define TEMPLATE_PARM_SIBLINGS(NODE) \
+  (TEMPLATE_PARM_INDEX_CAST (NODE)->siblings)
+
+/* This accessor has to do with partial instantiation of member
+   templates and type fixup.
+
+   Consider the member template M below:
+
+	template<class T>
+	struct S
+	{
+	  template<class U> struct M {};
+	};
+
+   When we say template<class V> S<int>::M<V>, M is partially
+   instantiated and the level of its template parameter V is reduced;
+   it was 2 initially, but in the context of the partial
+   instantiation, it becomes 1.
+
+   TEMPLATE_PARM_DESCENDANTS for U captures the relationship between that
+   parameter and those that result from its level-reducing.
+
+   For template type parameters, TEMPLATE_PARM_DESCENDANTS is a vector
+   in which each element represents a parameter reduced to a level
+   that is the vector index of said element.  In the example above,
+   the element at index 1 of TEMPLATE_PARM_DESCENDANTS (U) will
+   contain V.
+
+   For non-type template parameters, TEMPLATE_PARM_DESCENDANTS is a
+   vector or TREE_LIST.  For a given level (that represents the index
+   of each element of the vector), there is a list of parameters
+   reduced to that level, and each parameter of that list has a
+   different type.  For instance:
+
+	template<class T>
+	struct S
+	{
+	  template<T a>  struct M {};
+	};
+
+   When we say template<> S<int>::M, the level of parameter 'a' is
+   reduced to 1 (from 2), and its type is 'int'.
+
+   When we say template<> S<int>::M, the level of 'a' is reduced to 1
+   as well, but its type is 'char'.
+
+   So in TEMPLATE_PARM_DESCENDANTS for parameter 'a', the element at
+   index 1 will be a TREE_LIST of two elements which first TREE_VALUE
+   is the TEMPLATE_PARM_INDEX for 'int a' and which second TREE_VALUE
+   is the TEMPLATE_PARM_INDEX for 'char a'.
+
+   Note that types of template parameters that are inserted into
+   TEMPLATE_PARM_DESCENDANTS are always fixed-up types.
+
+   Also note that the argument for TEMPLATE_PARM_DESCENDANT must be a
+   TEMPLATE_PARM_INDEX.  */
+#define TEMPLATE_PARM_DESCENDANTS(NODE) (TREE_CHAIN (TEMPLATE_PARM_INDEX_CHECK (NODE)))
+#define TEMPLATE_PARM_ORIG_INDEX(NODE) \
+  (TEMPLATE_PARM_INDEX_CAST (NODE)->orig_index)
+#define TEMPLATE_PARM_ORIG_LEVEL(NODE) \
+  (TEMPLATE_PARM_LEVEL (TEMPLATE_PARM_ORIG_INDEX (NODE)))
 #define TEMPLATE_PARM_DECL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->decl)
 #define TEMPLATE_PARM_PARAMETER_PACK(NODE) \
   (TREE_LANG_FLAG_0 (TEMPLATE_PARM_INDEX_CHECK (NODE)))
@@ -5280,9 +5345,10 @@ extern void append_type_to_template_for_access_check (tree, tree, tree,
 extern tree splice_late_return_type		(tree, tree);
 extern bool is_auto				(const_tree);
 extern tree process_template_parm		(tree, location_t, tree, 
-						 bool, bool, unsigned);
+						 bool, bool, tree);
 extern tree end_template_parm_list		(tree);
-void fixup_template_parms (void);
+extern void fixup_current_template_parms        (void);
+extern void fixup_template_parms                (tree);
 extern void end_template_decl			(void);
 extern tree maybe_update_decl_type		(tree, tree);
 extern bool check_default_tmpl_args             (tree, tree, int, int, int);
@@ -5307,8 +5373,12 @@ extern void do_type_instantiation		(tree, tree, tsubst_flags_t);
 extern bool always_instantiate_p		(tree);
 extern void maybe_instantiate_noexcept		(tree);
 extern tree instantiate_decl			(tree, int, bool);
+extern bool comp_template_parms_siblings        (tree, tree, int);
+extern int comp_template_parm_levels            (const_tree, const_tree, int);
+extern int comp_template_parms_guided		(const_tree, const_tree, int);
 extern int comp_template_parms			(const_tree, const_tree);
 extern bool uses_parameter_packs                (tree);
+extern bool template_type_parameter_type_p      (tree);
 extern bool template_parameter_pack_p           (const_tree);
 extern bool function_parameter_pack_p		(const_tree);
 extern bool function_parameter_expanded_from_pack_p (tree, tree);
@@ -5321,6 +5391,8 @@ extern int template_class_depth			(tree);
 extern int is_specialization_of			(tree, tree);
 extern bool is_specialization_of_friend		(tree, tree);
 extern tree get_pattern_parm			(tree, tree);
+extern int comp_template_args_guided            (tree, tree, tree *,
+						 tree *, int);
 extern int comp_template_args			(tree, tree);
 extern tree maybe_process_partial_specialization (tree);
 extern tree most_specialized_instantiation	(tree);
@@ -5700,6 +5772,7 @@ extern tree lvalue_type				(tree);
 extern tree error_type				(tree);
 extern int varargs_function_p			(const_tree);
 extern bool really_overloaded_fn		(tree);
+extern bool compare_trees                       (tree, tree, int);
 extern bool cp_tree_equal			(tree, tree);
 extern tree no_linkage_check			(tree, bool);
 extern void debug_binfo				(tree);
@@ -5760,6 +5833,9 @@ extern int type_unknown_p			(const_tree);
 enum { ce_derived, ce_normal, ce_exact };
 extern bool comp_except_specs			(const_tree, const_tree, int);
 extern bool comptypes				(tree, tree, int);
+extern bool same_type_ignoring_top_level_qualifiers_guided_p (tree type1,
+							      tree type2,
+							      int strict);
 extern bool same_type_ignoring_top_level_qualifiers_p (tree, tree);
 extern bool compparms				(const_tree, const_tree);
 extern int comp_cv_qualification		(const_tree, const_tree);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index c6bd290..37e82a9 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -11960,7 +11960,7 @@ cp_parser_template_parameter_list (cp_parser* parser)
 						parameter,
 						is_non_type,
 						is_parameter_pack,
-						0);
+						NULL_TREE);
       else
        {
          tree err_parm = build_tree_list (parameter, parameter);
@@ -21124,7 +21124,7 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
     {
       /* Parse the template parameters.  */
       parameter_list = cp_parser_template_parameter_list (parser);
-      fixup_template_parms ();
+      fixup_current_template_parms ();
     }
 
   /* Get the deferred access checks from the parameter list.  These
@@ -21289,6 +21289,7 @@ cp_parser_single_declaration (cp_parser* parser,
     {
       if (cp_parser_declares_only_class_p (parser))
 	{
+	  bool friend_typename_p = false;
 	  decl = shadow_tag (&decl_specifiers);
 
 	  /* In this case:
@@ -21303,7 +21304,10 @@ cp_parser_single_declaration (cp_parser* parser,
 	      && !decl
 	      && decl_specifiers.type
 	      && TYPE_P (decl_specifiers.type))
-	    decl = decl_specifiers.type;
+	    {
+	      decl = decl_specifiers.type;
+	      friend_typename_p = true;
+	    }
 
 	  if (decl && decl != error_mark_node)
 	    decl = TYPE_NAME (decl);
@@ -21312,6 +21316,17 @@ cp_parser_single_declaration (cp_parser* parser,
 
 	  /* Perform access checks for template parameters.  */
 	  cp_parser_perform_template_parameter_access_checks (checks);
+	  if (friend_typename_p
+	      && parser->num_template_parameter_lists > 0
+	      && decl != error_mark_node)
+	    /*  We are looking a the declaration of a class/enum which
+		name is a typename; that declaration has a template
+		header that declares some template parameters used in
+		the declaration.  Ensure the declaration carries a
+		template info representing that header.  That template
+		info will later be useful when we need to fixup the
+		template parameters used in the declaration.  */
+	    push_template_decl_real (decl, /*is_friend=*/true);
 	}
     }
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 4980c19..51803fe 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -148,7 +148,7 @@ static tree convert_template_argument (tree, tree, tree,
 static int for_each_template_parm (tree, tree_fn_t, void*,
 				   struct pointer_set_t*, bool);
 static tree expand_template_argument_pack (tree);
-static tree build_template_parm_index (int, int, int, int, tree, tree);
+static tree build_template_parm_index (int, int, tree, tree, tree, tree);
 static bool inline_needs_template_parms (tree);
 static void push_inline_template_parms_recursive (tree, int);
 static tree retrieve_local_specialization (tree);
@@ -183,6 +183,7 @@ static tree try_class_unification (tree, tree, tree, tree, bool);
 static int coerce_template_template_parms (tree, tree, tsubst_flags_t,
 					   tree, tree);
 static bool template_template_parm_bindings_ok_p (tree, tree);
+static int template_args_equal_guided (tree, tree, int);
 static int template_args_equal (tree, tree);
 static void tsubst_default_arguments (tree);
 static tree for_each_template_parm_r (tree *, int *, void *);
@@ -201,12 +202,22 @@ static void append_type_to_template_for_access_check_1 (tree, tree, tree,
 							location_t);
 static tree listify (tree);
 static tree listify_autos (tree, tree);
-static tree template_parm_to_arg (tree t);
+static tree template_parm_to_arg (tree);
+static tree template_parms_to_args (tree);
 static bool arg_from_parm_pack_p (tree, tree);
+static bool arg_from_reduced_and_fixedup_parm_pack_of_expansion_p (tree,
+								   tree,
+								   tree);
 static tree current_template_args (void);
-static tree fixup_template_type_parm_type (tree, int);
-static tree fixup_template_parm_index (tree, tree, int);
+static tree get_root_index_same_level (tree);
+static void get_template_parameter_level_and_index (tree, int*, int*);
+static void add_descendant_to_parm_index (tree, tree);
+static tree get_descendant_of_parm_index (tree, int, tree);
+static tree get_template_parm_index (tree);
+static tree fixup_template_type_parm_type (tree, tree);
+static tree fixup_template_parm_index (tree, tree, tree);
 static tree tsubst_template_parm (tree, tree, tsubst_flags_t);
+static void fixup_innermost_template_parms (tree, tree);
 
 /* Make the current scope suitable for access checking when we are
    processing T.  T can be FUNCTION_DECL for instantiated function
@@ -322,7 +333,16 @@ get_template_info (const_tree t)
     return NULL;
 
   if (DECL_P (t) && DECL_LANG_SPECIFIC (t))
-    tinfo = DECL_TEMPLATE_INFO (t);
+    {     
+      int code = TREE_CODE (t);
+      /* Only the DECLs below are allowed to have template info.  */
+      if (code == VAR_DECL
+	  || code == FIELD_DECL
+	  || code == FUNCTION_DECL
+	  || code == TYPE_DECL
+	  || code == TEMPLATE_DECL)
+	tinfo = DECL_TEMPLATE_INFO (t);
+    }
 
   if (!tinfo && DECL_IMPLICIT_TYPEDEF_P (t))
     t = TREE_TYPE (t);
@@ -331,6 +351,9 @@ get_template_info (const_tree t)
     tinfo = TYPE_TEMPLATE_INFO (t);
   else if (TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM)
     tinfo = TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t);
+  else if (TREE_CODE (t) == TYPENAME_TYPE
+	   && DECL_LANG_SPECIFIC (TYPE_NAME (t)))
+    tinfo = DECL_TEMPLATE_INFO (TYPE_NAME (t));
 
   return tinfo;
 }
@@ -2675,11 +2698,56 @@ check_explicit_specialization (tree declarator,
 }
 
 /* Returns 1 iff PARMS1 and PARMS2 are identical sets of template
+   parameters of a given level, represented by a TREE_VEC of
+   TREE_LIST.  The TREE_VALUE of each TREE_LIST represents a given
+   template parameter.  STRICT controls how the comparison is done.
+   It has the same meaning as the last parameter of the comptypes
+   function.  */
+
+int
+comp_template_parm_levels (const_tree parms_level1,
+			   const_tree parms_level2,
+			   int strict)
+{
+  int i;
+  gcc_assert (TREE_CODE (parms_level1) == TREE_VEC);
+  gcc_assert (TREE_CODE (parms_level2) == TREE_VEC);
+
+  if (TREE_VEC_LENGTH (parms_level1) != TREE_VEC_LENGTH (parms_level2))
+    return 0;
+
+  for (i = 0; i < TREE_VEC_LENGTH (parms_level2); ++i)
+    {
+      tree parm1 = TREE_VALUE (TREE_VEC_ELT (parms_level1, i));
+      tree parm2 = TREE_VALUE (TREE_VEC_ELT (parms_level2, i));
+
+      /* If either of the template parameters are invalid, assume
+	 they match for the sake of error recovery. */
+      if (parm1 == error_mark_node || parm2 == error_mark_node)
+	return 1;
+
+      if (TREE_CODE (parm1) != TREE_CODE (parm2))
+	return 0;
+
+      if (TREE_CODE (parm1) == TEMPLATE_TYPE_PARM
+	  && (TEMPLATE_TYPE_PARAMETER_PACK (parm1)
+	      == TEMPLATE_TYPE_PARAMETER_PACK (parm2)))
+	continue;
+      else if (!comptypes (TREE_TYPE (parm1), TREE_TYPE (parm2), strict))
+	return 0;
+    }
+  return 1;
+}
+
+/* Returns 1 iff PARMS1 and PARMS2 are identical sets of template
    parameters.  These are represented in the same format used for
-   DECL_TEMPLATE_PARMS.  */
+   DECL_TEMPLATE_PARMS.  STRICT controls how the comparison is done.
+   Its semantics are the same as the last parameter of comptypes.  */
 
 int
-comp_template_parms (const_tree parms1, const_tree parms2)
+comp_template_parms_guided (const_tree parms1,
+			    const_tree parms2,
+			    int strict)
 {
   const_tree p1;
   const_tree p2;
@@ -2693,34 +2761,9 @@ comp_template_parms (const_tree parms1, const_tree parms2)
     {
       tree t1 = TREE_VALUE (p1);
       tree t2 = TREE_VALUE (p2);
-      int i;
-
-      gcc_assert (TREE_CODE (t1) == TREE_VEC);
-      gcc_assert (TREE_CODE (t2) == TREE_VEC);
 
-      if (TREE_VEC_LENGTH (t1) != TREE_VEC_LENGTH (t2))
+      if (!comp_template_parm_levels (t1, t2, strict))
 	return 0;
-
-      for (i = 0; i < TREE_VEC_LENGTH (t2); ++i)
-	{
-          tree parm1 = TREE_VALUE (TREE_VEC_ELT (t1, i));
-          tree parm2 = TREE_VALUE (TREE_VEC_ELT (t2, i));
-
-          /* If either of the template parameters are invalid, assume
-             they match for the sake of error recovery. */
-          if (parm1 == error_mark_node || parm2 == error_mark_node)
-            return 1;
-
-	  if (TREE_CODE (parm1) != TREE_CODE (parm2))
-	    return 0;
-
-	  if (TREE_CODE (parm1) == TEMPLATE_TYPE_PARM
-              && (TEMPLATE_TYPE_PARAMETER_PACK (parm1)
-                  == TEMPLATE_TYPE_PARAMETER_PACK (parm2)))
-	    continue;
-	  else if (!same_type_p (TREE_TYPE (parm1), TREE_TYPE (parm2)))
-	    return 0;
-	}
     }
 
   if ((p1 != NULL_TREE) != (p2 != NULL_TREE))
@@ -2731,6 +2774,28 @@ comp_template_parms (const_tree parms1, const_tree parms2)
   return 1;
 }
 
+/* Returns 1 iff PARMS1 and PARMS2 are identical sets of template
+   parameters.  These are represented in the same format used for
+   DECL_TEMPLATE_PARMS.  */
+
+int
+comp_template_parms (const_tree parms1, const_tree parms2)
+{
+  return comp_template_parms_guided (parms1, parms2,
+				     COMPARE_STRICT);
+}
+
+/* Determine wheter PARM is the type of a template type parameter.  */
+
+bool
+template_type_parameter_type_p (tree t)
+{
+  return (t
+	  && (TREE_CODE (t) == TEMPLATE_TYPE_PARM
+	      || TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM
+	      || TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM));
+}
+
 /* Determine whether PARM is a parameter pack.  */
 
 bool 
@@ -3395,22 +3460,27 @@ check_template_shadow (tree decl)
 }
 
 /* Return a new TEMPLATE_PARM_INDEX with the indicated INDEX, LEVEL,
-   ORIG_LEVEL, DECL, and TYPE.  NUM_SIBLINGS is the total number of
-   template parameters.  */
+   ORIG_INDEX, DECL, and TYPE.  SIBLINGS is a TREE_VEC containing the
+   set of parameters the current template parameter belongs to.  */
 
 static tree
 build_template_parm_index (int index,
 			   int level,
-			   int orig_level,
-			   int num_siblings,
+			   tree orig_index,
+			   tree siblings,
 			   tree decl,
 			   tree type)
 {
-  tree t = make_node (TEMPLATE_PARM_INDEX);
+  tree t;
+
+  gcc_assert (level >= 1);
+
+  t = make_node (TEMPLATE_PARM_INDEX);
   TEMPLATE_PARM_IDX (t) = index;
   TEMPLATE_PARM_LEVEL (t) = level;
-  TEMPLATE_PARM_ORIG_LEVEL (t) = orig_level;
-  TEMPLATE_PARM_NUM_SIBLINGS (t) = num_siblings;
+  TEMPLATE_PARM_ORIG_INDEX (t) = orig_index ? orig_index : t;
+  gcc_assert (TREE_CODE (TEMPLATE_PARM_ORIG_INDEX (t)) == TEMPLATE_PARM_INDEX);
+  TEMPLATE_PARM_SIBLINGS (t) = siblings;
   TEMPLATE_PARM_DECL (t) = decl;
   TREE_TYPE (t) = type;
   TREE_CONSTANT (t) = TREE_CONSTANT (decl);
@@ -3458,13 +3528,15 @@ static tree
 reduce_template_parm_level (tree index, tree type, int levels, tree args,
 			    tsubst_flags_t complain)
 {
-  if (TEMPLATE_PARM_DESCENDANTS (index) == NULL_TREE
-      || (TEMPLATE_PARM_LEVEL (TEMPLATE_PARM_DESCENDANTS (index))
-	  != TEMPLATE_PARM_LEVEL (index) - levels)
-      || !same_type_p (type, TREE_TYPE (TEMPLATE_PARM_DESCENDANTS (index))))
+  int new_level = TEMPLATE_PARM_LEVEL (index) - levels;
+  tree t = NULL_TREE;
+
+  gcc_assert (new_level > 0);
+
+  if ((t = get_descendant_of_parm_index (index, new_level, type)) == NULL_TREE)
     {
       tree orig_decl = TEMPLATE_PARM_DECL (index);
-      tree decl, t;
+      tree decl;
 
       decl = build_decl (DECL_SOURCE_LOCATION (orig_decl),
 			 TREE_CODE (orig_decl), DECL_NAME (orig_decl), type);
@@ -3475,10 +3547,18 @@ reduce_template_parm_level (tree index, tree type, int levels, tree args,
 
       t = build_template_parm_index (TEMPLATE_PARM_IDX (index),
 				     TEMPLATE_PARM_LEVEL (index) - levels,
-				     TEMPLATE_PARM_ORIG_LEVEL (index),
-				     TEMPLATE_PARM_NUM_SIBLINGS (index),
+				     TEMPLATE_PARM_ORIG_INDEX (index),
+				     /*we will fixup the siblings for
+				       this index in
+				       tsubst_template_parms, so set
+				       it to NULL here.  */
+				     NULL_TREE,
 				     decl, type);
-      TEMPLATE_PARM_DESCENDANTS (index) = t;
+      /* Do not yet update TEMPLATE_PARM_DESCENDANTS
+	 (TEMPLATE_PARM_ORIG_INDEX (index)) because it will be done
+	 when the new parm index T is fixed up, along with its
+	 siblings, using a call to add_descendant_to_parm_index.  */
+
       TEMPLATE_PARM_PARAMETER_PACK (t) 
 	= TEMPLATE_PARM_PARAMETER_PACK (index);
 
@@ -3489,23 +3569,23 @@ reduce_template_parm_level (tree index, tree type, int levels, tree args,
 	   args, complain);
     }
 
-  return TEMPLATE_PARM_DESCENDANTS (index);
+  return t;
 }
 
 /* Process information from new template parameter PARM and append it
    to the LIST being built.  This new parameter is a non-type
    parameter iff IS_NON_TYPE is true. This new parameter is a
    parameter pack iff IS_PARAMETER_PACK is true.  The location of PARM
-   is in PARM_LOC. NUM_TEMPLATE_PARMS is the size of the template
-   parameter list PARM belongs to. This is used used to create a
+   is in PARM_LOC.  SIBLING_PARMS is a TREE_VEC containing the set of
+   template parameters PARM belongs to.  This is used used to create a
    proper canonical type for the type of PARM that is to be created,
-   iff PARM is a type.  If the size is not known, this parameter shall
-   be set to 0.  */
+   iff PARM is a type.  If the set of parameters is not known, this
+   parameter shall be set to NULL_TREE.  */
 
 tree
 process_template_parm (tree list, location_t parm_loc, tree parm,
 		       bool is_non_type, bool is_parameter_pack,
-		       unsigned num_template_parms)
+		       tree sibling_parms)
 {
   tree decl = 0;
   tree defval;
@@ -3579,8 +3659,8 @@ process_template_parm (tree list, location_t parm_loc, tree parm,
       TREE_READONLY (decl) = 1;
       DECL_INITIAL (parm) = DECL_INITIAL (decl)
 	= build_template_parm_index (idx, processing_template_decl,
-				     processing_template_decl,
-				     num_template_parms,
+				     NULL_TREE,
+				     sibling_parms,
 				     decl, TREE_TYPE (parm));
 
       TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)) 
@@ -3613,8 +3693,8 @@ process_template_parm (tree list, location_t parm_loc, tree parm,
       parm = decl;
       TEMPLATE_TYPE_PARM_INDEX (t)
 	= build_template_parm_index (idx, processing_template_decl,
-				     processing_template_decl,
-				     num_template_parms,
+				     NULL_TREE,
+				     sibling_parms,
 				     decl, TREE_TYPE (parm));
       TEMPLATE_TYPE_PARAMETER_PACK (t) = is_parameter_pack;
       TYPE_CANONICAL (t) = canonical_type_parameter (t);
@@ -3654,34 +3734,314 @@ end_template_parm_list (tree parms)
   return saved_parmlist;
 }
 
+/*  Get the "canonical" INDEX of a given TEMPLATE_PARM_INDEX tree
+    node.
+
+    There can be several equivalent TEMPLATE_PARM_INDEX created for a
+    given template parameter, be it a type or non-type template
+    parameter.
+
+    For a type template parameter P, this function returns the
+    TEMPLATE_PARM_INDEX of the canonical type of P.
+
+    For a non-type template parameter P, this function returns the
+    the "original" TEMPLATE_PARM_INDEX P was created from, given that
+    they both have the same level.  */
+
+static tree
+get_root_index_same_level (tree index)
+{
+  tree i = index;
+
+  if (TREE_CODE (TEMPLATE_PARM_DECL (i)) == CONST_DECL)
+    {
+      if (TEMPLATE_PARM_ORIG_LEVEL (i) == TEMPLATE_PARM_LEVEL (index))
+	i = TEMPLATE_PARM_ORIG_INDEX (i);
+    }
+  else
+    {
+      if (template_type_parameter_type_p (TREE_TYPE (i))
+	  && TREE_CODE (TEMPLATE_PARM_DECL (i)) != CONST_DECL
+	  && TYPE_CANONICAL (TREE_TYPE (i)) != NULL_TREE)
+	i = TEMPLATE_TYPE_PARM_INDEX (TYPE_CANONICAL (TREE_TYPE (i)));
+    }
+  return i;
+}
+
+/* Get the level and the index of a given template parameter.  */
+
+static void
+get_template_parameter_level_and_index (tree parameter, int *level, int *index)
+{
+  int l = 0, i = -1;
+  tree parm;
+
+  if (TREE_CODE (parameter) == TYPE_DECL
+      || TREE_CODE (parameter) == TEMPLATE_DECL)
+    parm = TREE_TYPE (parameter);
+  else if (TREE_CODE (parameter) == PARM_DECL)
+    parm = DECL_INITIAL (parameter);
+  else
+    parm = parameter;
+
+  template_parm_level_and_index (parm, &l, &i);
+
+  gcc_assert (l > 0 && i >= 0);
+
+  if (level)
+    *level = l;
+  if (index)
+    *index = i;
+}
+
+/*  Add a descendant to a given template parameter index INDEX.  A
+    descendant of INDEX is the result of reducing the level of INDEX
+    to another level.  The property TEMPLATE_PARM_DESCENDANT of INDEX
+    is a vector that contains the descendants of INDEX.  This function
+    properly appends the descender of INDEX to that
+    TEMPLATE_PARM_DESCENDANT vector.  */
+
+static void
+add_descendant_to_parm_index (tree index,
+			      tree descendant)
+{
+  tree *where = NULL;
+
+  gcc_assert (TREE_CODE (index) == TEMPLATE_PARM_INDEX
+	      && TREE_CODE (descendant) == TEMPLATE_PARM_INDEX
+	      && TEMPLATE_PARM_LEVEL (descendant) > 0
+	      && TEMPLATE_PARM_LEVEL (index) > 0
+	      && TEMPLATE_PARM_LEVEL (descendant) <= TEMPLATE_PARM_LEVEL (index));
+
+  if (TYPE_CANONICAL (TREE_TYPE (TEMPLATE_PARM_DECL (descendant)))
+      != NULL_TREE)
+    /*  For a descendant that requires canonical type comparison
+	(unlike for reduced template template parms) we only accept
+	types that have been fixed-up.  */
+    gcc_assert (TEMPLATE_PARM_SIBLINGS (descendant) != NULL_TREE);
+
+  index = get_root_index_same_level (index);
+
+  if (TEMPLATE_PARM_DESCENDANTS (index) == NULL_TREE)
+    TEMPLATE_PARM_DESCENDANTS (index) =
+      make_tree_vec (TEMPLATE_PARM_LEVEL (index));
+
+  where = &TREE_VEC_ELT (TEMPLATE_PARM_DESCENDANTS (index),
+			 TEMPLATE_PARM_LEVEL (descendant) - 1);
+
+  if (TREE_CODE (TEMPLATE_PARM_DECL (index)) == CONST_DECL)
+    {
+    /* INDEX is for a non-type template param.  So each one of its
+       descendant might have a different type.  To see that, consider:
+
+       template<class T> struct S
+       {
+       template<template<T i> class TT> struct Inner;
+       };
+
+       Then if we write:
+
+       S<int> s0;
+
+       As a result, in:
+	 
+       template<> template<template<int i> class TT>
+       S<int>::Inner<TT>
+
+       'i' has level 2, which was reduced from its inital level 3.
+       But look at how its type is 'int'.
+
+       But if we write:
+
+       S<char> s1;
+
+       Then, in:
+
+       template<> template<template<char i> class TT>
+       S<char>::Inner<TT>
+
+       'i' still has level 2 (reduced from initial level 3), but its
+       type is now 'char'.
+
+       So both 'i' of level 2 that are descendants of the initial
+       'i' of level 3, but each of them (might) have a separate
+       type.
+
+       Therefore, at each index of TEMPLATE_PARM_DESCENDANTS (that
+       represent a level) we have a TREE_LIST in which each
+       TREE_PURPOSE has the type of TEMPLATE_PARM_INDEX and each
+       TREE_VALUE has the TEMPLATE_PARM_INDEX itself.  */
+      if (*where != NULL_TREE)
+	gcc_assert (TEMPLATE_PARM_LEVEL (TREE_VALUE (*where)) 
+		    == TEMPLATE_PARM_LEVEL (descendant));
+      *where = tree_cons (TREE_TYPE (descendant),
+			  descendant,
+			  *where);
+    }
+  else
+    {
+      if (*where == NULL_TREE)
+	TREE_VEC_ELT (TEMPLATE_PARM_DESCENDANTS (index),
+		      TEMPLATE_PARM_LEVEL (descendant) - 1) = descendant;
+      else
+	gcc_assert (same_type_p (TREE_TYPE (*where),
+				    TREE_TYPE (descendant))
+		    && (TEMPLATE_PARM_LEVEL (*where)
+			== TEMPLATE_PARM_LEVEL (descendant)));
+    }
+}
+
+/*  Inspect the TEMPLATE_PARM_DESCENDANTS vector associated to INDEX
+    to return its descendant for a given level and type.  */
+
+static tree
+get_descendant_of_parm_index (tree index,
+			      int level,
+			      tree type)
+{
+  tree result = NULL_TREE, orig_index = index;
+
+  gcc_assert (TREE_CODE (index) == TEMPLATE_PARM_INDEX
+	      && TEMPLATE_PARM_LEVEL (index) > 0
+	      && level > 0);
+
+  index = get_root_index_same_level (index);
+
+  if (TEMPLATE_PARM_DESCENDANTS (index))
+    {
+      gcc_assert (TREE_CODE (TEMPLATE_PARM_DESCENDANTS (index)) == TREE_VEC);
+      if (TREE_VEC_LENGTH (TEMPLATE_PARM_DESCENDANTS (index)) >= level)
+	{
+	  tree elem = TREE_VEC_ELT (TEMPLATE_PARM_DESCENDANTS (index),
+				    level - 1);
+	  if (TREE_CODE (TEMPLATE_PARM_DECL (index)) == CONST_DECL)
+	    /* We are looking for the index of a non-type template
+	       parm.  */
+	    for (; elem != NULL_TREE; elem = TREE_CHAIN (elem))
+	      {
+		if (same_type_p (TREE_TYPE (TREE_VALUE (elem)),
+				 type))
+		  result = TREE_VALUE (elem);
+	      }
+	  else
+	    /* We are looking for the index of type template parm.  */
+	    result = elem;
+	  if (result != NULL_TREE
+	      && (TEMPLATE_PARM_LEVEL (result) != TEMPLATE_PARM_LEVEL (orig_index))
+	      && (DECL_SOURCE_LOCATION (TEMPLATE_PARM_DECL (result))
+		  != DECL_SOURCE_LOCATION (TEMPLATE_PARM_DECL (orig_index))))
+	    {
+	      /*  We have gotten an equivalent index, that was reduced
+		  from index from ORIG_INDEX, but which (location of)
+		  DECL is different.  This can lead to having error
+		  messages pointing to the wrong location, so let's
+		  build an equivalent TEMPLATE_PARM_INDEX with a DECL
+		  pointing to the same location as ORIG_INDEX for
+		  RESULT.  */
+	      tree decl, orig_decl, orig_result = result, decl_type;
+
+	      decl = orig_decl = TEMPLATE_PARM_DECL (orig_index);
+
+	      if (TREE_CODE (decl) == TYPE_DECL
+		  || TREE_CODE (decl) == PARM_DECL
+		  || TREE_CODE (decl) == CONST_DECL)
+		{
+		  decl = build_decl (DECL_SOURCE_LOCATION (orig_decl),
+				     TREE_CODE (orig_decl), DECL_NAME (orig_decl),
+				     TREE_TYPE (result));
+		  TREE_CONSTANT (decl) = TREE_CONSTANT (orig_decl);
+		  TREE_READONLY (decl) = TREE_READONLY (orig_decl);
+		  DECL_ARTIFICIAL (decl) = 1;
+		  SET_DECL_TEMPLATE_PARM_P (decl);
+
+		  result = build_template_parm_index (TEMPLATE_PARM_IDX (result),
+						      TEMPLATE_PARM_LEVEL (result),
+						      TEMPLATE_PARM_ORIG_INDEX (result),
+						      TEMPLATE_PARM_SIBLINGS (result),
+						      decl,
+						      TREE_TYPE (result));
+		  TEMPLATE_PARM_PARAMETER_PACK (result) =
+		    TEMPLATE_PARM_PARAMETER_PACK (orig_result);
+		  TEMPLATE_PARM_DESCENDANTS (result) =
+		    TEMPLATE_PARM_DESCENDANTS (orig_result);
+
+		  decl_type = copy_type (TREE_TYPE (decl));
+		  TYPE_NAME (decl_type) = decl;
+		  TREE_TYPE (decl) = decl_type;
+		  TREE_TYPE (result) = decl_type;
+		}
+	    }
+
+	}
+    }
+  return result;
+}
+
+/*  Return the TEMPLATE_PARM_INDEX of a template parameter PARM.  PARM
+    can be either the type of a template parameter, or its DECL.  */
+
+static tree
+get_template_parm_index (tree parm)
+{
+  tree result = NULL_TREE;
+
+  switch (TREE_CODE (parm))
+    {
+    case TEMPLATE_PARM_INDEX:
+      result = parm;
+      break;
+
+    case TEMPLATE_TYPE_PARM:
+    case TEMPLATE_TEMPLATE_PARM:
+    case BOUND_TEMPLATE_TEMPLATE_PARM:
+      result = TEMPLATE_TYPE_PARM_INDEX (parm);
+      break;
+
+    case PARM_DECL:
+    case CONST_DECL:
+      gcc_assert (DECL_TEMPLATE_PARM_P (parm));
+      return get_template_parm_index (DECL_INITIAL (parm));
+
+    case TEMPLATE_DECL:
+    case TYPE_DECL:
+      gcc_assert (DECL_TEMPLATE_PARM_P (parm));      
+      return get_template_parm_index (TREE_TYPE (parm));
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return result;
+}
+
 /* Create a new type almost identical to TYPE but which has the
    following differences:
 
-     1/ T has a new TEMPLATE_PARM_INDEX that carries the new number of
-     template sibling parameters of T.
+     1/ T has a new TEMPLATE_PARM_INDEX that carries the set of
+     sibling template parameters of T.
 
-     2/ T has a new canonical type that matches the new number
-     of sibling parms.
+     2/ T has a new canonical type that matches the set of sibling
+     parms.
 
      3/ From now on, T is going to be what lookups referring to the
-     name of TYPE will return. No lookup should return TYPE anymore.
+     name of TYPE will return.  No lookup should return TYPE anymore.
 
-   NUM_PARMS is the new number of sibling parms TYPE belongs to.
+   SIBLING_PARMS is the set of sibling parms TYPE belongs to.
 
-   This is a subroutine of fixup_template_parms.  */
+   This is a subroutine of fixup_innermost_template_parms.  */
 
 static tree
-fixup_template_type_parm_type (tree type, int num_parms)
+fixup_template_type_parm_type (tree type, tree sibling_parms)
 {
-  tree orig_idx = TEMPLATE_TYPE_PARM_INDEX (type), idx;
-  tree t;
+  tree orig_idx = TEMPLATE_TYPE_PARM_INDEX (type),
+    t, idx, parent_idx = NULL_TREE;
   /* This is the decl which name is inserted into the symbol table for
      the template parm type. So whenever we lookup the type name, this
      is the DECL we get.  */
   tree decl;
 
   /* Do not fix up the type twice.  */
-  if (orig_idx && TEMPLATE_PARM_NUM_SIBLINGS (orig_idx) != 0)
+  if (orig_idx && TEMPLATE_PARM_SIBLINGS (orig_idx) != NULL_TREE)
     return type;
 
   t = copy_type (type);
@@ -3692,12 +4052,19 @@ fixup_template_type_parm_type (tree type, int num_parms)
   TYPE_POINTER_TO (t) = 0;
   TYPE_REFERENCE_TO (t) = 0;
 
+  if (TEMPLATE_PARM_LEVEL (TEMPLATE_PARM_ORIG_INDEX (orig_idx))
+      != TEMPLATE_PARM_LEVEL (orig_idx))
+    /* We are fixing up a type which TEMPLATE_TYPE_PARM_INDEX is the
+       result of level-reduction.  Keep a pointer to the original
+       upper (fixed-up) level index.  */
+    parent_idx = TEMPLATE_PARM_ORIG_INDEX (orig_idx);
+
   idx = build_template_parm_index (TEMPLATE_PARM_IDX (orig_idx),
 				   TEMPLATE_PARM_LEVEL (orig_idx),
-				   TEMPLATE_PARM_ORIG_LEVEL (orig_idx),
-				   num_parms,
+				   parent_idx,
+				   sibling_parms,
 				   decl, t);
-  TEMPLATE_PARM_DESCENDANTS (idx) = TEMPLATE_PARM_DESCENDANTS (orig_idx);
+
   TEMPLATE_PARM_PARAMETER_PACK (idx) = TEMPLATE_PARM_PARAMETER_PACK (orig_idx);
   TEMPLATE_TYPE_PARM_INDEX (t) = idx;
 
@@ -3711,7 +4078,15 @@ fixup_template_type_parm_type (tree type, int num_parms)
      type is properly fixed up.  */
   TREE_TYPE (decl) = t;
 
-  TYPE_CANONICAL (t) = canonical_type_parameter (t);
+  /* Don't set canonical type if the original type was requiring
+     structural equality.  This can happen for e.g, types of template
+     template parms that got level-reduced.  */
+  if (!TYPE_STRUCTURAL_EQUALITY_P (type))
+    TYPE_CANONICAL (t) = canonical_type_parameter (t);
+
+  /*  Update TEMPLATE_PARM_DESCENDANTS (TEMPLATE_PARM_ORIG_INDEX
+      (orig_idx)).  */
+  add_descendant_to_parm_index (TEMPLATE_PARM_ORIG_INDEX (idx), idx);
 
   return t;
 }
@@ -3719,35 +4094,41 @@ fixup_template_type_parm_type (tree type, int num_parms)
 /* Create and return a new TEMPLATE_PARM_INDEX that is almost
    identical to I, but that is fixed up as to:
 
-   1/ carry the number of sibling parms (NUM_PARMS) of the template
+   1/ carry the set of sibling parms (SIBLING_PARMS) of the template
    parm represented by I.
 
    2/ replace all references to template parm types declared before I
    (in the same template parm list as I) by references to template
-   parm types contained in ARGS. ARGS should contain the list of
+   parm types contained in ARGS.  ARGS should contain the list of
    template parms that have been fixed up so far, in a form suitable
    to be passed to tsubst.
 
-   This is a subroutine of fixup_template_parms.  */
+   This is a subroutine of fixup_innermost_template_parms.  */
 
 static tree
-fixup_template_parm_index (tree i, tree args, int num_parms)
+fixup_template_parm_index (tree i, tree args, tree sibling_parms)
 {
-  tree index, decl, type;
+  tree index, decl, type, parent_idx = NULL_TREE;
 
   if (i == NULL_TREE
       || TREE_CODE (i) != TEMPLATE_PARM_INDEX
       /* Do not fix up the index twice.  */
-      || (TEMPLATE_PARM_NUM_SIBLINGS (i) != 0))
+      || (TEMPLATE_PARM_SIBLINGS (i) != NULL_TREE))
     return i;
 
   decl = TEMPLATE_PARM_DECL (i);
   type = TREE_TYPE (decl);
 
+  if (TEMPLATE_PARM_LEVEL (TEMPLATE_PARM_ORIG_INDEX (i))
+      != TEMPLATE_PARM_LEVEL (i))
+    /* We are fixing up a type which TEMPLATE_TYPE_PARM_INDEX is the
+       result or a level-reduction.  Keep a pointer to the original
+       upper (fixed-up) level.  */
+    parent_idx = TEMPLATE_PARM_ORIG_INDEX (i);
+
   index = build_template_parm_index (TEMPLATE_PARM_IDX (i),
 				     TEMPLATE_PARM_LEVEL (i),
-				     TEMPLATE_PARM_ORIG_LEVEL (i),
-				     num_parms,
+				     parent_idx, sibling_parms,
 				     decl, type);
 
   TEMPLATE_PARM_DESCENDANTS (index) = TEMPLATE_PARM_DESCENDANTS (i);
@@ -3758,11 +4139,15 @@ fixup_template_parm_index (tree i, tree args, int num_parms)
   TREE_TYPE (decl) = type;
   TREE_TYPE (index) = type;
 
+  /* Update descendants of the original index INDEX is reduced
+     from.  */
+  add_descendant_to_parm_index (TEMPLATE_PARM_ORIG_INDEX (index),
+				index);
   return index;
 }
 
 /* 
-   This is a subroutine of fixup_template_parms.
+   This is a subroutine of fixup_innermost_template_parms.
 
    It computes the canonical type of the type of the template
    parameter PARM_DESC and update all references to that type so that
@@ -3770,8 +4155,8 @@ fixup_template_parm_index (tree i, tree args, int num_parms)
    performed during the fixup. PARM_DESC is a TREE_LIST which
    TREE_VALUE is the template parameter and its TREE_PURPOSE is the
    default argument of the template parm if any. IDX is the index of
-   the template parameter, starting at 0. NUM_PARMS is the number of
-   template parameters in the set PARM_DESC belongs to. ARGLIST is a
+   the template parameter, starting at 0. SIBLING_PARMS is the set of
+   template parameters the PARM_DESC belongs to. ARGLIST is a
    TREE_VEC containing the full set of template parameters in a form
    suitable to be passed to substs functions as their ARGS
    argument. This is what current_template_args returns for a given
@@ -3782,11 +4167,18 @@ fixup_template_parm_index (tree i, tree args, int num_parms)
 static void
 fixup_template_parm (tree parm_desc,
 		     int idx,
-		     int num_parms,
+		     tree sibling_parms,
 		     tree arglist)
 {
   tree parm = TREE_VALUE (parm_desc);
-  tree fixedup_args = INNERMOST_TEMPLATE_ARGS (arglist);
+  tree fixedup_args;
+  int level;
+
+  if (parm == error_mark_node)
+    return;
+
+  get_template_parameter_level_and_index (parm, &level, NULL);
+  fixedup_args = TMPL_ARGS_LEVEL (arglist, level);
 
   push_deferring_access_checks (dk_no_check);
 
@@ -3798,7 +4190,7 @@ fixup_template_parm (tree parm_desc,
 	 template parms into the default argument of this
 	 parameter.  */
       tree t =
-	fixup_template_type_parm_type (TREE_TYPE (parm), num_parms);
+	fixup_template_type_parm_type (TREE_TYPE (parm), sibling_parms);
       TREE_TYPE (parm) = t;
 
       TREE_VEC_ELT (fixedup_args, idx) = template_parm_to_arg (parm_desc);
@@ -3852,13 +4244,12 @@ fixup_template_parm (tree parm_desc,
 	    template_parm_to_arg (parameter);
 
 	  fixup_template_parm (parameter, j,
-			       TREE_VEC_LENGTH (tparms),
-			       targs);
+			       tparms, targs);
 	}
 
       /* Now fix up the type of the template template parm.  */
 
-      t = fixup_template_type_parm_type (TREE_TYPE (parm), num_parms);
+      t = fixup_template_type_parm_type (TREE_TYPE (parm), sibling_parms);
       TREE_TYPE (parm) = t;
 
       TREE_VEC_ELT (fixedup_args, idx) =
@@ -3898,7 +4289,7 @@ fixup_template_parm (tree parm_desc,
 	 fixup the type of PUSHED_DECL as well and luckily
 	 fixup_template_parm_index does it for us too.  */
       tree fixed_up_index =
-	fixup_template_parm_index (index, arglist, num_parms);
+	fixup_template_parm_index (index, arglist, sibling_parms);
 
       DECL_INITIAL (pushed_decl) = DECL_INITIAL (parm) = fixed_up_index;
 
@@ -3918,39 +4309,99 @@ fixup_template_parm (tree parm_desc,
   pop_deferring_access_checks ();
 }
 
-/* Walk the current template parms and properly compute the canonical
-   types of the dependent types created during
-   cp_parser_template_parameter_list.  */
+/* Walk the innermost template parameters of PARMS parms and properly
+   compute the canonical types of the dependent types created during
+   cp_parser_template_parameter_list.  ARGLIST contains a TREE_VEC of
+   arguments built from the elements of PARMS that have been fixed-up
+   so far.  This function  udpates ARGLIST as it runs.  If the caller
+   of this function  is not interested in getting ARGLIST, it can
+   set it to NULL_TREE.  */
 
-void
-fixup_template_parms (void)
+static void
+fixup_innermost_template_parms (tree parms, tree arglist)
 {
-  tree arglist;
   tree parameter_vec;
-  tree fixedup_args;
   int i, num_parms;
 
-  parameter_vec = INNERMOST_TEMPLATE_PARMS (current_template_parms);
+  if (parms == NULL_TREE || parms == error_mark_node)
+    return;
+
+  parameter_vec = INNERMOST_TEMPLATE_PARMS (parms);
   if (parameter_vec == NULL_TREE)
     return;
 
   num_parms = TREE_VEC_LENGTH (parameter_vec);
 
-  /* This vector contains the current innermost template parms that
-     have been fixed up so far.  The form of FIXEDUP_ARGS is suitable
-     to be passed to tsubst* functions as their ARGS argument.  */
-  fixedup_args = make_tree_vec (num_parms);
-
   /* This vector contains the full set of template parms in a form
      suitable to be passed to substs functions as their ARGS
      argument.  */
-  arglist = current_template_args ();
-  arglist = add_outermost_template_args (arglist, fixedup_args);
+  if (arglist == NULL_TREE)
+    {
+      tree fixedup_args;
+      arglist = template_parms_to_args (parms);
+      /* This vector contains the current innermost template parms
+	 that have been fixed up so far.  The form of ARGLIST is
+	 suitable to be passed to tsubst* functions as their ARGS
+	 argument.  */
+      fixedup_args = make_tree_vec (num_parms);
+      arglist = add_outermost_template_args (arglist, fixedup_args);
+    }
 
   /* Let's do the proper fixup now.  */
   for (i = 0; i < num_parms; ++i)
     fixup_template_parm (TREE_VEC_ELT (parameter_vec, i),
-			 i, num_parms, arglist);
+			 i, parameter_vec, arglist);
+}
+
+/*  Fixup the template parameters PARMS; that is, compute the
+    canonical types of each parameter therein.
+
+    Note that PARMS must be of the form described in the comments of
+    the DECL_TEMPLATE_PARMS accessor in cp-tree.h.  */
+
+void
+fixup_template_parms (tree parms)
+{
+  tree level, args;
+  int i;
+
+  if (parms == NULL_TREE || parms == error_mark_node)
+    return;
+
+
+  if (TMPL_PARMS_DEPTH (parms) > 1)
+    {
+      int parms_depth = TMPL_PARMS_DEPTH (parms);
+      args = make_tree_vec (parms_depth);
+      for (i = 0; i < parms_depth; ++i)
+	{
+	  level = get_template_parms_at_level (parms, i + 1);
+	  if (level == NULL_TREE)
+	    continue;
+	  TREE_VEC_ELT (args, i) =
+	    make_tree_vec (TREE_VEC_LENGTH (TREE_VALUE (level)));
+	}
+    }
+  else
+    args = make_tree_vec (TREE_VEC_LENGTH (TREE_VALUE (parms)));
+
+  /* Template parms ought to be fixed-up from left to right.  */
+  parms = nreverse (parms);
+
+  for (level = parms; level != NULL_TREE; level = TREE_CHAIN (level))
+    fixup_innermost_template_parms (level, args);
+
+  parms = nreverse (parms);
+}
+
+/* Walk the current template parms and properly compute the canonical
+   types of the dependent types created during
+   cp_parser_template_parameter_list.  */
+
+void
+fixup_current_template_parms (void)
+{
+  fixup_innermost_template_parms (current_template_parms, NULL_TREE);
 }
 
 /* end_template_decl is called after a template declaration is seen.  */
@@ -4032,6 +4483,60 @@ template_parm_to_arg (tree t)
   return t;
 }
 
+/*  Transform a template parameter into an argument, suitable to be
+    passed to tsubst as an element of its ARGS parameter.  */
+
+static tree
+template_parms_to_args (tree parms)
+{
+  tree header;
+  tree args = NULL_TREE;
+  int length = TMPL_PARMS_DEPTH (parms);
+  int l = length;
+
+  /* If there is only one level of template parameters, we do not
+     create a TREE_VEC of TREE_VECs.  Instead, we return a single
+     TREE_VEC containing the arguments.  */
+  if (length > 1)
+    args = make_tree_vec (length);
+
+  for (header = parms; header; header = TREE_CHAIN (header))
+    {
+      tree a = copy_node (TREE_VALUE (header));
+      int i;
+
+      TREE_TYPE (a) = NULL_TREE;
+      for (i = TREE_VEC_LENGTH (a) - 1; i >= 0; --i)
+	TREE_VEC_ELT (a, i) = template_parm_to_arg (TREE_VEC_ELT (a, i));
+
+#ifdef ENABLE_CHECKING
+      SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (a, TREE_VEC_LENGTH (a));
+#endif
+
+      if (length > 1)
+	TREE_VEC_ELT (args, --l) = a;
+      else
+	args = a;
+    }
+
+    if (length > 1 && TREE_VEC_ELT (args, 0) == NULL_TREE)
+      /* This can happen for template parms of a template template
+	 parameter, e.g:
+
+	 template<template<class T, class U> class TT> struct S;
+
+	 Consider the level of the parms of TT; T and U both have
+	 level 2; TT has no template parm of level 1. So in this case
+	 the first element of full_template_args is NULL_TREE. If we
+	 leave it like this TMPL_ARG_DEPTH on args returns 1 instead
+	 of 2. This will make tsubst wrongly consider that T and U
+	 have level 1. Instead, let's create a dummy vector as the
+	 first element of full_template_args so that TMPL_ARG_DEPTH
+	 returns the correct depth for args.  */
+      TREE_VEC_ELT (args, 0) = make_tree_vec (1);
+  return args;
+}
+
 /* This function returns TRUE if PARM_PACK is a template parameter
    pack and if ARG_PACK is what template_parm_to_arg returned when
    passed PARM_PACK.  */
@@ -4089,60 +4594,92 @@ arg_from_parm_pack_p (tree arg_pack, tree parm_pack)
   return false;
 }
 
-/* Within the declaration of a template, return all levels of template
-   parameters that apply.  The template parameters are represented as
-   a TREE_VEC, in the form documented in cp-tree.h for template
-   arguments.  */
-
-static tree
-current_template_args (void)
-{
-  tree header;
-  tree args = NULL_TREE;
-  int length = TMPL_PARMS_DEPTH (current_template_parms);
-  int l = length;
+/* When a template parameter PARM_PACK is a pack that is part of a
+   pack expansion EXPANSION and when EXPANSION has been partially
+   instantiated (or rather substituted into) with a set of arguments
+   ARGS0 which depth is less than the level of PARM_PACK, the level of
+   PARM_PACK is not reduced, unlike what happens for a non-pack
+   template parameter.
+
+   Rather, EXPANSION remembers ARGS0 and later, when an attempt to
+   instantiate EXPANSION with a set of arguments ARGS1 which is so
+   that the set {ARGS0, ARGS1} is deep enough to fully instantiate
+   EXPANSION, EXPANSION is substituted into with the arguments {ARGS0,
+   ARGS1}.
+
+   So in the time interval between when EXPANSION remembers ARGS0 and
+   when it gets ARGS1, the level of E stays the same, even if it has
+   been morally reduced.  If the type fixup of E happens in that time
+   interval, we'll need to be able to detect that ARG_PACK is the
+   result of template_parm_to_arg called on PARM_PACK' - which is the result
+   of morally reducing the level of PARM_PACK and fixing up its
+   type.
+
+   Note that because of the complication that arises due to the way
+   pack expansions handle partial instantiations of parameter packs,
+   arg_from_parm_pack_p won't work on arg_pack and parm_pack.
+
+   This function should thus return true if ARG_PACK is the result of
+     1/ morally level-reducing parameter pack PARM_PACK
+     2/ fixing-up the result of 1/
+     3/ passing the result 2/ to template_parm_to_arg.
+
+   FIXME: This function does an approximation, as it only checks that
+   the levels of PARM_PACK/EXPANSION and ARG_PACK do match.  For it to
+   be precise, I think the TEMPLATE_PARM_INDEX of PARM_PACK should
+   track its pre-fixup type, so that ARG_PACK could be compared with
+   that type instead.  But that would increase the size of the
+   template_parm_index_s struct, as I don't see where else I could
+   store the pre-fixup type.  */
 
-  /* If there is only one level of template parameters, we do not
-     create a TREE_VEC of TREE_VECs.  Instead, we return a single
-     TREE_VEC containing the arguments.  */
-  if (length > 1)
-    args = make_tree_vec (length);
+static bool
+arg_from_reduced_and_fixedup_parm_pack_of_expansion_p (tree arg_pack,
+						       tree parm_pack,
+						       tree expansion)
+{
+  /* We want parm_pack to be a type or non-type parameter pack.  */
+  if (parm_pack == NULL_TREE
+      || (!template_type_parameter_type_p (parm_pack)
+	  && !(DECL_P (parm_pack) && DECL_TEMPLATE_PARM_P (parm_pack))
+	  && TREE_CODE (parm_pack) != TEMPLATE_PARM_INDEX))
+    return false;
 
-  for (header = current_template_parms; header; header = TREE_CHAIN (header))
+  if (arg_pack
+      && TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack)) == 1
+      && PACK_EXPANSION_P (TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack), 0)))
     {
-      tree a = copy_node (TREE_VALUE (header));
-      int i;
+      tree e = TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack), 0);
+      tree p = PACK_EXPANSION_PATTERN (e);
+      tree extra_args = PACK_EXPANSION_EXTRA_ARGS (expansion);
+      tree index_p, index_parm_pack;
+      int extra_args_depth = extra_args ? TMPL_ARGS_DEPTH (extra_args) : 0;
 
-      TREE_TYPE (a) = NULL_TREE;
-      for (i = TREE_VEC_LENGTH (a) - 1; i >= 0; --i)
-	TREE_VEC_ELT (a, i) = template_parm_to_arg (TREE_VEC_ELT (a, i));
+      if (TREE_CODE (p) != TREE_CODE (parm_pack))
+	return false;
 
-#ifdef ENABLE_CHECKING
-      SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (a, TREE_VEC_LENGTH (a));
-#endif
+      index_p = get_template_parm_index (p);
+      index_parm_pack = get_template_parm_index (parm_pack);
 
-      if (length > 1)
-	TREE_VEC_ELT (args, --l) = a;
-      else
-	args = a;
+      if (extra_args_depth != 0
+	  && (TEMPLATE_PARM_LEVEL (index_p)
+	      == TEMPLATE_PARM_LEVEL (index_parm_pack) - extra_args_depth)
+	  && (TEMPLATE_PARM_IDX (index_p)
+	      == TEMPLATE_PARM_IDX (index_parm_pack)))
+	return true;
     }
 
-    if (length > 1 && TREE_VEC_ELT (args, 0) == NULL_TREE)
-      /* This can happen for template parms of a template template
-	 parameter, e.g:
+  return false;
+}
 
-	 template<template<class T, class U> class TT> struct S;
+/* Within the declaration of a template, return all levels of template
+   parameters that apply.  The template parameters are represented as
+   a TREE_VEC, in the form documented in cp-tree.h for template
+   arguments.  */
 
-	 Consider the level of the parms of TT; T and U both have
-	 level 2; TT has no template parm of level 1. So in this case
-	 the first element of full_template_args is NULL_TREE. If we
-	 leave it like this TMPL_ARG_DEPTH on args returns 1 instead
-	 of 2. This will make tsubst wrongly consider that T and U
-	 have level 1. Instead, let's create a dummy vector as the
-	 first element of full_template_args so that TMPL_ARG_DEPTH
-	 returns the correct depth for args.  */
-      TREE_VEC_ELT (args, 0) = make_tree_vec (1);
-  return args;
+static tree
+current_template_args (void)
+{
+  return template_parms_to_args (current_template_parms);
 }
 
 /* Update the declared TYPE by doing any lookups which were thought to be
@@ -4851,6 +5388,8 @@ push_template_decl_real (tree decl, bool is_friend)
 	       && TYPE_DECL_ALIAS_P (decl))
 	/* alias-declaration */
 	gcc_assert (!DECL_ARTIFICIAL (decl));
+      else if (is_friend && TREE_CODE (TREE_TYPE (decl)) == TYPENAME_TYPE)
+	/* OK */;
       else
 	{
 	  error ("template declaration of %q#D", decl);
@@ -4917,7 +5456,8 @@ push_template_decl_real (tree decl, bool is_friend)
   if (!ctx
       || TREE_CODE (ctx) == FUNCTION_DECL
       || (CLASS_TYPE_P (ctx) && TYPE_BEING_DEFINED (ctx))
-      || (is_friend && !DECL_TEMPLATE_INFO (decl)))
+      || (is_friend && (!DECL_LANG_SPECIFIC (decl)
+			|| !DECL_TEMPLATE_INFO (decl))))
     {
       if (DECL_LANG_SPECIFIC (decl)
 	  && DECL_TEMPLATE_INFO (decl)
@@ -5120,7 +5660,7 @@ template arguments to %qD do not match original template %qD",
     SET_TYPE_TEMPLATE_INFO (TREE_TYPE (tmpl), info);
   else
     {
-      if (primary && !DECL_LANG_SPECIFIC (decl))
+      if ((primary || is_friend) && !DECL_LANG_SPECIFIC (decl))
 	retrofit_lang_decl (decl);
       if (DECL_LANG_SPECIFIC (decl))
 	DECL_TEMPLATE_INFO (decl) = info;
@@ -6909,10 +7449,12 @@ coerce_template_parms (tree parms,
   return new_inner_args;
 }
 
-/* Returns 1 if template args OT and NT are equivalent.  */
+/* Returns 1 if template args OT and NT are equivalent.  STRICT
+   controls how the comparison is done, with the same semantics as
+   for the last parameter of comptypes.  */
 
 static int
-template_args_equal (tree ot, tree nt)
+template_args_equal_guided (tree ot, tree nt, int strict)
 {
   if (nt == ot)
     return 1;
@@ -6921,13 +7463,16 @@ template_args_equal (tree ot, tree nt)
 
   if (TREE_CODE (nt) == TREE_VEC)
     /* For member templates */
-    return TREE_CODE (ot) == TREE_VEC && comp_template_args (ot, nt);
+    return (TREE_CODE (ot) == TREE_VEC
+	    && comp_template_args_guided (ot, nt, NULL, NULL, strict));
   else if (PACK_EXPANSION_P (ot))
     return (PACK_EXPANSION_P (nt)
-	    && template_args_equal (PACK_EXPANSION_PATTERN (ot),
-				    PACK_EXPANSION_PATTERN (nt))
-	    && template_args_equal (PACK_EXPANSION_EXTRA_ARGS (ot),
-				    PACK_EXPANSION_EXTRA_ARGS (nt)));
+	    && template_args_equal_guided (PACK_EXPANSION_PATTERN (ot),
+					   PACK_EXPANSION_PATTERN (nt),
+					   strict)
+	    && template_args_equal_guided (PACK_EXPANSION_EXTRA_ARGS (ot),
+					   PACK_EXPANSION_EXTRA_ARGS (nt),
+					   strict));
   else if (ARGUMENT_PACK_P (ot))
     {
       int i, len;
@@ -6942,8 +7487,9 @@ template_args_equal (tree ot, tree nt)
       if (TREE_VEC_LENGTH (npack) != len)
 	return 0;
       for (i = 0; i < len; ++i)
-	if (!template_args_equal (TREE_VEC_ELT (opack, i),
-				  TREE_VEC_ELT (npack, i)))
+	if (!template_args_equal_guided (TREE_VEC_ELT (opack, i),
+					 TREE_VEC_ELT (npack, i),
+					 strict))
 	  return 0;
       return 1;
     }
@@ -6957,23 +7503,32 @@ template_args_equal (tree ot, tree nt)
       ot = ARGUMENT_PACK_SELECT_FROM_PACK (ot);
       if (nt && TREE_CODE (nt) == ARGUMENT_PACK_SELECT)
 	nt = ARGUMENT_PACK_SELECT_FROM_PACK (nt);
-      return template_args_equal (ot, nt);
+      return template_args_equal_guided (ot, nt, strict);
     }
   else if (TYPE_P (nt))
-    return TYPE_P (ot) && same_type_p (ot, nt);
+    return TYPE_P (ot) && comptypes (ot, nt, strict);
   else if (TREE_CODE (ot) == TREE_VEC || TYPE_P (ot))
     return 0;
   else
     return cp_tree_equal (ot, nt);
 }
 
+/* Returns 1 if template args OT and NT are equivalent.  */
+
+static int
+template_args_equal (tree ot, tree nt)
+{
+  return template_args_equal_guided (ot, nt, COMPARE_STRICT);
+}
+
 /* Returns 1 iff the OLDARGS and NEWARGS are in fact identical sets of
    template arguments.  Returns 0 otherwise, and updates OLDARG_PTR and
    NEWARG_PTR with the offending arguments if they are non-NULL.  */
 
-static int
-comp_template_args_with_info (tree oldargs, tree newargs,
-			      tree *oldarg_ptr, tree *newarg_ptr)
+int
+comp_template_args_guided (tree oldargs, tree newargs,
+			   tree *oldarg_ptr, tree *newarg_ptr,
+			   int strict)
 {
   int i;
 
@@ -6991,7 +7546,7 @@ comp_template_args_with_info (tree oldargs, tree newargs,
       tree nt = TREE_VEC_ELT (newargs, i);
       tree ot = TREE_VEC_ELT (oldargs, i);
 
-      if (! template_args_equal (ot, nt))
+      if (! template_args_equal_guided (ot, nt, strict))
 	{
 	  if (oldarg_ptr != NULL)
 	    *oldarg_ptr = ot;
@@ -7009,7 +7564,8 @@ comp_template_args_with_info (tree oldargs, tree newargs,
 int
 comp_template_args (tree oldargs, tree newargs)
 {
-  return comp_template_args_with_info (oldargs, newargs, NULL, NULL);
+  return comp_template_args_guided (oldargs, newargs,
+				    NULL, NULL, COMPARE_STRICT);
 }
 
 static void
@@ -8854,6 +9410,18 @@ instantiate_class_template_1 (tree type)
        member; member = TREE_CHAIN (member))
     {
       tree t = TREE_VALUE (member);
+      tree tinfo = get_template_info (t);
+
+      if (tinfo && TREE_CODE (TI_TEMPLATE (tinfo)) == TEMPLATE_DECL)
+	{
+	  ++processing_template_decl;
+	  /* prepare possible partial instantiation of member
+	     template by fixing-up template parms which level are
+	     going to be reduced by the partial instantiation.  */
+	  tsubst_template_parms (DECL_TEMPLATE_PARMS (TI_TEMPLATE (tinfo)),
+				 args, tf_none);
+	  --processing_template_decl;
+	}
 
       if (TREE_PURPOSE (member))
 	{
@@ -9362,7 +9930,10 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
 	  return result;
 	}
 
-      if (arg_from_parm_pack_p (arg_pack, parm_pack))
+      if (arg_from_parm_pack_p (arg_pack, parm_pack)
+	  || arg_from_reduced_and_fixedup_parm_pack_of_expansion_p (arg_pack,
+								    parm_pack,
+								    t))
 	/* The argument pack that the parameter maps to is just an
 	   expansion of the parameter itself, such as one would find
 	   in the implicit typedef of a class inside the class itself.
@@ -9716,7 +10287,14 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl)
    PARMS, then the result will contain n levels of PARMS.  For
    example, if PARMS is `template <class T> template <class U>
    template <T*, U, class V>' and ARGS is {{int}, {double}} then the
-   result will be `template <int*, double, class V>'.  */
+   result will be `template <int*, double, class V>'.
+
+   If the depth of ARGS is less than the depth of PARMS, it most
+   probably means we are looking at the partial instantiation of a
+   member template.  This implies that the resulting set of template
+   parms is going to be level-reduced.  In that case, this function
+   does the proper type fixing-up of the reduced template
+   parameters.  */
 
 static tree
 tsubst_template_parms (tree parms, tree args, tsubst_flags_t complain)
@@ -9724,6 +10302,9 @@ tsubst_template_parms (tree parms, tree args, tsubst_flags_t complain)
   tree r = NULL_TREE;
   tree* new_parms;
 
+  if (parms == NULL_TREE || parms == error_mark_node)
+    return parms;
+
   /* When substituting into a template, we must set
      PROCESSING_TEMPLATE_DECL as the template parameters may be
      dependent if they are based on one-another, and the dependency
@@ -9761,6 +10342,7 @@ tsubst_template_parms (tree parms, tree args, tsubst_flags_t complain)
 		   new_vec, NULL_TREE);
     }
 
+  fixup_template_parms (r);
   --processing_template_decl;
 
   return r;
@@ -9829,6 +10411,12 @@ tsubst_aggr_type (tree t,
 	  int saved_unevaluated_operand;
 	  int saved_inhibit_evaluation_warnings;
 
+	  /* If T is a member template being partially instantiated,
+	     fixup its template parameters that are to be
+	     level-reduced.  */
+	  tsubst_template_parms (DECL_TEMPLATE_PARMS (TYPE_TI_TEMPLATE (t)),
+				 args, complain);
+
 	  /* In "sizeof(X<I>)" we need to evaluate "I".  */
 	  saved_unevaluated_operand = cp_unevaluated_operand;
 	  cp_unevaluated_operand = 0;
@@ -9998,6 +10586,15 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	tree spec;
 	tree tmpl_args;
 	tree full_args;
+	tree fixedup_parms;
+
+	/* If T is a member template being partially instantiated,
+	   fixup its template parameters that are to be
+	   level-reduced.  */
+	++processing_template_decl;
+	fixedup_parms = tsubst_template_parms (DECL_TEMPLATE_PARMS (t),
+					       args, complain);
+	--processing_template_decl;
 
 	if (DECL_TEMPLATE_TEMPLATE_PARM_P (t))
 	  {
@@ -10073,6 +10670,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 
 	    TREE_TYPE (r) = new_type;
 	    CLASSTYPE_TI_TEMPLATE (new_type) = r;
+	    DECL_TEMPLATE_PARMS (r) = fixedup_parms;
 	    DECL_TEMPLATE_RESULT (r) = TYPE_MAIN_DECL (new_type);
 	    DECL_TI_ARGS (r) = CLASSTYPE_TI_ARGS (new_type);
 	    DECL_CONTEXT (r) = TYPE_CONTEXT (new_type);
@@ -10088,6 +10686,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 
 	    DECL_TEMPLATE_RESULT (r) = new_decl;
 	    DECL_TI_TEMPLATE (new_decl) = r;
+	    DECL_TEMPLATE_PARMS (r) = fixedup_parms;
 	    TREE_TYPE (r) = TREE_TYPE (new_decl);
 	    DECL_TI_ARGS (r) = DECL_TI_ARGS (new_decl);
 	    DECL_CONTEXT (r) = DECL_CONTEXT (new_decl);
@@ -10097,13 +10696,6 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	DECL_TEMPLATE_INSTANTIATIONS (r) = NULL_TREE;
 	DECL_TEMPLATE_SPECIALIZATIONS (r) = NULL_TREE;
 
-	/* The template parameters for this new template are all the
-	   template parameters for the old template, except the
-	   outermost level of parameters.  */
-	DECL_TEMPLATE_PARMS (r)
-	  = tsubst_template_parms (DECL_TEMPLATE_PARMS (t), args,
-				   complain);
-
 	if (PRIMARY_TEMPLATE_P (t))
 	  DECL_PRIMARY_TEMPLATE (r) = r;
 
@@ -11711,16 +12303,19 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 
     case UNBOUND_CLASS_TEMPLATE:
       {
+	/* If T is a member template being partially instantiated,
+	   fixup its template parmeters that are to be level-reduced,
+	   upfront.  */
+	tree parm_list =
+	  tsubst_template_parms (DECL_TEMPLATE_PARMS (TYPE_NAME (t)),
+				 args, complain);
 	tree ctx = tsubst_aggr_type (TYPE_CONTEXT (t), args, complain,
 				     in_decl, /*entering_scope=*/1);
 	tree name = TYPE_IDENTIFIER (t);
-	tree parm_list = DECL_TEMPLATE_PARMS (TYPE_NAME (t));
 
 	if (ctx == error_mark_node || name == error_mark_node)
 	  return error_mark_node;
 
-	if (parm_list)
-	  parm_list = tsubst_template_parms (parm_list, args, complain);
 	return make_unbound_class_template (ctx, name, parm_list, complain);
       }
 
@@ -16077,8 +16672,9 @@ unify_pack_expansion (tree tparms, tree targs, tree packed_parms,
 	  tree bad_old_arg = NULL_TREE, bad_new_arg = NULL_TREE;
 	  tree old_args = ARGUMENT_PACK_ARGS (old_pack);
 
-	  if (!comp_template_args_with_info (old_args, new_args,
-					     &bad_old_arg, &bad_new_arg))
+	  if (!comp_template_args_guided (old_args, new_args,
+					  &bad_old_arg, &bad_new_arg,
+					  COMPARE_STRICT))
 	    /* Inconsistent unification of this parameter pack.  */
 	    return unify_parameter_pack_inconsistent (explain_p,
 						      bad_old_arg,
@@ -19066,15 +19662,13 @@ get_mostly_instantiated_function_type (tree decl)
       int i;
       tree partial_args;
 
-      /* Replace the innermost level of the TARGS with NULL_TREEs to
-	 let tsubst know not to substitute for those parameters.  */
-      partial_args = make_tree_vec (TREE_VEC_LENGTH (targs));
+      /* Copy all but the innermost level of the TARGS to let tsubst
+	 below know not to substitute for those parameters and
+	 properly perform the partial substituting of fn_type.  */
+      partial_args = make_tree_vec (TREE_VEC_LENGTH (targs) - 1);
       for (i = 1; i < TMPL_ARGS_DEPTH (targs); ++i)
 	SET_TMPL_ARGS_LEVEL (partial_args, i,
 			     TMPL_ARGS_LEVEL (targs, i));
-      SET_TMPL_ARGS_LEVEL (partial_args,
-			   TMPL_ARGS_DEPTH (targs),
-			   make_tree_vec (DECL_NTPARMS (tmpl)));
 
       /* Make sure that we can see identifiers, and compute access
 	 correctly.  */
@@ -19090,7 +19684,6 @@ get_mostly_instantiated_function_type (tree decl)
 	 innermost set of parameters.  This step is important if the
 	 innermost set of template parameters contains value
 	 parameters whose types depend on outer template parameters.  */
-      TREE_VEC_LENGTH (partial_args)--;
       tparms = tsubst_template_parms (tparms, partial_args, tf_error);
 
       pop_access_scope (decl);
@@ -20214,7 +20807,7 @@ make_auto (void)
 			       TYPE_DECL, get_identifier ("auto"), au);
   TYPE_STUB_DECL (au) = TYPE_NAME (au);
   TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index
-    (0, processing_template_decl + 1, processing_template_decl + 1,
+    (0, processing_template_decl + 1, NULL_TREE,
      0, TYPE_NAME (au), NULL_TREE);
   TYPE_CANONICAL (au) = canonical_type_parameter (au);
   DECL_ARTIFICIAL (TYPE_NAME (au)) = 1;
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index b80b52a..04bdedd 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2178,7 +2178,7 @@ decl_anon_ns_mem_p (const_tree decl)
    CALL_EXPRS.  Return whether they are equivalent.  */
 
 static bool
-called_fns_equal (tree t1, tree t2)
+called_fns_equal (tree t1, tree t2, int strict)
 {
   /* Core 1321: dependent names are equivalent even if the overload sets
      are different.  But do compare explicit template arguments.  */
@@ -2195,17 +2195,21 @@ called_fns_equal (tree t1, tree t2)
 	targs1 = TREE_OPERAND (t1, 1);
       if (TREE_CODE (t2) == TEMPLATE_ID_EXPR)
 	targs2 = TREE_OPERAND (t2, 1);
-      return cp_tree_equal (targs1, targs2);
+      return compare_trees (targs1, targs2, strict);
     }
   else
     return cp_tree_equal (t1, t2);
 }
 
 /* Return truthvalue of whether T1 is the same tree structure as T2.
-   Return 1 if they are the same. Return 0 if they are different.  */
+   STRICT controls how the comparison is done, with the same semantics
+   as the for the last parameter of comptypes.  Please make sure that
+   any type or tree comparison function used in this function is a
+   variant that takes this STRICT parameter.  Return 1 if they are the
+   same. Return 0 if they are different.  */
 
 bool
-cp_tree_equal (tree t1, tree t2)
+compare_trees (tree t1, tree t2, int strict)
 {
   enum tree_code code1, code2;
 
@@ -2251,14 +2255,14 @@ cp_tree_equal (tree t1, tree t2)
 				     TREE_FIXED_CST (t2));
 
     case COMPLEX_CST:
-      return cp_tree_equal (TREE_REALPART (t1), TREE_REALPART (t2))
-	&& cp_tree_equal (TREE_IMAGPART (t1), TREE_IMAGPART (t2));
+      return compare_trees (TREE_REALPART (t1), TREE_REALPART (t2), strict)
+	&& compare_trees (TREE_IMAGPART (t1), TREE_IMAGPART (t2), strict);
 
     case CONSTRUCTOR:
       /* We need to do this when determining whether or not two
 	 non-type pointer to member function template arguments
 	 are the same.  */
-      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))
+      if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict)
 	  || CONSTRUCTOR_NELTS (t1) != CONSTRUCTOR_NELTS (t2))
 	return false;
       {
@@ -2267,35 +2271,35 @@ cp_tree_equal (tree t1, tree t2)
 	FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t1), i, field, value)
 	  {
 	    constructor_elt *elt2 = CONSTRUCTOR_ELT (t2, i);
-	    if (!cp_tree_equal (field, elt2->index)
-		|| !cp_tree_equal (value, elt2->value))
+	    if (!compare_trees (field, elt2->index, strict)
+		|| !compare_trees (value, elt2->value, strict))
 	      return false;
 	  }
       }
       return true;
 
     case TREE_LIST:
-      if (!cp_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2)))
+      if (!compare_trees (TREE_PURPOSE (t1), TREE_PURPOSE (t2), strict))
 	return false;
-      if (!cp_tree_equal (TREE_VALUE (t1), TREE_VALUE (t2)))
+      if (!compare_trees (TREE_VALUE (t1), TREE_VALUE (t2), strict))
 	return false;
-      return cp_tree_equal (TREE_CHAIN (t1), TREE_CHAIN (t2));
+      return compare_trees (TREE_CHAIN (t1), TREE_CHAIN (t2), strict);
 
     case SAVE_EXPR:
-      return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+      return compare_trees (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0), strict);
 
     case CALL_EXPR:
       {
 	tree arg1, arg2;
 	call_expr_arg_iterator iter1, iter2;
-	if (!called_fns_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2)))
+	if (!called_fns_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2), strict))
 	  return false;
 	for (arg1 = first_call_expr_arg (t1, &iter1),
 	       arg2 = first_call_expr_arg (t2, &iter2);
 	     arg1 && arg2;
 	     arg1 = next_call_expr_arg (&iter1),
 	       arg2 = next_call_expr_arg (&iter2))
-	  if (!cp_tree_equal (arg1, arg2))
+	  if (!compare_trees (arg1, arg2, strict))
 	    return false;
 	if (arg1 || arg2)
 	  return false;
@@ -2317,28 +2321,30 @@ cp_tree_equal (tree t1, tree t2)
 	else if (TREE_CODE (o2) == VAR_DECL && DECL_NAME (o2) == NULL_TREE
 		 && !DECL_RTL_SET_P (o2))
 	  /*Nop*/;
-	else if (!cp_tree_equal (o1, o2))
+	else if (!compare_trees (o1, o2, strict))
 	  return false;
 
-	return cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
+	return compare_trees (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1),
+			      strict);
       }
 
     case WITH_CLEANUP_EXPR:
-      if (!cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)))
+      if (!compare_trees (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0), strict))
 	return false;
-      return cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t1, 1));
+      return compare_trees (TREE_OPERAND (t1, 1), TREE_OPERAND (t1, 1), strict);
 
     case COMPONENT_REF:
       if (TREE_OPERAND (t1, 1) != TREE_OPERAND (t2, 1))
 	return false;
-      return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+      return compare_trees (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0),
+			    strict);
 
     case PARM_DECL:
       /* For comparing uses of parameters in late-specified return types
 	 with an out-of-class definition of the function, but can also come
 	 up for expressions that involve 'this' in a member function
 	 template.  */
-      if (same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+      if (comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	{
 	  if (DECL_ARTIFICIAL (t1) ^ DECL_ARTIFICIAL (t2))
 	    return false;
@@ -2361,19 +2367,18 @@ cp_tree_equal (tree t1, tree t2)
       return (BASELINK_BINFO (t1) == BASELINK_BINFO (t2)
 	      && BASELINK_ACCESS_BINFO (t1) == BASELINK_ACCESS_BINFO (t2)
 	      && BASELINK_QUALIFIED_P (t1) == BASELINK_QUALIFIED_P (t2)
-	      && cp_tree_equal (BASELINK_FUNCTIONS (t1),
-				BASELINK_FUNCTIONS (t2)));
+	      && compare_trees (BASELINK_FUNCTIONS (t1),
+				BASELINK_FUNCTIONS (t2), strict));
 
     case TEMPLATE_PARM_INDEX:
-      if (TEMPLATE_PARM_NUM_SIBLINGS (t1)
-	  != TEMPLATE_PARM_NUM_SIBLINGS (t2))
+      if (!(TEMPLATE_PARM_IDX (t1) == TEMPLATE_PARM_IDX (t2)
+	    && TEMPLATE_PARM_LEVEL (t1) == TEMPLATE_PARM_LEVEL (t2)
+	    && (TEMPLATE_PARM_PARAMETER_PACK (t1)
+		== TEMPLATE_PARM_PARAMETER_PACK (t2))
+	    && comptypes (TREE_TYPE (TEMPLATE_PARM_DECL (t1)),
+			  TREE_TYPE (TEMPLATE_PARM_DECL (t2)), strict)))
 	return false;
-      return (TEMPLATE_PARM_IDX (t1) == TEMPLATE_PARM_IDX (t2)
-	      && TEMPLATE_PARM_LEVEL (t1) == TEMPLATE_PARM_LEVEL (t2)
-	      && (TEMPLATE_PARM_PARAMETER_PACK (t1)
-		  == TEMPLATE_PARM_PARAMETER_PACK (t2))
-	      && same_type_p (TREE_TYPE (TEMPLATE_PARM_DECL (t1)),
-			      TREE_TYPE (TEMPLATE_PARM_DECL (t2))));
+      return comp_template_parms_siblings (t1, t2, strict);
 
     case TEMPLATE_ID_EXPR:
       return (cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0))
@@ -2385,8 +2390,9 @@ cp_tree_equal (tree t1, tree t2)
 	if (TREE_VEC_LENGTH (t1) != TREE_VEC_LENGTH (t2))
 	  return false;
 	for (ix = TREE_VEC_LENGTH (t1); ix--;)
-	  if (!cp_tree_equal (TREE_VEC_ELT (t1, ix),
-			      TREE_VEC_ELT (t2, ix)))
+	  if (!compare_trees (TREE_VEC_ELT (t1, ix),
+			      TREE_VEC_ELT (t2, ix),
+			      strict))
 	    return false;
 	return true;
       }
@@ -2400,16 +2406,17 @@ cp_tree_equal (tree t1, tree t2)
 	if (TREE_CODE (o1) != TREE_CODE (o2))
 	  return false;
 	if (TYPE_P (o1))
-	  return same_type_p (o1, o2);
+	  return comptypes (o1, o2, strict);
 	else
-	  return cp_tree_equal (o1, o2);
+	  return compare_trees (o1, o2, strict);
       }
 
     case MODOP_EXPR:
       {
 	tree t1_op1, t2_op1;
 
-	if (!cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)))
+	if (!compare_trees (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0),
+			    strict))
 	  return false;
 
 	t1_op1 = TREE_OPERAND (t1, 1);
@@ -2417,7 +2424,7 @@ cp_tree_equal (tree t1, tree t2)
 	if (TREE_CODE (t1_op1) != TREE_CODE (t2_op1))
 	  return false;
 
-	return cp_tree_equal (TREE_OPERAND (t1, 2), TREE_OPERAND (t2, 2));
+	return compare_trees (TREE_OPERAND (t1, 2), TREE_OPERAND (t2, 2), strict);
       }
 
     case PTRMEM_CST:
@@ -2426,18 +2433,18 @@ cp_tree_equal (tree t1, tree t2)
       if (PTRMEM_CST_MEMBER (t1) != PTRMEM_CST_MEMBER (t2))
 	return false;
 
-      return same_type_p (PTRMEM_CST_CLASS (t1), PTRMEM_CST_CLASS (t2));
+      return comptypes (PTRMEM_CST_CLASS (t1), PTRMEM_CST_CLASS (t2), strict);
 
     case OVERLOAD:
       if (OVL_FUNCTION (t1) != OVL_FUNCTION (t2))
 	return false;
-      return cp_tree_equal (OVL_CHAIN (t1), OVL_CHAIN (t2));
+      return compare_trees (OVL_CHAIN (t1), OVL_CHAIN (t2), strict);
 
     case TRAIT_EXPR:
       if (TRAIT_EXPR_KIND (t1) != TRAIT_EXPR_KIND (t2))
 	return false;
-      return same_type_p (TRAIT_EXPR_TYPE1 (t1), TRAIT_EXPR_TYPE1 (t2))
-	&& same_type_p (TRAIT_EXPR_TYPE2 (t1), TRAIT_EXPR_TYPE2 (t2));
+      return comptypes (TRAIT_EXPR_TYPE1 (t1), TRAIT_EXPR_TYPE1 (t2), strict)
+	&& comptypes (TRAIT_EXPR_TYPE2 (t1), TRAIT_EXPR_TYPE2 (t2), strict);
 
     case CAST_EXPR:
     case STATIC_CAST_EXPR:
@@ -2446,16 +2453,18 @@ cp_tree_equal (tree t1, tree t2)
     case DYNAMIC_CAST_EXPR:
     case IMPLICIT_CONV_EXPR:
     case NEW_EXPR:
-      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+      if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	return false;
       /* Now compare operands as usual.  */
       break;
 
     case DEFERRED_NOEXCEPT:
-      return (cp_tree_equal (DEFERRED_NOEXCEPT_PATTERN (t1),
-			     DEFERRED_NOEXCEPT_PATTERN (t2))
-	      && comp_template_args (DEFERRED_NOEXCEPT_ARGS (t1),
-				     DEFERRED_NOEXCEPT_ARGS (t2)));
+      return (compare_trees (DEFERRED_NOEXCEPT_PATTERN (t1),
+			     DEFERRED_NOEXCEPT_PATTERN (t2),
+			     strict)
+	      && comp_template_args_guided (DEFERRED_NOEXCEPT_ARGS (t1),
+					    DEFERRED_NOEXCEPT_ARGS (t2),
+					    NULL, NULL, strict));
       break;
 
     default:
@@ -2480,14 +2489,15 @@ cp_tree_equal (tree t1, tree t2)
 	  return false;
 
 	for (i = 0; i < n; ++i)
-	  if (!cp_tree_equal (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i)))
+	  if (!compare_trees (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i),
+			      strict))
 	    return false;
 
 	return true;
       }
 
     case tcc_type:
-      return same_type_p (t1, t2);
+      return comptypes (t1, t2, strict);
     default:
       gcc_unreachable ();
     }
@@ -2495,6 +2505,15 @@ cp_tree_equal (tree t1, tree t2)
   return false;
 }
 
+/* Return truthvalue of whether T1 is the same tree structure as T2.
+   Return 1 if they are the same. Return 0 if they are different.  */
+
+bool
+cp_tree_equal (tree t1, tree t2)
+{
+  return compare_trees (t1, t2, COMPARE_STRICT);
+}
+
 /* The type of ARG when used as an lvalue.  */
 
 tree
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index ba5ae46..cff910b 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -53,6 +53,7 @@ static tree rationalize_conditional_expr (enum tree_code, tree,
 static int comp_ptr_ttypes_real (tree, tree, int);
 static bool comp_except_types (tree, tree, bool);
 static bool comp_array_types (const_tree, const_tree, bool);
+static bool compparms_guided (const_tree, const_tree, int);
 static tree pointer_diff (tree, tree, tree);
 static tree get_delta_difference (tree, tree, bool, bool, tsubst_flags_t);
 static void casts_away_constness_r (tree *, tree *);
@@ -1119,13 +1120,56 @@ comp_array_types (const_tree t1, const_tree t2, bool allow_redeclaration)
   return true;
 }
 
+/* Return true iff the two instances of TEMPLATE_PARM_INDEX are
+   equivalent.  STRICT controls how the comparison is done, with the
+   same semantics as the last parameter of comptypes.  */
+
+bool
+comp_template_parms_siblings (tree index1,
+			      tree index2,
+			      int strict)
+{
+  tree siblings1, siblings2;
+
+  gcc_assert (index1 != NULL_TREE 
+	      && index2 != NULL_TREE
+	      && TREE_CODE (index1) == TREE_CODE (index2)
+	      && TREE_CODE (index1) == TEMPLATE_PARM_INDEX);
+
+  if (strict & COMPARE_NO_SIBLINGS)
+    return true;
+
+  siblings1 = TEMPLATE_PARM_SIBLINGS (index1);
+  siblings2 = TEMPLATE_PARM_SIBLINGS (index2);
+    
+  if (siblings1 == siblings2)
+    return true;
+
+  /* If T1 and T2 belong to different template parm lists let's assume
+     they are different.  */
+
+  if ((siblings1 != NULL_TREE) != (siblings2 != NULL_TREE))
+    return false;
+
+  if (TREE_VEC_LENGTH (siblings1) != TREE_VEC_LENGTH (siblings2))
+    return false;
+
+  if (!comp_template_parm_levels (siblings1, siblings2,
+				  strict | COMPARE_NO_SIBLINGS))
+    return false;
+
+  return true;
+}
+
 /* Compare the relative position of T1 and T2 into their respective
    template parameter list.
-   T1 and T2 must be template parameter types.
+   T1 and T2 must be template parameter types.  STRICT controls how
+   the comparison is done, with the same semantics as the for the last
+   parameter of comptypes.
    Return TRUE if T1 and T2 have the same position, FALSE otherwise.  */
 
 static bool
-comp_template_parms_position (tree t1, tree t2)
+comp_template_parms_position (tree t1, tree t2, int strict)
 {
   tree index1, index2;
   gcc_assert (t1 && t2
@@ -1137,19 +1181,16 @@ comp_template_parms_position (tree t1, tree t2)
   index1 = TEMPLATE_TYPE_PARM_INDEX (TYPE_MAIN_VARIANT (t1));
   index2 = TEMPLATE_TYPE_PARM_INDEX (TYPE_MAIN_VARIANT (t2));
 
-  /* If T1 and T2 belong to template parm lists of different size,
-     let's assume they are different.  */
-  if (TEMPLATE_PARM_NUM_SIBLINGS (index1)
-      != TEMPLATE_PARM_NUM_SIBLINGS (index2))
-    return false;
-
-  /* Then compare their relative position.  */
+  /* Compare their relative position.  */
   if (TEMPLATE_PARM_IDX (index1) != TEMPLATE_PARM_IDX (index2)
       || TEMPLATE_PARM_LEVEL (index1) != TEMPLATE_PARM_LEVEL (index2)
       || (TEMPLATE_PARM_PARAMETER_PACK (index1)
 	  != TEMPLATE_PARM_PARAMETER_PACK (index2)))
     return false;
 
+  if (!comp_template_parms_siblings (index1, index2, strict))
+    return false;
+
   return true;
 }
 
@@ -1233,11 +1274,12 @@ structural_comptypes (tree t1, tree t2, int strict)
 
     case TEMPLATE_TEMPLATE_PARM:
     case BOUND_TEMPLATE_TEMPLATE_PARM:
-      if (!comp_template_parms_position (t1, t2))
+      if (!comp_template_parms_position (t1, t2, strict))
 	return false;
-      if (!comp_template_parms
+      if (!comp_template_parms_guided
 	  (DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t1)),
-	   DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t2))))
+	   DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t2)),
+	   strict))
 	return false;
       if (TREE_CODE (t1) == TEMPLATE_TEMPLATE_PARM)
 	break;
@@ -1250,7 +1292,9 @@ structural_comptypes (tree t1, tree t2, int strict)
       if (TYPE_TEMPLATE_INFO (t1) && TYPE_TEMPLATE_INFO (t2)
 	  && (TYPE_TI_TEMPLATE (t1) == TYPE_TI_TEMPLATE (t2)
 	      || TREE_CODE (t1) == BOUND_TEMPLATE_TEMPLATE_PARM)
-	  && comp_template_args (TYPE_TI_ARGS (t1), TYPE_TI_ARGS (t2)))
+	  && comp_template_args_guided (TYPE_TI_ARGS (t1),
+					TYPE_TI_ARGS (t2),
+					NULL, NULL, strict))
 	break;
 
       if ((strict & COMPARE_BASE) && DERIVED_FROM_P (t1, t2))
@@ -1264,7 +1308,7 @@ structural_comptypes (tree t1, tree t2, int strict)
       if (!comptypes (TYPE_OFFSET_BASETYPE (t1), TYPE_OFFSET_BASETYPE (t2),
 		      strict & ~COMPARE_REDECLARATION))
 	return false;
-      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+      if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	return false;
       break;
 
@@ -1276,15 +1320,17 @@ structural_comptypes (tree t1, tree t2, int strict)
     case POINTER_TYPE:
       if (TYPE_MODE (t1) != TYPE_MODE (t2)
 	  || TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2)
-	  || !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+	  || !comptypes (TREE_TYPE (t1), TREE_TYPE (t2),
+			 strict & ~COMPARE_REDECLARATION))
 	return false;
       break;
 
     case METHOD_TYPE:
     case FUNCTION_TYPE:
-      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+      if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	return false;
-      if (!compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2)))
+      if (!compparms_guided (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2),
+			   strict))
 	return false;
       break;
 
@@ -1297,43 +1343,48 @@ structural_comptypes (tree t1, tree t2, int strict)
     case TEMPLATE_TYPE_PARM:
       /* If T1 and T2 don't have the same relative position in their
 	 template parameters set, they can't be equal.  */
-      if (!comp_template_parms_position (t1, t2))
+      if (!comp_template_parms_position (t1, t2, strict))
 	return false;
       break;
 
     case TYPENAME_TYPE:
-      if (!cp_tree_equal (TYPENAME_TYPE_FULLNAME (t1),
-			  TYPENAME_TYPE_FULLNAME (t2)))
+      if (!compare_trees (TYPENAME_TYPE_FULLNAME (t1),
+			  TYPENAME_TYPE_FULLNAME (t2),
+			  strict))
 	return false;
       /* Qualifiers don't matter on scopes.  */
-      if (!same_type_ignoring_top_level_qualifiers_p (TYPE_CONTEXT (t1),
-						      TYPE_CONTEXT (t2)))
+      if (!same_type_ignoring_top_level_qualifiers_guided_p (TYPE_CONTEXT (t1),
+							     TYPE_CONTEXT (t2),
+							     strict))
 	return false;
       break;
 
     case UNBOUND_CLASS_TEMPLATE:
-      if (!cp_tree_equal (TYPE_IDENTIFIER (t1), TYPE_IDENTIFIER (t2)))
+      if (!compare_trees (TYPE_IDENTIFIER (t1), TYPE_IDENTIFIER (t2),
+			  strict))
 	return false;
-      if (!same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2)))
+      if (!comptypes (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2), strict))
 	return false;
       break;
 
     case COMPLEX_TYPE:
-      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+      if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	return false;
       break;
 
     case VECTOR_TYPE:
       if (TYPE_VECTOR_SUBPARTS (t1) != TYPE_VECTOR_SUBPARTS (t2)
-	  || !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+	  || !comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	return false;
       break;
 
     case TYPE_PACK_EXPANSION:
-      return (same_type_p (PACK_EXPANSION_PATTERN (t1),
-			   PACK_EXPANSION_PATTERN (t2))
-	      && comp_template_args (PACK_EXPANSION_EXTRA_ARGS (t1),
-				     PACK_EXPANSION_EXTRA_ARGS (t2)));
+	return (comptypes (PACK_EXPANSION_PATTERN (t1), 
+			   PACK_EXPANSION_PATTERN (t2),
+			   strict)
+		&& comp_template_args_guided (PACK_EXPANSION_EXTRA_ARGS (t1),
+					      PACK_EXPANSION_EXTRA_ARGS (t2),
+					      NULL, NULL, strict));
 
     case DECLTYPE_TYPE:
       if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t1)
@@ -1342,14 +1393,16 @@ structural_comptypes (tree t1, tree t2, int strict)
 	      != DECLTYPE_FOR_LAMBDA_CAPTURE (t2))
 	  || (DECLTYPE_FOR_LAMBDA_PROXY (t1)
 	      != DECLTYPE_FOR_LAMBDA_PROXY (t2))
-          || !cp_tree_equal (DECLTYPE_TYPE_EXPR (t1), 
-                             DECLTYPE_TYPE_EXPR (t2)))
+          || !compare_trees (DECLTYPE_TYPE_EXPR (t1), 
+                             DECLTYPE_TYPE_EXPR (t2),
+			     strict))
         return false;
       break;
 
     case UNDERLYING_TYPE:
-      return same_type_p (UNDERLYING_TYPE_TYPE (t1), 
-			  UNDERLYING_TYPE_TYPE (t2));
+      return comptypes (UNDERLYING_TYPE_TYPE (t1), 
+			UNDERLYING_TYPE_TYPE (t2),
+			strict);
 
     default:
       return false;
@@ -1416,15 +1469,31 @@ comptypes (tree t1, tree t2, int strict)
 }
 
 /* Returns nonzero iff TYPE1 and TYPE2 are the same type, ignoring
-   top-level qualifiers.  */
+   top-level qualifiers.  STRICT controls how the type comparison is
+   done, with the same semantics as for the last parameter of
+   comptypes.  */
 
 bool
-same_type_ignoring_top_level_qualifiers_p (tree type1, tree type2)
+same_type_ignoring_top_level_qualifiers_guided_p (tree type1,
+						  tree type2,
+						  int strict)
 {
   if (type1 == error_mark_node || type2 == error_mark_node)
     return false;
 
-  return same_type_p (TYPE_MAIN_VARIANT (type1), TYPE_MAIN_VARIANT (type2));
+  return comptypes (TYPE_MAIN_VARIANT (type1),
+		    TYPE_MAIN_VARIANT (type2),
+		    strict);
+}
+
+/* Returns nonzero iff TYPE1 and TYPE2 are the same type, ignoring
+   top-level qualifiers.  */
+
+bool
+same_type_ignoring_top_level_qualifiers_p (tree type1, tree type2)
+{
+  return same_type_ignoring_top_level_qualifiers_guided_p (type1, type2,
+							   COMPARE_STRICT);
 }
 
 /* Returns 1 if TYPE1 is at least as qualified as TYPE2.  */
@@ -1479,10 +1548,10 @@ comp_cv_qual_signature (tree type1, tree type2)
 /* Return true if two parameter type lists PARMS1 and PARMS2 are
    equivalent in the sense that functions with those parameter types
    can have equivalent types.  The two lists must be equivalent,
-   element by element.  */
+   element by element.  STRICT controls how the comparison is done.  */
 
-bool
-compparms (const_tree parms1, const_tree parms2)
+static bool
+compparms_guided (const_tree parms1, const_tree parms2, int strict)
 {
   const_tree t1, t2;
 
@@ -1497,12 +1566,23 @@ compparms (const_tree parms1, const_tree parms2)
 	 they fail to match.  */
       if (!t1 || !t2)
 	return false;
-      if (!same_type_p (TREE_VALUE (t1), TREE_VALUE (t2)))
+      if (!comptypes (TREE_VALUE (t1), TREE_VALUE (t2), strict))
 	return false;
     }
   return true;
 }
 
+/* Return true if two parameter type lists PARMS1 and PARMS2 are
+   equivalent in the sense that functions with those parameter types
+   can have equivalent types.  The two lists must be equivalent,
+   element by element.  */
+
+bool
+compparms (const_tree parms1, const_tree parms2)
+{
+  return compparms_guided (parms1, parms2, COMPARE_STRICT);
+}
+
 \f
 /* Process a sizeof or alignof expression where the operand is a
    type.  */
diff --git a/gcc/testsuite/g++.dg/template/crash84.C b/gcc/testsuite/g++.dg/template/crash84.C
index c42f85c..69ee87c 100644
--- a/gcc/testsuite/g++.dg/template/crash84.C
+++ b/gcc/testsuite/g++.dg/template/crash84.C
@@ -4,8 +4,8 @@
 
 template<typename T> struct a
 {
-    template <template <typename> class C, typename X, C<X>* =0>
-    struct b // { dg-error "class C' is not a template|is not a valid type" }
+    template <template <typename> class C, typename X, C<X>* = 0>
+    struct b
     {
     };
 };
@@ -13,7 +13,5 @@ template<typename T> struct a
 void
 foo ()
 {
-    a<int> v; // { dg-message "required from here" }
+    a<int> v;
 }
-
-
diff --git a/gcc/testsuite/g++.dg/template/typedef39.C b/gcc/testsuite/g++.dg/template/typedef39.C
new file mode 100644
index 0000000..4ee23a6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef39.C
@@ -0,0 +1,16 @@
+// Origin PR c++/50852
+// { dg-do compile }
+
+template<int d> class A;
+template<class T> struct B {typedef int K;typedef int L;};
+template<class U,class V> struct C
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W;
+};
+template<class U,int d> struct D
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W; // { dg-error "not a member" }
+};
+template class D<B<A<1> >,3>;
diff --git a/gcc/testsuite/g++.dg/template/typedef40.C b/gcc/testsuite/g++.dg/template/typedef40.C
new file mode 100644
index 0000000..6cd9766
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef40.C
@@ -0,0 +1,22 @@
+// Origin PR c++/50852
+// { dg-do compile }
+
+template<int d> class A;
+
+template<class T> struct B {typedef int K;typedef int L;};
+template<class U, void(*)(U&), class V> struct C
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W;
+};
+template<class U, void(*)(U&), int d> struct D
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W; // { dg-error "not a member" }
+};
+
+struct S;
+
+void f(B<A<1> >&);
+
+template class D<B<A<1> >, &f, 3>;
diff --git a/gcc/testsuite/g++.dg/template/typedef41.C b/gcc/testsuite/g++.dg/template/typedef41.C
new file mode 100644
index 0000000..17d2feb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef41.C
@@ -0,0 +1,19 @@
+// Origin PR c++/50852
+// { dg-do compile }
+
+template<int d> class A;
+
+template<class T> struct B {typedef int K;typedef int L;};
+template<class U, typename U::K, class V> struct C
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W;
+};
+template<class U, typename U::K, int d> struct D
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W; // { dg-error "not a member" }
+};
+
+
+template class D<B<A<1> >, 0, 3>;
-- 
1.7.6.5

-- 
		Dodji

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] PR c++/50852 - Revisit dependant template parameter
  2012-03-08 13:22       ` [PATCH] PR c++/50852 - Revisit dependant template parameter Dodji Seketeli
@ 2012-03-08 20:17         ` Jason Merrill
  2012-03-09 10:04           ` Dodji Seketeli
  2012-03-13 21:33         ` Jason Merrill
  1 sibling, 1 reply; 18+ messages in thread
From: Jason Merrill @ 2012-03-08 20:17 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: GCC Patches

On 03/08/2012 08:21 AM, Dodji Seketeli wrote:
> [Handle fix-up for level-reduced a template parameter pack]
>
> In the partial instantiation of the member template A<int>::f, the
> level of the parameter pack Us is NOT reduced, even if it ought to be
> considered as morally reduced.

The level of the parameter is reduced, right?  It's just that we don't 
do any substitution of the pattern of the pack expansion, so we still 
have the unreduced version of the parameter there.

I don't think we need morally reduced parameters.

Jason

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] PR c++/50852 - Revisit dependant template parameter
  2012-03-08 20:17         ` Jason Merrill
@ 2012-03-09 10:04           ` Dodji Seketeli
  0 siblings, 0 replies; 18+ messages in thread
From: Dodji Seketeli @ 2012-03-09 10:04 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches

Jason Merrill <jason@redhat.com> writes:

> On 03/08/2012 08:21 AM, Dodji Seketeli wrote:
>> [Handle fix-up for level-reduced a template parameter pack]
>>
>> In the partial instantiation of the member template A<int>::f, the
>> level of the parameter pack Us is NOT reduced, even if it ought to be
>> considered as morally reduced.
>
> The level of the parameter is reduced, right?

Yes.

> It's just that we don't do any substitution of the pattern of the
> pack expansion, so we still have the unreduced version of the
> parameter there.

Yes, and that is precisely what breaks type fix-up and here is why.

Let's call the non-reduced parameter P, the reduced one Pr and the
fixed-up and reduced one Prf.

During fix-up, once Prf is built from Pr, we need to replace references
to Pr inside the default argument of the parameter V (in the example I
gave in my previous email).  That means, we need to replace references
to Pr inside the pattern (of the pack expansion) by references to Prf.

This is done by turning Prf into an argument (by calling
template_parm_to_arg on Prf) and by substituting Prf for Pr, into the
pack expansion tuple<pair<Ts,Us>..., and in turn, into the pattern.
This is done by tsubst_pack_expansion.

For tsubst_pack_expansion to work properly in that context, it needs to
detect that the argument representation of Prf matches the Pr parameter
pack inside the pattern.  This is what arg_from_parm_pack_p does.

But as there is no Pr in the pattern (because it only contains P, as you
noted) arg_from_parm_pack_p fails, taking tsubst_pack_expansion down
with it.  So I needed to say somehow that the P in the pack expansion
(in the pattern) is actually a Pr "in spirit".  Note that 

> I don't think we need morally reduced parameters.

How can I make tsubst_pack_expansion work during the fix-up of a reduced
parameter otherwise?

-- 
		Dodji

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] PR c++/50852 - Revisit dependant template parameter
  2012-03-08 13:22       ` [PATCH] PR c++/50852 - Revisit dependant template parameter Dodji Seketeli
  2012-03-08 20:17         ` Jason Merrill
@ 2012-03-13 21:33         ` Jason Merrill
  2012-03-25 18:12           ` Dodji Seketeli
  2012-03-28 15:02           ` Dodji Seketeli
  1 sibling, 2 replies; 18+ messages in thread
From: Jason Merrill @ 2012-03-13 21:33 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: GCC Patches

On 03/08/2012 08:21 AM, Dodji Seketeli wrote:
> So I needed to say somehow that the P in the pack expansion
> (in the pattern) is actually a Pr "in spirit".

Ah, I see.

> +                                    /*we will fixup the siblings for

Space and capital W.

> +get_root_index_same_level (tree index)
> +{
> +  tree i = index;
> +
> +  if (TREE_CODE (TEMPLATE_PARM_DECL (i)) == CONST_DECL)
> +    {
> +      if (TEMPLATE_PARM_ORIG_LEVEL (i) == TEMPLATE_PARM_LEVEL (index))
> +       i = TEMPLATE_PARM_ORIG_INDEX (i);

If the levels are the same, shouldn't the ORIG_INDEX already be the same 
as index?

> +  else
> +    {
> +      if (template_type_parameter_type_p (TREE_TYPE (i))
> +         && TREE_CODE (TEMPLATE_PARM_DECL (i)) != CONST_DECL
> +         && TYPE_CANONICAL (TREE_TYPE (i)) != NULL_TREE)

You already checked the TREE_CODE of TEMPLATE_PARM_DECL in the outer if. 
  And if it's not a CONST_DECL, it must be either a type parameter or 
template parameter.  So I think you only need the last test here.

> +get_template_parameter_level_and_index (tree parameter, int *level, int *index)
> +{
> +  int l = 0, i = -1;
> +  tree parm;
> +
> +  if (TREE_CODE (parameter) == TYPE_DECL
> +      || TREE_CODE (parameter) == TEMPLATE_DECL)
> +    parm = TREE_TYPE (parameter);
> +  else if (TREE_CODE (parameter) == PARM_DECL)
> +    parm = DECL_INITIAL (parameter);
> +  else
> +    parm = parameter;
> +
> +  template_parm_level_and_index (parm, &l, &i);

Why not extend template_parm_level_and_index to handle these cases as well?

> +    properly appends the descender of INDEX to that

descendant

> +      if (*where == NULL_TREE)
> +       TREE_VEC_ELT (TEMPLATE_PARM_DESCENDANTS (index),
> +                     TEMPLATE_PARM_LEVEL (descendant) - 1) = descendant;

Why not "*where = descendant"?

> +             && (DECL_SOURCE_LOCATION (TEMPLATE_PARM_DECL (result))
> +                 != DECL_SOURCE_LOCATION (TEMPLATE_PARM_DECL (orig_index))))
> +           {
> +             /*  We have gotten an equivalent index, that was reduced
> +                 from index from ORIG_INDEX, but which (location of)
> +                 DECL is different.  This can lead to having error
> +                 messages pointing to the wrong location, so let's
> +                 build an equivalent TEMPLATE_PARM_INDEX with a DECL
> +                 pointing to the same location as ORIG_INDEX for
> +                 RESULT.  */

How can this happen?  Hmm, I guess it's because of

> +       i = TEMPLATE_TYPE_PARM_INDEX (TYPE_CANONICAL (TREE_TYPE (i)));

Why do we want to go to the canonical type parameter (which has no name) 
rather than just TYPE_MAIN_VARIANT?

I think it makes more sense to reduce the index we have, rather than 
reduce the canonical index and then adjust the result to match the index 
we have.

> +  /* Template parms ought to be fixed-up from left to right.  */
> +  parms = nreverse (parms);

I'm a bit nervous about something called by fixup getting confused by 
this change to the template parms before we change it back.

> +/*  Transform a template parameter into an argument, suitable to be
> +    passed to tsubst as an element of its ARGS parameter.  */
> +
> +static tree
> +template_parms_to_args (tree parms)

The comment seems to be talking about a single parm.

> +      /* This can happen for template parms of a template template
> +        parameter, e.g:
> +
> +        template<template<class T, class U> class TT> struct S;
> +
> +        Consider the level of the parms of TT; T and U both have
> +        level 2; TT has no template parm of level 1. So in this case
> +        the first element of full_template_args is NULL_TREE. If we
> +        leave it like this TMPL_ARG_DEPTH on args returns 1 instead
> +        of 2. This will make tsubst wrongly consider that T and U
> +        have level 1. Instead, let's create a dummy vector as the
> +        first element of full_template_args so that TMPL_ARG_DEPTH
> +        returns the correct depth for args.  */

Hmm, it seems odd that the parms wouldn't have level 1.  I wonder if 
changing that would also avoid needing to use structural equality for 
template template parameters.

>    FIXME: This function does an approximation, as it only checks that
>    the levels of PARM_PACK/EXPANSION and ARG_PACK do match.  For it to
>    be precise, I think the TEMPLATE_PARM_INDEX of PARM_PACK should
>    track its pre-fixup type, so that ARG_PACK could be compared with
>    that type instead.  But that would increase the size of the
>    template_parm_index_s struct, as I don't see where else I could
>    store the pre-fixup type.  */

Doesn't ...ORIG_INDEX work for this?  Indeed, I'd think you could change 
arg_from_parm_pack_p to compare ORIG_INDEX and then it would handle both 
cases.

> +      if (tinfo && TREE_CODE (TI_TEMPLATE (tinfo)) == TEMPLATE_DECL)
> +       {
> +         ++processing_template_decl;
> +         /* prepare possible partial instantiation of member
> +            template by fixing-up template parms which level are
> +            going to be reduced by the partial instantiation.  */
> +         tsubst_template_parms (DECL_TEMPLATE_PARMS (TI_TEMPLATE (tinfo)),
> +                                args, tf_none);
> +         --processing_template_decl;
> +       }

This doesn't seem necessary for member functon templates, since we fix 
up the parms first thing in tsubst_decl.  Is it necessary for member 
class templates?  Can we handle it at a lower level there, too?

>      case UNBOUND_CLASS_TEMPLATE:
>        {
> +       /* If T is a member template being partially instantiated,
> +          fixup its template parmeters that are to be level-reduced,
> +          upfront.  */
> +       tree parm_list =
> +         tsubst_template_parms (DECL_TEMPLATE_PARMS (TYPE_NAME (t)),
> +                                args, complain);

This comment could be clearer; an UNBOUND_CLASS_TEMPLATE isn't a member 
template, though it will eventually be replaced with one.

Jason

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] PR c++/50852 - Revisit dependant template parameter
  2012-03-13 21:33         ` Jason Merrill
@ 2012-03-25 18:12           ` Dodji Seketeli
  2012-03-27 17:30             ` Dodji Seketeli
  2012-03-28 15:02           ` Dodji Seketeli
  1 sibling, 1 reply; 18+ messages in thread
From: Dodji Seketeli @ 2012-03-25 18:12 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches

Jason Merrill <jason@redhat.com> writes:

> > +                                    /*we will fixup the siblings for
> Space and capital W.

Fixed in my local tree.

> 
> > +get_root_index_same_level (tree index)
> > +{
> > +  tree i = index;
> > +
> > +  if (TREE_CODE (TEMPLATE_PARM_DECL (i)) == CONST_DECL)
> > +    {
> > +      if (TEMPLATE_PARM_ORIG_LEVEL (i) == TEMPLATE_PARM_LEVEL (index))
> > +       i = TEMPLATE_PARM_ORIG_INDEX (i);
> 
> If the levels are the same, shouldn't the ORIG_INDEX already be the
> same as index?

Not necessarily.  I believe they can have the same index and at the
same time, one can be the fixed-up version of the other, without any
level-reducing happening in the process.

> 
> > +  else
> > +    {
> > +      if (template_type_parameter_type_p (TREE_TYPE (i))
> > +         && TREE_CODE (TEMPLATE_PARM_DECL (i)) != CONST_DECL
> > +         && TYPE_CANONICAL (TREE_TYPE (i)) != NULL_TREE)
> 
> You already checked the TREE_CODE of TEMPLATE_PARM_DECL in the outer
> if. And if it's not a CONST_DECL, it must be either a type parameter
> or template parameter.  So I think you only need the last test here.

Right.  This is an artifact of an earlier version of the patch and I
forgot to remove the earlier test.  Fixed.

> 
> > +get_template_parameter_level_and_index (tree parameter, int *level, int *index)
> > +{
> > +  int l = 0, i = -1;
> > +  tree parm;
> > +
> > +  if (TREE_CODE (parameter) == TYPE_DECL
> > +      || TREE_CODE (parameter) == TEMPLATE_DECL)
> > +    parm = TREE_TYPE (parameter);
> > +  else if (TREE_CODE (parameter) == PARM_DECL)
> > +    parm = DECL_INITIAL (parameter);
> > +  else
> > +    parm = parameter;
> > +
> > +  template_parm_level_and_index (parm, &l, &i);
> 
> Why not extend template_parm_level_and_index to handle these cases
> as well?

Done in my local tree.

> 
> > +    properly appends the descender of INDEX to that
> 
> descendant
> 
> > +      if (*where == NULL_TREE)
> > +       TREE_VEC_ELT (TEMPLATE_PARM_DESCENDANTS (index),
> > +                     TEMPLATE_PARM_LEVEL (descendant) - 1) = descendant;
> 
> Why not "*where = descendant"?

Another factorization miss from me.  Thanks for catching it.  Fixed in
my local tree.

> 
> > +             && (DECL_SOURCE_LOCATION (TEMPLATE_PARM_DECL (result))
> > +                 != DECL_SOURCE_LOCATION (TEMPLATE_PARM_DECL (orig_index))))
> > +           {
> > +             /*  We have gotten an equivalent index, that was reduced
> > +                 from index from ORIG_INDEX, but which (location of)
> > +                 DECL is different.  This can lead to having error
> > +                 messages pointing to the wrong location, so let's
> > +                 build an equivalent TEMPLATE_PARM_INDEX with a DECL
> > +                 pointing to the same location as ORIG_INDEX for
> > +                 RESULT.  */
> 
> How can this happen?  Hmm, I guess it's because of
> 
> > +       i = TEMPLATE_TYPE_PARM_INDEX (TYPE_CANONICAL (TREE_TYPE (i)));
> 

Yes.

> Why do we want to go to the canonical type parameter (which has no
> name) rather than just TYPE_MAIN_VARIANT?

It took me a lot of time to understand why this wouldn't work on e.g,
the 25_algorithms/copy/streambuf_iterators/char/1.cc test case of
libstdc++ and distill a smaller example that illustrates the issue.

Consider this:

    template<class T> class I {};

    template<class T, class U = I<T> > class S1;
    template<class T> class S2;

    template<class T>
    class S0
    {
	template<class W> friend S1<W> foo (); //#1
    };

    template<class T, class U>
    class S1
    {
    };

    template<class T>
    class S2
    {
	template<class V> //#2
	friend void access(S1<V>, S2<V>); //#3
	bool p; // ---> error: ‘bool S2<int>::p’ is private
    };

    template<class U>
    void
    access(S1<U> s1, S2<U> s2) //#4
    {
	s2.p = true; // ---> error in this context.
	return s1;
    }

    int
    main()
    {
	S1<int> s1;
	S2<int> s2; //#5
	access(s1, s2);
    }

When we consider S2<int> in #5, it triggers the partial instantiation
of the friend 'access' member template in #2 and #3.  In #2 (as we
have a handle on the list of siblings of V there), V is level-reduced
to level 1, and is fixed-up (by tsubst_template_parms).

Lets call Vi the initial V of level 2, Vr the level-reduced V of level
1 and Vrf the level-reduced and fixed-up V; and similarly Wi, Wr and
Wrf.

After fix-up, the question (which you are asking in essence) is, which
Vi do we hang Vrf on?

Suppose then that we hang it on TYPE_MAIN_VARIANT of Vi in #2.

In #3, during the type substitution of Vrf into the declaration of
"access" (in tsubst_decl), we have a problem with the default argument
of the second parameter of S1 in S1<V>.

To understand the problem, one must note that S1<V> in #3 (before the
level-reduction-and-fix-up) really is S1<V, I<W> >.  In theory, it is
S1<V, I<V> >, but the I<V> there is equivalent to I<W> that
lookup_template_class built earlier at #1, so S1<V, I<W> > really is
what we have in #3.  This subtlety becomes meaningful as it follows
that the TYPE_MAIN_VARIANT for W is different from the
TYPE_MAIN_VARIANT for V, in #3.

So during the type substitution of Vrf into the declaration of
"access" in #3, the Wi parm in the I<W> default template argument is
level-reduced.  Note that in this case, the level-reduction cannot be
followed by type fix-up because we don't have a handle on all template
parameters siblings in a row, like we did in #2.  Thus
reduce_template_parm_level on Vi *must* yield Vrf here (for the whole
scheme to work), not Vr.

So reduce_template_parm_level looks in TYPE_MAIN_VARIANT of Wi to see
if there is a Wrf hung on there, so that it could return it as a
result of the level-reduction.  But it won't find any because we hung
the Wrf (really Vrf) on the TYPE_MAIN_VARIANT for Vi, and
TYPE_MAIN_VARIANT of Vi is different from TYPE_MAIN_VARIANT for Wi.

As a matter of fact, the level-reduction of Wi here yields a reduced
parameter that is not fixed up: Wr or rather Vr.  Precisely what we
want to avoid.

That in turns makes the "access" declaration in #4 be different from
the one declared in #3.  Oops.

In contrast, if we hang Vrf on TYPE_CANONICAL of Vi, it will be found
when reduce_template_parm_level looks it up on the TYPE_CANONICAL of
Wi, because Vi and Wi have the same canonical type.

Also, I don't understand when you said above that the TYPE_CANONICAL
for V doesn't have a name.  In this case, it does have seem to have a
name (a TYPE_NAME), which is W.  What am I missing?

> 
> > +  /* Template parms ought to be fixed-up from left to right.  */
> > +  parms = nreverse (parms);
> 
> I'm a bit nervous about something called by fixup getting confused by
> this change to the template parms before we change it back.

Do you have a particular spot in mind?

Would you prefer to copy the linked list parms, and do the reversing
and fixup on it instead?

> 
> > +/*  Transform a template parameter into an argument, suitable to be
> > +    passed to tsubst as an element of its ARGS parameter.  */
> > +
> > +static tree
> > +template_parms_to_args (tree parms)
> 
> The comment seems to be talking about a single parm.

Fixed in my local tree.

> 
> > +      /* This can happen for template parms of a template template
> > +        parameter, e.g:
> > +
> > +        template<template<class T, class U> class TT> struct S;
> > +
> > +        Consider the level of the parms of TT; T and U both have
> > +        level 2; TT has no template parm of level 1. So in this case
> > +        the first element of full_template_args is NULL_TREE. If we
> > +        leave it like this TMPL_ARG_DEPTH on args returns 1 instead
> > +        of 2. This will make tsubst wrongly consider that T and U
> > +        have level 1. Instead, let's create a dummy vector as the
> > +        first element of full_template_args so that TMPL_ARG_DEPTH
> > +        returns the correct depth for args.  */
> 
> Hmm, it seems odd that the parms wouldn't have level 1.  I wonder if
> changing that would also avoid needing to use structural equality for
> template template parameters.

Yes, it looks like so.  I'd like to address that in a subsequent patch
once the other core parts of this one are OK, because I suspect there
are a few other places I'd need to adjust if I touch this.  That and
I'll probably need to chase a fallout or two.  :-)

I'll then probably merge that subsequent patch with this one, as you
see fit.  Is that OK?

> 
> >    FIXME: This function does an approximation, as it only checks that
> >    the levels of PARM_PACK/EXPANSION and ARG_PACK do match.  For it to
> >    be precise, I think the TEMPLATE_PARM_INDEX of PARM_PACK should
> >    track its pre-fixup type, so that ARG_PACK could be compared with
> >    that type instead.  But that would increase the size of the
> >    template_parm_index_s struct, as I don't see where else I could
> >    store the pre-fixup type.  */
> 
> Doesn't ...ORIG_INDEX work for this?  Indeed, I'd think you could
> change arg_from_parm_pack_p to compare ORIG_INDEX and then it would
> handle both cases.

It's close but it doesn't fit perfectly.  For a parameter T, if let's
call Ti its initial (pre-fixup) version, Tf its fixed up version, Tr
the reduced version, and Trf the reduced and fixed up version.

At the moment, for a fixed-up type, TEMPLATE_PARM_ORIG_INDEX(Tf) and
TEMPLATE_PARM_ORIG_INDEX(Trf) all point to Tf.  That is, they point to
a fixed-up version of T.

To make this work, I think I'd need to make TEMPLATE_PARM_ORIG_INDEX
point to Ti instead.  I think it's possible to get the fixed-up
version of a given pre-fix-up one (by poking the TREE_TYPE (TYPE_NAME
(Ti))) so I believe this should work.  I am looking into this at the
moment.

> > +      if (tinfo && TREE_CODE (TI_TEMPLATE (tinfo)) == TEMPLATE_DECL)
> > +       {
> > +         ++processing_template_decl;
> > +         /* prepare possible partial instantiation of member
> > +            template by fixing-up template parms which level are
> > +            going to be reduced by the partial instantiation.  */
> > +         tsubst_template_parms (DECL_TEMPLATE_PARMS (TI_TEMPLATE (tinfo)),
> > +                                args, tf_none);
> > +         --processing_template_decl;
> > +       }
> 
> This doesn't seem necessary for member functon templates, since we fix
> up the parms first thing in tsubst_decl.  Is it necessary for member
> class templates?  Can we handle it at a lower level there, too?

Indeed.  I actually started the patch by putting the
reducing-and-fixup call here first, to be sure I wasn't forgetting any
spot.  I then moved handle it a lower level but it seems like I forgot
to remove this.  Now I realize I forgot to handle the case of member
typename declarations that have their own template header.  Fixed in
my local tree.

> 
> >      case UNBOUND_CLASS_TEMPLATE:
> >        {
> > +       /* If T is a member template being partially instantiated,
> > +          fixup its template parmeters that are to be level-reduced,
> > +          upfront.  */
> > +       tree parm_list =
> > +         tsubst_template_parms (DECL_TEMPLATE_PARMS (TYPE_NAME (t)),
> > +                                args, complain);
> 
> This comment could be clearer; an UNBOUND_CLASS_TEMPLATE isn't a
> member template, though it will eventually be replaced with one.

Fixed in my local tree.

Here is what currently passes bootstrap and regression tests in my local
tree.
    
    gcc/cp/
    
    	PR c++/50852
    	* cp-tree.h (struct template_parm_index_s)<num_siblings,orig_level>: Remove.
    	(struct template_parm_index_s)<siblings, orig_index>: New members.
    	(COMPARE_NO_SIBLINGS): New type comparison control flag.
    	(TEMPLATE_PARM_SIBLINGS): New accessor macro.
    	(TEMPLATE_PARM_DESCENDANTS): Add comments.
    	(TEMPLATE_PARM_ORIG_INDEX): New accessor.
    	(TEMPLATE_PARM_ORIG_LEVEL): Rewrite in terms of
    	TEMPLATE_PARM_ORIG_INDEX.
    	(process_template_parm): Change the integer num_siblings parm into
    	a tree siblings parm.
    	(comp_template_parms_siblings, comp_template_parm_levels)
    	(comp_template_parms_guided, comp_template_args_guided)
    	(same_type_ignoring_top_level_qualifiers_guided_p, compare_trees)
    	(template_type_parameter_type_p): Declare new functions.
    	(fixup_current_template_parms): New, better name for
    	fixup_template_parms.
    	(fixup_template_parms): Take the set of parameters to fixup in
    	parameters.
    	* pt.c (arg_from_reduced_and_fixedup_parm_pack_of_expansion_p)
    	(get_root_index_same_level, add_descendant_to_parm_index)
    	(get_descendant_of_parm_index, get_template_parm_index)
    	(comp_template_parm_levels, template_parms_to_args)
    	(template_type_parameter_type_p): Define new functions.
    	(current_template_args): Use the new template_parms_to_args
    	function.
    	(fixup_template_type_parm_type)
    	(fixup_template_parm_index, build_template_parm_index)
    	(fixup_template_parm_index, process_template_parm)
    	(fixup_template_type_parm_type, fixup_template_parm)
    	(process_template_parm): Change the integer num_siblings parm into
    	a tree siblings parm.  Update comments.
    	(build_template_parm_index): Likewise.  Replace ORIG_LEVEL integer
    	parm with an ORIG_INDEX tree.  Add a few asserts.
    	(get_template_info): Make this more robust and support getting
    	template info from TYPENAME_TYPE nodes.
    	(comp_template_parms_guided): New function.  Takes an additional
    	parm to control comparison.  Factorized out of ...
    	(comp_template_parms): ... this.
    	(reduce_template_parm_level): Use TEMPLATE_PARM_SIBLINGS instead
    	of TEMPLATE_PARM_NUM_SIBLINGS.  Update usage of
    	TEMPLATE_PARM_DESCENDANTS.  Use the new
    	get_descendant_of_parm_index.
    	(template_args_equal_guided): Take an additional parm to control
    	comparison.  Use template_args_equal_guided instead of
    	template_args_equal.  Factorize this out of ...
    	(template_args_equal): ... this.
    	(comp_template_args_guided): Take an additional parm to control
    	comparison.  Renamed from comp_template_args_with_info.  Make this
    	public.
    	(comp_template_args, unify_pack_expansion): Adjust.
    	(fixup_innermost_template_parms): Transformed former
    	fixup_template_parms in to this.  Make it take a set of parms to
    	fixup and an arglist.  Update comments.
    	(fixup_template_parms): Take the parms to fixup in argument.
    	(fixup_current_template_parms): This is the new name for the
    	former fixup_template_parms.  It has be re-written in terms of
    	fixup_innermost_template_parms.
    	* tree.c (compare_trees): Factorized this out of cp_tree_equal.
    	Take a comparison control parameter. Use tree comparison functions
    	that take a comparison control parm.
    	(cp_tree_equal): Use the factorized compare_trees.
    	(tsubst_template_parms):  Fixup template parameters that are
    	level-reduced.
    	(push_template_decl_real): Support declarations of friend template
    	represented by TYPENAME_TYPE nodes.
    	(instantiate_class_template_1, tsubst_aggr_type, tsubst_decl)
    	(tsubst<UNBOUND_CLASS_TEMPLATE>): Call tsubst_template_parms
    	upfront to fixup dependant types that are to be level-reduced by a
    	possible partial instantiation of a member template.
    	(tsubst_pack_expansion): During type fixup, take in account parm
    	packs that have been level-reduced.
    	(get_mostly_instantiated_function_type): Fix this by setting the
    	proper size for the args of tsubst, so that partial instantiation
    	happens there.  Otherwise, tsubst indirectly and wrongly calls
    	reduce_template_parm_level with a reduced level of 0.
    	(make_auto): Adjust for sibling_parms instead of
    	num_sibling_parms.
    	* typeck.c (compparms_guided): Take a comparison control parameter.
    	Split out of ...
    	(compparms): ... this.
    	(comp_template_parms_siblings): Define new function.
    	(comp_template_parms_position): Take an additional parameter to
    	control the comparison.  Use the new comp_template_parms_siblings.
    	(structural_comptypes): Use type comparison routines variants that
    	take the comparison control parm.
    	(same_type_ignoring_top_level_qualifiers_guided_p): Take an
    	additional parm to control comparison.  Use comptypes instead of
    	comptypes.  Factorize out of ...
    	(same_type_ignoring_top_level_qualifiers_p): ... this.
    	* parser.c (cp_parser_template_parameter_list): Adjust for the
    	change to using sibling_parms instead of num_sibling_parms.
    	(cp_parser_template_declaration_after_export): Adjust
    	to call fixup_current_template_parms instead of
    	fixup_template_parms.
    	(cp_parser_single_declaration):  Make friend typename declarations
    	carry a template info.
    
    gcc/testsuite/
    
    	PR c++/50852
    	* g++.dg/template/typedef39.C: New test.
    	* g++.dg/template/typedef40.C: Likewise.
    	* g++.dg/template/typedef41.C: Likewise.
    	* g++.dg/template/crash84.C: This test should actually pass
    	without error.
    
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 71573ff..4e4aaec 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -247,8 +247,12 @@ struct GTY(()) template_parm_index_s {
   struct tree_common common;
   int index;
   int level;
-  int orig_level;
-  int num_siblings;
+  /* If the current index was reduced from an original index, keep
+     track of the later using this pointer.  */
+  tree orig_index;
+  /* A TREE_VEC containing the set of parms this parameter belongs
+     to. */
+  tree siblings;
   tree decl;
 };
 typedef struct template_parm_index_s template_parm_index;
@@ -4476,6 +4480,9 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
 				   structural. The actual comparison
 				   will be identical to
 				   COMPARE_STRICT.  */
+#define COMPARE_NO_SIBLINGS   16 /* When comparing template
+				    parameters, don't consider their
+				    siblings.  */
 
 /* Used with push_overloaded_decl.  */
 #define PUSH_GLOBAL	     0  /* Push the DECL into namespace scope,
@@ -4509,11 +4516,69 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
 	((template_parm_index*)TEMPLATE_PARM_INDEX_CHECK (NODE))
 #define TEMPLATE_PARM_IDX(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->index)
 #define TEMPLATE_PARM_LEVEL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->level)
-/* The Number of sibling parms this template parm has.  */
-#define TEMPLATE_PARM_NUM_SIBLINGS(NODE) \
-  (TEMPLATE_PARM_INDEX_CAST (NODE)->num_siblings)
-#define TEMPLATE_PARM_DESCENDANTS(NODE) (TREE_CHAIN (NODE))
-#define TEMPLATE_PARM_ORIG_LEVEL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->orig_level)
+/* A TREE_VEC containing the sibling parameters for a given template
+   parm.  */
+#define TEMPLATE_PARM_SIBLINGS(NODE) \
+  (TEMPLATE_PARM_INDEX_CAST (NODE)->siblings)
+
+/* This accessor has to do with partial instantiation of member
+   templates and type fixup.
+
+   Consider the member template M below:
+
+	template<class T>
+	struct S
+	{
+	  template<class U> struct M {};
+	};
+
+   When we say template<class V> S<int>::M<V>, M is partially
+   instantiated and the level of its template parameter V is reduced;
+   it was 2 initially, but in the context of the partial
+   instantiation, it becomes 1.
+
+   TEMPLATE_PARM_DESCENDANTS for U captures the relationship between that
+   parameter and those that result from its level-reducing.
+
+   For template type parameters, TEMPLATE_PARM_DESCENDANTS is a vector
+   in which each element represents a parameter reduced to a level
+   that is the vector index of said element.  In the example above,
+   the element at index 1 of TEMPLATE_PARM_DESCENDANTS (U) will
+   contain V.
+
+   For non-type template parameters, TEMPLATE_PARM_DESCENDANTS is a
+   vector or TREE_LIST.  For a given level (that represents the index
+   of each element of the vector), there is a list of parameters
+   reduced to that level, and each parameter of that list has a
+   different type.  For instance:
+
+	template<class T>
+	struct S
+	{
+	  template<T a>  struct M {};
+	};
+
+   When we say template<> S<int>::M, the level of parameter 'a' is
+   reduced to 1 (from 2), and its type is 'int'.
+
+   When we say template<> S<int>::M, the level of 'a' is reduced to 1
+   as well, but its type is 'char'.
+
+   So in TEMPLATE_PARM_DESCENDANTS for parameter 'a', the element at
+   index 1 will be a TREE_LIST of two elements which first TREE_VALUE
+   is the TEMPLATE_PARM_INDEX for 'int a' and which second TREE_VALUE
+   is the TEMPLATE_PARM_INDEX for 'char a'.
+
+   Note that types of template parameters that are inserted into
+   TEMPLATE_PARM_DESCENDANTS are always fixed-up types.
+
+   Also note that the argument for TEMPLATE_PARM_DESCENDANT must be a
+   TEMPLATE_PARM_INDEX.  */
+#define TEMPLATE_PARM_DESCENDANTS(NODE) (TREE_CHAIN (TEMPLATE_PARM_INDEX_CHECK (NODE)))
+#define TEMPLATE_PARM_ORIG_INDEX(NODE) \
+  (TEMPLATE_PARM_INDEX_CAST (NODE)->orig_index)
+#define TEMPLATE_PARM_ORIG_LEVEL(NODE) \
+  (TEMPLATE_PARM_LEVEL (TEMPLATE_PARM_ORIG_INDEX (NODE)))
 #define TEMPLATE_PARM_DECL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->decl)
 #define TEMPLATE_PARM_PARAMETER_PACK(NODE) \
   (TREE_LANG_FLAG_0 (TEMPLATE_PARM_INDEX_CHECK (NODE)))
@@ -5280,9 +5345,10 @@ extern void append_type_to_template_for_access_check (tree, tree, tree,
 extern tree splice_late_return_type		(tree, tree);
 extern bool is_auto				(const_tree);
 extern tree process_template_parm		(tree, location_t, tree, 
-						 bool, bool, unsigned);
+						 bool, bool, tree);
 extern tree end_template_parm_list		(tree);
-void fixup_template_parms (void);
+extern void fixup_current_template_parms        (void);
+extern void fixup_template_parms                (tree);
 extern void end_template_decl			(void);
 extern tree maybe_update_decl_type		(tree, tree);
 extern bool check_default_tmpl_args             (tree, tree, int, int, int);
@@ -5307,8 +5373,12 @@ extern void do_type_instantiation		(tree, tree, tsubst_flags_t);
 extern bool always_instantiate_p		(tree);
 extern void maybe_instantiate_noexcept		(tree);
 extern tree instantiate_decl			(tree, int, bool);
+extern bool comp_template_parms_siblings        (tree, tree, int);
+extern int comp_template_parm_levels            (const_tree, const_tree, int);
+extern int comp_template_parms_guided		(const_tree, const_tree, int);
 extern int comp_template_parms			(const_tree, const_tree);
 extern bool uses_parameter_packs                (tree);
+extern bool template_type_parameter_type_p      (tree);
 extern bool template_parameter_pack_p           (const_tree);
 extern bool function_parameter_pack_p		(const_tree);
 extern bool function_parameter_expanded_from_pack_p (tree, tree);
@@ -5321,6 +5391,8 @@ extern int template_class_depth			(tree);
 extern int is_specialization_of			(tree, tree);
 extern bool is_specialization_of_friend		(tree, tree);
 extern tree get_pattern_parm			(tree, tree);
+extern int comp_template_args_guided            (tree, tree, tree *,
+						 tree *, int);
 extern int comp_template_args			(tree, tree);
 extern tree maybe_process_partial_specialization (tree);
 extern tree most_specialized_instantiation	(tree);
@@ -5700,6 +5772,7 @@ extern tree lvalue_type				(tree);
 extern tree error_type				(tree);
 extern int varargs_function_p			(const_tree);
 extern bool really_overloaded_fn		(tree);
+extern bool compare_trees                       (tree, tree, int);
 extern bool cp_tree_equal			(tree, tree);
 extern tree no_linkage_check			(tree, bool);
 extern void debug_binfo				(tree);
@@ -5760,6 +5833,9 @@ extern int type_unknown_p			(const_tree);
 enum { ce_derived, ce_normal, ce_exact };
 extern bool comp_except_specs			(const_tree, const_tree, int);
 extern bool comptypes				(tree, tree, int);
+extern bool same_type_ignoring_top_level_qualifiers_guided_p (tree type1,
+							      tree type2,
+							      int strict);
 extern bool same_type_ignoring_top_level_qualifiers_p (tree, tree);
 extern bool compparms				(const_tree, const_tree);
 extern int comp_cv_qualification		(const_tree, const_tree);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index c6bd290..37e82a9 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -11960,7 +11960,7 @@ cp_parser_template_parameter_list (cp_parser* parser)
 						parameter,
 						is_non_type,
 						is_parameter_pack,
-						0);
+						NULL_TREE);
       else
        {
          tree err_parm = build_tree_list (parameter, parameter);
@@ -21124,7 +21124,7 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
     {
       /* Parse the template parameters.  */
       parameter_list = cp_parser_template_parameter_list (parser);
-      fixup_template_parms ();
+      fixup_current_template_parms ();
     }
 
   /* Get the deferred access checks from the parameter list.  These
@@ -21289,6 +21289,7 @@ cp_parser_single_declaration (cp_parser* parser,
     {
       if (cp_parser_declares_only_class_p (parser))
 	{
+	  bool friend_typename_p = false;
 	  decl = shadow_tag (&decl_specifiers);
 
 	  /* In this case:
@@ -21303,7 +21304,10 @@ cp_parser_single_declaration (cp_parser* parser,
 	      && !decl
 	      && decl_specifiers.type
 	      && TYPE_P (decl_specifiers.type))
-	    decl = decl_specifiers.type;
+	    {
+	      decl = decl_specifiers.type;
+	      friend_typename_p = true;
+	    }
 
 	  if (decl && decl != error_mark_node)
 	    decl = TYPE_NAME (decl);
@@ -21312,6 +21316,17 @@ cp_parser_single_declaration (cp_parser* parser,
 
 	  /* Perform access checks for template parameters.  */
 	  cp_parser_perform_template_parameter_access_checks (checks);
+	  if (friend_typename_p
+	      && parser->num_template_parameter_lists > 0
+	      && decl != error_mark_node)
+	    /*  We are looking a the declaration of a class/enum which
+		name is a typename; that declaration has a template
+		header that declares some template parameters used in
+		the declaration.  Ensure the declaration carries a
+		template info representing that header.  That template
+		info will later be useful when we need to fixup the
+		template parameters used in the declaration.  */
+	    push_template_decl_real (decl, /*is_friend=*/true);
 	}
     }
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 4980c19..627163a 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -148,7 +148,7 @@ static tree convert_template_argument (tree, tree, tree,
 static int for_each_template_parm (tree, tree_fn_t, void*,
 				   struct pointer_set_t*, bool);
 static tree expand_template_argument_pack (tree);
-static tree build_template_parm_index (int, int, int, int, tree, tree);
+static tree build_template_parm_index (int, int, tree, tree, tree, tree);
 static bool inline_needs_template_parms (tree);
 static void push_inline_template_parms_recursive (tree, int);
 static tree retrieve_local_specialization (tree);
@@ -183,6 +183,7 @@ static tree try_class_unification (tree, tree, tree, tree, bool);
 static int coerce_template_template_parms (tree, tree, tsubst_flags_t,
 					   tree, tree);
 static bool template_template_parm_bindings_ok_p (tree, tree);
+static int template_args_equal_guided (tree, tree, int);
 static int template_args_equal (tree, tree);
 static void tsubst_default_arguments (tree);
 static tree for_each_template_parm_r (tree *, int *, void *);
@@ -201,12 +202,21 @@ static void append_type_to_template_for_access_check_1 (tree, tree, tree,
 							location_t);
 static tree listify (tree);
 static tree listify_autos (tree, tree);
-static tree template_parm_to_arg (tree t);
+static tree template_parm_to_arg (tree);
+static tree template_parms_to_args (tree);
 static bool arg_from_parm_pack_p (tree, tree);
+static bool arg_from_reduced_and_fixedup_parm_pack_of_expansion_p (tree,
+								   tree,
+								   tree);
 static tree current_template_args (void);
-static tree fixup_template_type_parm_type (tree, int);
-static tree fixup_template_parm_index (tree, tree, int);
+static tree get_root_index_same_level (tree);
+static void add_descendant_to_parm_index (tree, tree);
+static tree get_descendant_of_parm_index (tree, int, tree);
+static tree get_template_parm_index (tree);
+static tree fixup_template_type_parm_type (tree, tree);
+static tree fixup_template_parm_index (tree, tree, tree);
 static tree tsubst_template_parm (tree, tree, tsubst_flags_t);
+static void fixup_innermost_template_parms (tree, tree);
 
 /* Make the current scope suitable for access checking when we are
    processing T.  T can be FUNCTION_DECL for instantiated function
@@ -322,7 +332,16 @@ get_template_info (const_tree t)
     return NULL;
 
   if (DECL_P (t) && DECL_LANG_SPECIFIC (t))
-    tinfo = DECL_TEMPLATE_INFO (t);
+    {     
+      int code = TREE_CODE (t);
+      /* Only the DECLs below are allowed to have template info.  */
+      if (code == VAR_DECL
+	  || code == FIELD_DECL
+	  || code == FUNCTION_DECL
+	  || code == TYPE_DECL
+	  || code == TEMPLATE_DECL)
+	tinfo = DECL_TEMPLATE_INFO (t);
+    }
 
   if (!tinfo && DECL_IMPLICIT_TYPEDEF_P (t))
     t = TREE_TYPE (t);
@@ -331,6 +350,9 @@ get_template_info (const_tree t)
     tinfo = TYPE_TEMPLATE_INFO (t);
   else if (TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM)
     tinfo = TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t);
+  else if (TREE_CODE (t) == TYPENAME_TYPE
+	   && DECL_LANG_SPECIFIC (TYPE_NAME (t)))
+    tinfo = DECL_TEMPLATE_INFO (TYPE_NAME (t));
 
   return tinfo;
 }
@@ -2675,11 +2697,56 @@ check_explicit_specialization (tree declarator,
 }
 
 /* Returns 1 iff PARMS1 and PARMS2 are identical sets of template
+   parameters of a given level, represented by a TREE_VEC of
+   TREE_LIST.  The TREE_VALUE of each TREE_LIST represents a given
+   template parameter.  STRICT controls how the comparison is done.
+   It has the same meaning as the last parameter of the comptypes
+   function.  */
+
+int
+comp_template_parm_levels (const_tree parms_level1,
+			   const_tree parms_level2,
+			   int strict)
+{
+  int i;
+  gcc_assert (TREE_CODE (parms_level1) == TREE_VEC);
+  gcc_assert (TREE_CODE (parms_level2) == TREE_VEC);
+
+  if (TREE_VEC_LENGTH (parms_level1) != TREE_VEC_LENGTH (parms_level2))
+    return 0;
+
+  for (i = 0; i < TREE_VEC_LENGTH (parms_level2); ++i)
+    {
+      tree parm1 = TREE_VALUE (TREE_VEC_ELT (parms_level1, i));
+      tree parm2 = TREE_VALUE (TREE_VEC_ELT (parms_level2, i));
+
+      /* If either of the template parameters are invalid, assume
+	 they match for the sake of error recovery. */
+      if (parm1 == error_mark_node || parm2 == error_mark_node)
+	return 1;
+
+      if (TREE_CODE (parm1) != TREE_CODE (parm2))
+	return 0;
+
+      if (TREE_CODE (parm1) == TEMPLATE_TYPE_PARM
+	  && (TEMPLATE_TYPE_PARAMETER_PACK (parm1)
+	      == TEMPLATE_TYPE_PARAMETER_PACK (parm2)))
+	continue;
+      else if (!comptypes (TREE_TYPE (parm1), TREE_TYPE (parm2), strict))
+	return 0;
+    }
+  return 1;
+}
+
+/* Returns 1 iff PARMS1 and PARMS2 are identical sets of template
    parameters.  These are represented in the same format used for
-   DECL_TEMPLATE_PARMS.  */
+   DECL_TEMPLATE_PARMS.  STRICT controls how the comparison is done.
+   Its semantics are the same as the last parameter of comptypes.  */
 
 int
-comp_template_parms (const_tree parms1, const_tree parms2)
+comp_template_parms_guided (const_tree parms1,
+			    const_tree parms2,
+			    int strict)
 {
   const_tree p1;
   const_tree p2;
@@ -2693,34 +2760,9 @@ comp_template_parms (const_tree parms1, const_tree parms2)
     {
       tree t1 = TREE_VALUE (p1);
       tree t2 = TREE_VALUE (p2);
-      int i;
 
-      gcc_assert (TREE_CODE (t1) == TREE_VEC);
-      gcc_assert (TREE_CODE (t2) == TREE_VEC);
-
-      if (TREE_VEC_LENGTH (t1) != TREE_VEC_LENGTH (t2))
+      if (!comp_template_parm_levels (t1, t2, strict))
 	return 0;
-
-      for (i = 0; i < TREE_VEC_LENGTH (t2); ++i)
-	{
-          tree parm1 = TREE_VALUE (TREE_VEC_ELT (t1, i));
-          tree parm2 = TREE_VALUE (TREE_VEC_ELT (t2, i));
-
-          /* If either of the template parameters are invalid, assume
-             they match for the sake of error recovery. */
-          if (parm1 == error_mark_node || parm2 == error_mark_node)
-            return 1;
-
-	  if (TREE_CODE (parm1) != TREE_CODE (parm2))
-	    return 0;
-
-	  if (TREE_CODE (parm1) == TEMPLATE_TYPE_PARM
-              && (TEMPLATE_TYPE_PARAMETER_PACK (parm1)
-                  == TEMPLATE_TYPE_PARAMETER_PACK (parm2)))
-	    continue;
-	  else if (!same_type_p (TREE_TYPE (parm1), TREE_TYPE (parm2)))
-	    return 0;
-	}
     }
 
   if ((p1 != NULL_TREE) != (p2 != NULL_TREE))
@@ -2731,6 +2773,28 @@ comp_template_parms (const_tree parms1, const_tree parms2)
   return 1;
 }
 
+/* Returns 1 iff PARMS1 and PARMS2 are identical sets of template
+   parameters.  These are represented in the same format used for
+   DECL_TEMPLATE_PARMS.  */
+
+int
+comp_template_parms (const_tree parms1, const_tree parms2)
+{
+  return comp_template_parms_guided (parms1, parms2,
+				     COMPARE_STRICT);
+}
+
+/* Determine wheter PARM is the type of a template type parameter.  */
+
+bool
+template_type_parameter_type_p (tree t)
+{
+  return (t
+	  && (TREE_CODE (t) == TEMPLATE_TYPE_PARM
+	      || TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM
+	      || TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM));
+}
+
 /* Determine whether PARM is a parameter pack.  */
 
 bool 
@@ -3395,22 +3459,27 @@ check_template_shadow (tree decl)
 }
 
 /* Return a new TEMPLATE_PARM_INDEX with the indicated INDEX, LEVEL,
-   ORIG_LEVEL, DECL, and TYPE.  NUM_SIBLINGS is the total number of
-   template parameters.  */
+   ORIG_INDEX, DECL, and TYPE.  SIBLINGS is a TREE_VEC containing the
+   set of parameters the current template parameter belongs to.  */
 
 static tree
 build_template_parm_index (int index,
 			   int level,
-			   int orig_level,
-			   int num_siblings,
+			   tree orig_index,
+			   tree siblings,
 			   tree decl,
 			   tree type)
 {
-  tree t = make_node (TEMPLATE_PARM_INDEX);
+  tree t;
+
+  gcc_assert (level >= 1);
+
+  t = make_node (TEMPLATE_PARM_INDEX);
   TEMPLATE_PARM_IDX (t) = index;
   TEMPLATE_PARM_LEVEL (t) = level;
-  TEMPLATE_PARM_ORIG_LEVEL (t) = orig_level;
-  TEMPLATE_PARM_NUM_SIBLINGS (t) = num_siblings;
+  TEMPLATE_PARM_ORIG_INDEX (t) = orig_index ? orig_index : t;
+  gcc_assert (TREE_CODE (TEMPLATE_PARM_ORIG_INDEX (t)) == TEMPLATE_PARM_INDEX);
+  TEMPLATE_PARM_SIBLINGS (t) = siblings;
   TEMPLATE_PARM_DECL (t) = decl;
   TREE_TYPE (t) = type;
   TREE_CONSTANT (t) = TREE_CONSTANT (decl);
@@ -3458,13 +3527,15 @@ static tree
 reduce_template_parm_level (tree index, tree type, int levels, tree args,
 			    tsubst_flags_t complain)
 {
-  if (TEMPLATE_PARM_DESCENDANTS (index) == NULL_TREE
-      || (TEMPLATE_PARM_LEVEL (TEMPLATE_PARM_DESCENDANTS (index))
-	  != TEMPLATE_PARM_LEVEL (index) - levels)
-      || !same_type_p (type, TREE_TYPE (TEMPLATE_PARM_DESCENDANTS (index))))
+  int new_level = TEMPLATE_PARM_LEVEL (index) - levels;
+  tree t = NULL_TREE;
+
+  gcc_assert (new_level > 0);
+
+  if ((t = get_descendant_of_parm_index (index, new_level, type)) == NULL_TREE)
     {
       tree orig_decl = TEMPLATE_PARM_DECL (index);
-      tree decl, t;
+      tree decl;
 
       decl = build_decl (DECL_SOURCE_LOCATION (orig_decl),
 			 TREE_CODE (orig_decl), DECL_NAME (orig_decl), type);
@@ -3475,10 +3546,18 @@ reduce_template_parm_level (tree index, tree type, int levels, tree args,
 
       t = build_template_parm_index (TEMPLATE_PARM_IDX (index),
 				     TEMPLATE_PARM_LEVEL (index) - levels,
-				     TEMPLATE_PARM_ORIG_LEVEL (index),
-				     TEMPLATE_PARM_NUM_SIBLINGS (index),
+				     TEMPLATE_PARM_ORIG_INDEX (index),
+				     /* We will fixup the siblings for
+				       this index in
+				       tsubst_template_parms, so set
+				       it to NULL here.  */
+				     NULL_TREE,
 				     decl, type);
-      TEMPLATE_PARM_DESCENDANTS (index) = t;
+      /* Do not yet update TEMPLATE_PARM_DESCENDANTS
+	 (TEMPLATE_PARM_ORIG_INDEX (index)) because it will be done
+	 when the new parm index T is fixed up, along with its
+	 siblings, using a call to add_descendant_to_parm_index.  */
+
       TEMPLATE_PARM_PARAMETER_PACK (t) 
 	= TEMPLATE_PARM_PARAMETER_PACK (index);
 
@@ -3489,23 +3568,23 @@ reduce_template_parm_level (tree index, tree type, int levels, tree args,
 	   args, complain);
     }
 
-  return TEMPLATE_PARM_DESCENDANTS (index);
+  return t;
 }
 
 /* Process information from new template parameter PARM and append it
    to the LIST being built.  This new parameter is a non-type
    parameter iff IS_NON_TYPE is true. This new parameter is a
    parameter pack iff IS_PARAMETER_PACK is true.  The location of PARM
-   is in PARM_LOC. NUM_TEMPLATE_PARMS is the size of the template
-   parameter list PARM belongs to. This is used used to create a
+   is in PARM_LOC.  SIBLING_PARMS is a TREE_VEC containing the set of
+   template parameters PARM belongs to.  This is used used to create a
    proper canonical type for the type of PARM that is to be created,
-   iff PARM is a type.  If the size is not known, this parameter shall
-   be set to 0.  */
+   iff PARM is a type.  If the set of parameters is not known, this
+   parameter shall be set to NULL_TREE.  */
 
 tree
 process_template_parm (tree list, location_t parm_loc, tree parm,
 		       bool is_non_type, bool is_parameter_pack,
-		       unsigned num_template_parms)
+		       tree sibling_parms)
 {
   tree decl = 0;
   tree defval;
@@ -3579,8 +3658,8 @@ process_template_parm (tree list, location_t parm_loc, tree parm,
       TREE_READONLY (decl) = 1;
       DECL_INITIAL (parm) = DECL_INITIAL (decl)
 	= build_template_parm_index (idx, processing_template_decl,
-				     processing_template_decl,
-				     num_template_parms,
+				     NULL_TREE,
+				     sibling_parms,
 				     decl, TREE_TYPE (parm));
 
       TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)) 
@@ -3613,8 +3692,8 @@ process_template_parm (tree list, location_t parm_loc, tree parm,
       parm = decl;
       TEMPLATE_TYPE_PARM_INDEX (t)
 	= build_template_parm_index (idx, processing_template_decl,
-				     processing_template_decl,
-				     num_template_parms,
+				     NULL_TREE,
+				     sibling_parms,
 				     decl, TREE_TYPE (parm));
       TEMPLATE_TYPE_PARAMETER_PACK (t) = is_parameter_pack;
       TYPE_CANONICAL (t) = canonical_type_parameter (t);
@@ -3654,34 +3733,284 @@ end_template_parm_list (tree parms)
   return saved_parmlist;
 }
 
+/*  Get the "canonical" INDEX of a given TEMPLATE_PARM_INDEX tree
+    node.
+
+    There can be several equivalent TEMPLATE_PARM_INDEX created for a
+    given template parameter, be it a type or non-type template
+    parameter.
+
+    For a type template parameter P, this function returns the
+    TEMPLATE_PARM_INDEX of the canonical type of P.
+
+    For a non-type template parameter P, this function returns the
+    the "original" TEMPLATE_PARM_INDEX P was created from, given that
+    they both have the same level.  */
+
+static tree
+get_root_index_same_level (tree index)
+{
+  tree i = index;
+
+  if (TREE_CODE (TEMPLATE_PARM_DECL (i)) == CONST_DECL)
+    {
+      if (TEMPLATE_PARM_ORIG_LEVEL (i) == TEMPLATE_PARM_LEVEL (index))
+	i = TEMPLATE_PARM_ORIG_INDEX (i);
+    }
+  else
+    {
+      if (template_type_parameter_type_p (TREE_TYPE (i))
+	  && TYPE_CANONICAL (TREE_TYPE (i)) != NULL_TREE)
+	i = TEMPLATE_TYPE_PARM_INDEX (TYPE_CANONICAL (TREE_TYPE (i)));
+    }
+  return i;
+}
+
+/*  Add a descendant to a given template parameter index INDEX.  A
+    descendant of INDEX is the result of reducing the level of INDEX
+    to another level.  The property TEMPLATE_PARM_DESCENDANT of INDEX
+    is a vector that contains the descendants of INDEX.  This function
+    properly appends the descendant of INDEX to that
+    TEMPLATE_PARM_DESCENDANT vector.  */
+
+static void
+add_descendant_to_parm_index (tree index,
+			      tree descendant)
+{
+  tree *where = NULL;
+
+  gcc_assert (TREE_CODE (index) == TEMPLATE_PARM_INDEX
+	      && TREE_CODE (descendant) == TEMPLATE_PARM_INDEX
+	      && TEMPLATE_PARM_LEVEL (descendant) > 0
+	      && TEMPLATE_PARM_LEVEL (index) > 0
+	      && TEMPLATE_PARM_LEVEL (descendant) <= TEMPLATE_PARM_LEVEL (index));
+
+  if (TYPE_CANONICAL (TREE_TYPE (TEMPLATE_PARM_DECL (descendant)))
+      != NULL_TREE)
+    /*  For a descendant that requires canonical type comparison
+	(unlike for reduced template template parms) we only accept
+	types that have been fixed-up.  */
+    gcc_assert (TEMPLATE_PARM_SIBLINGS (descendant) != NULL_TREE);
+
+  index = get_root_index_same_level (index);
+
+  if (TEMPLATE_PARM_DESCENDANTS (index) == NULL_TREE)
+    TEMPLATE_PARM_DESCENDANTS (index) =
+      make_tree_vec (TEMPLATE_PARM_LEVEL (index));
+
+  where = &TREE_VEC_ELT (TEMPLATE_PARM_DESCENDANTS (index),
+			 TEMPLATE_PARM_LEVEL (descendant) - 1);
+
+  if (TREE_CODE (TEMPLATE_PARM_DECL (index)) == CONST_DECL)
+    {
+    /* INDEX is for a non-type template param.  So each one of its
+       descendant might have a different type.  To see that, consider:
+
+       template<class T> struct S
+       {
+       template<template<T i> class TT> struct Inner;
+       };
+
+       Then if we write:
+
+       S<int> s0;
+
+       As a result, in:
+	 
+       template<> template<template<int i> class TT>
+       S<int>::Inner<TT>
+
+       'i' has level 2, which was reduced from its inital level 3.
+       But look at how its type is 'int'.
+
+       But if we write:
+
+       S<char> s1;
+
+       Then, in:
+
+       template<> template<template<char i> class TT>
+       S<char>::Inner<TT>
+
+       'i' still has level 2 (reduced from initial level 3), but its
+       type is now 'char'.
+
+       So both 'i' of level 2 that are descendants of the initial
+       'i' of level 3, but each of them (might) have a separate
+       type.
+
+       Therefore, at each index of TEMPLATE_PARM_DESCENDANTS (that
+       represent a level) we have a TREE_LIST in which each
+       TREE_PURPOSE has the type of TEMPLATE_PARM_INDEX and each
+       TREE_VALUE has the TEMPLATE_PARM_INDEX itself.  */
+      if (*where != NULL_TREE)
+	gcc_assert (TEMPLATE_PARM_LEVEL (TREE_VALUE (*where)) 
+		    == TEMPLATE_PARM_LEVEL (descendant));
+      *where = tree_cons (TREE_TYPE (descendant),
+			  descendant,
+			  *where);
+    }
+  else
+    {
+      if (*where == NULL_TREE)
+	*where = descendant;
+      else
+	gcc_assert (same_type_p (TREE_TYPE (*where),
+				 TREE_TYPE (descendant)));
+    }
+}
+
+/*  Inspect the TEMPLATE_PARM_DESCENDANTS vector associated to INDEX
+    to return its descendant for a given level and type.  */
+
+static tree
+get_descendant_of_parm_index (tree index,
+			      int level,
+			      tree type)
+{
+  tree result = NULL_TREE, orig_index = index;
+
+  gcc_assert (TREE_CODE (index) == TEMPLATE_PARM_INDEX
+	      && TEMPLATE_PARM_LEVEL (index) > 0
+	      && level > 0);
+
+  index = get_root_index_same_level (index);
+
+  if (TEMPLATE_PARM_DESCENDANTS (index))
+    {
+      gcc_assert (TREE_CODE (TEMPLATE_PARM_DESCENDANTS (index)) == TREE_VEC);
+      if (TREE_VEC_LENGTH (TEMPLATE_PARM_DESCENDANTS (index)) >= level)
+	{
+	  tree elem = TREE_VEC_ELT (TEMPLATE_PARM_DESCENDANTS (index),
+				    level - 1);
+	  if (TREE_CODE (TEMPLATE_PARM_DECL (index)) == CONST_DECL)
+	    /* We are looking for the index of a non-type template
+	       parm.  */
+	    for (; elem != NULL_TREE; elem = TREE_CHAIN (elem))
+	      {
+		if (same_type_p (TREE_TYPE (TREE_VALUE (elem)),
+				 type))
+		  result = TREE_VALUE (elem);
+	      }
+	  else
+	    /* We are looking for the index of type template parm.  */
+	    result = elem;
+	  if (result != NULL_TREE
+	      && (TEMPLATE_PARM_LEVEL (result) != TEMPLATE_PARM_LEVEL (orig_index))
+	      && (DECL_SOURCE_LOCATION (TEMPLATE_PARM_DECL (result))
+		  != DECL_SOURCE_LOCATION (TEMPLATE_PARM_DECL (orig_index))))
+	    {
+	      /*  We have gotten an equivalent index, that was reduced
+		  from an index equivalent to ORIG_INDEX, but which
+		  (location of) DECL is different.  This can lead to
+		  having error messages pointing to the wrong
+		  location, so let's build an equivalent
+		  TEMPLATE_PARM_INDEX with a DECL pointing to the same
+		  location as ORIG_INDEX for RESULT.  */
+	      tree decl, orig_decl, orig_result = result, decl_type;
+
+	      decl = orig_decl = TEMPLATE_PARM_DECL (orig_index);
+
+	      if (TREE_CODE (decl) == TYPE_DECL
+		  || TREE_CODE (decl) == PARM_DECL
+		  || TREE_CODE (decl) == CONST_DECL)
+		{
+		  decl = build_decl (DECL_SOURCE_LOCATION (orig_decl),
+				     TREE_CODE (orig_decl), DECL_NAME (orig_decl),
+				     TREE_TYPE (result));
+		  TREE_CONSTANT (decl) = TREE_CONSTANT (orig_decl);
+		  TREE_READONLY (decl) = TREE_READONLY (orig_decl);
+		  DECL_ARTIFICIAL (decl) = 1;
+		  SET_DECL_TEMPLATE_PARM_P (decl);
+
+		  result = build_template_parm_index (TEMPLATE_PARM_IDX (result),
+						      TEMPLATE_PARM_LEVEL (result),
+						      TEMPLATE_PARM_ORIG_INDEX (result),
+						      TEMPLATE_PARM_SIBLINGS (result),
+						      decl,
+						      TREE_TYPE (result));
+		  TEMPLATE_PARM_PARAMETER_PACK (result) =
+		    TEMPLATE_PARM_PARAMETER_PACK (orig_result);
+		  TEMPLATE_PARM_DESCENDANTS (result) =
+		    TEMPLATE_PARM_DESCENDANTS (orig_result);
+
+		  decl_type = copy_type (TREE_TYPE (decl));
+		  TYPE_NAME (decl_type) = decl;
+		  TREE_TYPE (decl) = decl_type;
+		  TREE_TYPE (result) = decl_type;
+		}
+	    }
+
+	}
+    }
+  return result;
+}
+
+/*  Return the TEMPLATE_PARM_INDEX of a template parameter PARM.  PARM
+    can be either the type of a template parameter, or its DECL.  */
+
+static tree
+get_template_parm_index (tree parm)
+{
+  tree result = NULL_TREE;
+
+  switch (TREE_CODE (parm))
+    {
+    case TEMPLATE_PARM_INDEX:
+      result = parm;
+      break;
+
+    case TEMPLATE_TYPE_PARM:
+    case TEMPLATE_TEMPLATE_PARM:
+    case BOUND_TEMPLATE_TEMPLATE_PARM:
+      result = TEMPLATE_TYPE_PARM_INDEX (parm);
+      break;
+
+    case PARM_DECL:
+    case CONST_DECL:
+      gcc_assert (DECL_TEMPLATE_PARM_P (parm));
+      return get_template_parm_index (DECL_INITIAL (parm));
+
+    case TEMPLATE_DECL:
+    case TYPE_DECL:
+      gcc_assert (DECL_TEMPLATE_PARM_P (parm));      
+      return get_template_parm_index (TREE_TYPE (parm));
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return result;
+}
+
 /* Create a new type almost identical to TYPE but which has the
    following differences:
 
-     1/ T has a new TEMPLATE_PARM_INDEX that carries the new number of
-     template sibling parameters of T.
+     1/ T has a new TEMPLATE_PARM_INDEX that carries the set of
+     sibling template parameters of T.
 
-     2/ T has a new canonical type that matches the new number
-     of sibling parms.
+     2/ T has a new canonical type that matches the set of sibling
+     parms.
 
      3/ From now on, T is going to be what lookups referring to the
-     name of TYPE will return. No lookup should return TYPE anymore.
+     name of TYPE will return.  No lookup should return TYPE anymore.
 
-   NUM_PARMS is the new number of sibling parms TYPE belongs to.
+   SIBLING_PARMS is the set of sibling parms TYPE belongs to.
 
-   This is a subroutine of fixup_template_parms.  */
+   This is a subroutine of fixup_innermost_template_parms.  */
 
 static tree
-fixup_template_type_parm_type (tree type, int num_parms)
+fixup_template_type_parm_type (tree type, tree sibling_parms)
 {
-  tree orig_idx = TEMPLATE_TYPE_PARM_INDEX (type), idx;
-  tree t;
+  tree orig_idx = TEMPLATE_TYPE_PARM_INDEX (type),
+    t, idx, parent_idx = NULL_TREE;
   /* This is the decl which name is inserted into the symbol table for
      the template parm type. So whenever we lookup the type name, this
      is the DECL we get.  */
   tree decl;
 
   /* Do not fix up the type twice.  */
-  if (orig_idx && TEMPLATE_PARM_NUM_SIBLINGS (orig_idx) != 0)
+  if (orig_idx && TEMPLATE_PARM_SIBLINGS (orig_idx) != NULL_TREE)
     return type;
 
   t = copy_type (type);
@@ -3692,12 +4021,19 @@ fixup_template_type_parm_type (tree type, int num_parms)
   TYPE_POINTER_TO (t) = 0;
   TYPE_REFERENCE_TO (t) = 0;
 
+  if (TEMPLATE_PARM_LEVEL (TEMPLATE_PARM_ORIG_INDEX (orig_idx))
+      != TEMPLATE_PARM_LEVEL (orig_idx))
+    /* We are fixing up a type which TEMPLATE_TYPE_PARM_INDEX is the
+       result of level-reduction.  Keep a pointer to the original
+       upper (fixed-up) level index.  */
+    parent_idx = TEMPLATE_PARM_ORIG_INDEX (orig_idx);
+
   idx = build_template_parm_index (TEMPLATE_PARM_IDX (orig_idx),
 				   TEMPLATE_PARM_LEVEL (orig_idx),
-				   TEMPLATE_PARM_ORIG_LEVEL (orig_idx),
-				   num_parms,
+				   parent_idx,
+				   sibling_parms,
 				   decl, t);
-  TEMPLATE_PARM_DESCENDANTS (idx) = TEMPLATE_PARM_DESCENDANTS (orig_idx);
+
   TEMPLATE_PARM_PARAMETER_PACK (idx) = TEMPLATE_PARM_PARAMETER_PACK (orig_idx);
   TEMPLATE_TYPE_PARM_INDEX (t) = idx;
 
@@ -3711,7 +4047,15 @@ fixup_template_type_parm_type (tree type, int num_parms)
      type is properly fixed up.  */
   TREE_TYPE (decl) = t;
 
-  TYPE_CANONICAL (t) = canonical_type_parameter (t);
+  /* Don't set canonical type if the original type was requiring
+     structural equality.  This can happen for e.g, types of template
+     template parms that got level-reduced.  */
+  if (!TYPE_STRUCTURAL_EQUALITY_P (type))
+    TYPE_CANONICAL (t) = canonical_type_parameter (t);
+
+  /*  Update TEMPLATE_PARM_DESCENDANTS (TEMPLATE_PARM_ORIG_INDEX
+      (orig_idx)).  */
+  add_descendant_to_parm_index (TEMPLATE_PARM_ORIG_INDEX (idx), idx);
 
   return t;
 }
@@ -3719,35 +4063,41 @@ fixup_template_type_parm_type (tree type, int num_parms)
 /* Create and return a new TEMPLATE_PARM_INDEX that is almost
    identical to I, but that is fixed up as to:
 
-   1/ carry the number of sibling parms (NUM_PARMS) of the template
+   1/ carry the set of sibling parms (SIBLING_PARMS) of the template
    parm represented by I.
 
    2/ replace all references to template parm types declared before I
    (in the same template parm list as I) by references to template
-   parm types contained in ARGS. ARGS should contain the list of
+   parm types contained in ARGS.  ARGS should contain the list of
    template parms that have been fixed up so far, in a form suitable
    to be passed to tsubst.
 
-   This is a subroutine of fixup_template_parms.  */
+   This is a subroutine of fixup_innermost_template_parms.  */
 
 static tree
-fixup_template_parm_index (tree i, tree args, int num_parms)
+fixup_template_parm_index (tree i, tree args, tree sibling_parms)
 {
-  tree index, decl, type;
+  tree index, decl, type, parent_idx = NULL_TREE;
 
   if (i == NULL_TREE
       || TREE_CODE (i) != TEMPLATE_PARM_INDEX
       /* Do not fix up the index twice.  */
-      || (TEMPLATE_PARM_NUM_SIBLINGS (i) != 0))
+      || (TEMPLATE_PARM_SIBLINGS (i) != NULL_TREE))
     return i;
 
   decl = TEMPLATE_PARM_DECL (i);
   type = TREE_TYPE (decl);
 
+  if (TEMPLATE_PARM_LEVEL (TEMPLATE_PARM_ORIG_INDEX (i))
+      != TEMPLATE_PARM_LEVEL (i))
+    /* We are fixing up a type which TEMPLATE_TYPE_PARM_INDEX is the
+       result or a level-reduction.  Keep a pointer to the original
+       upper (fixed-up) level.  */
+    parent_idx = TEMPLATE_PARM_ORIG_INDEX (i);
+
   index = build_template_parm_index (TEMPLATE_PARM_IDX (i),
 				     TEMPLATE_PARM_LEVEL (i),
-				     TEMPLATE_PARM_ORIG_LEVEL (i),
-				     num_parms,
+				     parent_idx, sibling_parms,
 				     decl, type);
 
   TEMPLATE_PARM_DESCENDANTS (index) = TEMPLATE_PARM_DESCENDANTS (i);
@@ -3758,11 +4108,15 @@ fixup_template_parm_index (tree i, tree args, int num_parms)
   TREE_TYPE (decl) = type;
   TREE_TYPE (index) = type;
 
+  /* Update descendants of the original index INDEX is reduced
+     from.  */
+  add_descendant_to_parm_index (TEMPLATE_PARM_ORIG_INDEX (index),
+				index);
   return index;
 }
 
 /* 
-   This is a subroutine of fixup_template_parms.
+   This is a subroutine of fixup_innermost_template_parms.
 
    It computes the canonical type of the type of the template
    parameter PARM_DESC and update all references to that type so that
@@ -3770,8 +4124,8 @@ fixup_template_parm_index (tree i, tree args, int num_parms)
    performed during the fixup. PARM_DESC is a TREE_LIST which
    TREE_VALUE is the template parameter and its TREE_PURPOSE is the
    default argument of the template parm if any. IDX is the index of
-   the template parameter, starting at 0. NUM_PARMS is the number of
-   template parameters in the set PARM_DESC belongs to. ARGLIST is a
+   the template parameter, starting at 0. SIBLING_PARMS is the set of
+   template parameters the PARM_DESC belongs to. ARGLIST is a
    TREE_VEC containing the full set of template parameters in a form
    suitable to be passed to substs functions as their ARGS
    argument. This is what current_template_args returns for a given
@@ -3782,11 +4136,18 @@ fixup_template_parm_index (tree i, tree args, int num_parms)
 static void
 fixup_template_parm (tree parm_desc,
 		     int idx,
-		     int num_parms,
+		     tree sibling_parms,
 		     tree arglist)
 {
   tree parm = TREE_VALUE (parm_desc);
-  tree fixedup_args = INNERMOST_TEMPLATE_ARGS (arglist);
+  tree fixedup_args;
+  int level;
+
+  if (parm == error_mark_node)
+    return;
+
+  template_parm_level_and_index (parm, &level, NULL);
+  fixedup_args = TMPL_ARGS_LEVEL (arglist, level);
 
   push_deferring_access_checks (dk_no_check);
 
@@ -3798,7 +4159,7 @@ fixup_template_parm (tree parm_desc,
 	 template parms into the default argument of this
 	 parameter.  */
       tree t =
-	fixup_template_type_parm_type (TREE_TYPE (parm), num_parms);
+	fixup_template_type_parm_type (TREE_TYPE (parm), sibling_parms);
       TREE_TYPE (parm) = t;
 
       TREE_VEC_ELT (fixedup_args, idx) = template_parm_to_arg (parm_desc);
@@ -3852,13 +4213,12 @@ fixup_template_parm (tree parm_desc,
 	    template_parm_to_arg (parameter);
 
 	  fixup_template_parm (parameter, j,
-			       TREE_VEC_LENGTH (tparms),
-			       targs);
+			       tparms, targs);
 	}
 
       /* Now fix up the type of the template template parm.  */
 
-      t = fixup_template_type_parm_type (TREE_TYPE (parm), num_parms);
+      t = fixup_template_type_parm_type (TREE_TYPE (parm), sibling_parms);
       TREE_TYPE (parm) = t;
 
       TREE_VEC_ELT (fixedup_args, idx) =
@@ -3898,7 +4258,7 @@ fixup_template_parm (tree parm_desc,
 	 fixup the type of PUSHED_DECL as well and luckily
 	 fixup_template_parm_index does it for us too.  */
       tree fixed_up_index =
-	fixup_template_parm_index (index, arglist, num_parms);
+	fixup_template_parm_index (index, arglist, sibling_parms);
 
       DECL_INITIAL (pushed_decl) = DECL_INITIAL (parm) = fixed_up_index;
 
@@ -3918,39 +4278,99 @@ fixup_template_parm (tree parm_desc,
   pop_deferring_access_checks ();
 }
 
-/* Walk the current template parms and properly compute the canonical
-   types of the dependent types created during
-   cp_parser_template_parameter_list.  */
+/* Walk the innermost template parameters of PARMS parms and properly
+   compute the canonical types of the dependent types created during
+   cp_parser_template_parameter_list.  ARGLIST contains a TREE_VEC of
+   arguments built from the elements of PARMS that have been fixed-up
+   so far.  This function  udpates ARGLIST as it runs.  If the caller
+   of this function  is not interested in getting ARGLIST, it can
+   set it to NULL_TREE.  */
 
-void
-fixup_template_parms (void)
+static void
+fixup_innermost_template_parms (tree parms, tree arglist)
 {
-  tree arglist;
   tree parameter_vec;
-  tree fixedup_args;
   int i, num_parms;
 
-  parameter_vec = INNERMOST_TEMPLATE_PARMS (current_template_parms);
+  if (parms == NULL_TREE || parms == error_mark_node)
+    return;
+
+  parameter_vec = INNERMOST_TEMPLATE_PARMS (parms);
   if (parameter_vec == NULL_TREE)
     return;
 
   num_parms = TREE_VEC_LENGTH (parameter_vec);
 
-  /* This vector contains the current innermost template parms that
-     have been fixed up so far.  The form of FIXEDUP_ARGS is suitable
-     to be passed to tsubst* functions as their ARGS argument.  */
-  fixedup_args = make_tree_vec (num_parms);
-
   /* This vector contains the full set of template parms in a form
      suitable to be passed to substs functions as their ARGS
      argument.  */
-  arglist = current_template_args ();
-  arglist = add_outermost_template_args (arglist, fixedup_args);
+  if (arglist == NULL_TREE)
+    {
+      tree fixedup_args;
+      arglist = template_parms_to_args (parms);
+      /* This vector contains the current innermost template parms
+	 that have been fixed up so far.  The form of ARGLIST is
+	 suitable to be passed to tsubst* functions as their ARGS
+	 argument.  */
+      fixedup_args = make_tree_vec (num_parms);
+      arglist = add_outermost_template_args (arglist, fixedup_args);
+    }
 
   /* Let's do the proper fixup now.  */
   for (i = 0; i < num_parms; ++i)
     fixup_template_parm (TREE_VEC_ELT (parameter_vec, i),
-			 i, num_parms, arglist);
+			 i, parameter_vec, arglist);
+}
+
+/*  Fixup the template parameters PARMS; that is, compute the
+    canonical types of each parameter therein.
+
+    Note that PARMS must be of the form described in the comments of
+    the DECL_TEMPLATE_PARMS accessor in cp-tree.h.  */
+
+void
+fixup_template_parms (tree parms)
+{
+  tree level, args;
+  int i;
+
+  if (parms == NULL_TREE || parms == error_mark_node)
+    return;
+
+
+  if (TMPL_PARMS_DEPTH (parms) > 1)
+    {
+      int parms_depth = TMPL_PARMS_DEPTH (parms);
+      args = make_tree_vec (parms_depth);
+      for (i = 0; i < parms_depth; ++i)
+	{
+	  level = get_template_parms_at_level (parms, i + 1);
+	  if (level == NULL_TREE)
+	    continue;
+	  TREE_VEC_ELT (args, i) =
+	    make_tree_vec (TREE_VEC_LENGTH (TREE_VALUE (level)));
+	}
+    }
+  else
+    args = make_tree_vec (TREE_VEC_LENGTH (TREE_VALUE (parms)));
+
+  /* Template parms ought to be fixed-up from left to right.  */
+  parms = nreverse (parms);
+
+  for (level = parms; level != NULL_TREE; level = TREE_CHAIN (level))
+    fixup_innermost_template_parms (level, args);
+
+  parms = nreverse (parms);
+}
+
+/* Walk the current template parms and properly compute the canonical
+   types of the dependent types created during
+   cp_parser_template_parameter_list.  */
+
+void
+fixup_current_template_parms (void)
+{
+  fixup_innermost_template_parms (current_template_parms, NULL_TREE);
 }
 
 /* end_template_decl is called after a template declaration is seen.  */
@@ -4032,6 +4452,62 @@ template_parm_to_arg (tree t)
   return t;
 }
 
+/*  Transform a list of of template parameters into a list of
+    arguments, suitable to be passed to tsubst as its ARGS parameter.
+    The list of template parameters has the same format as the one
+    described in the comments of DECL_TEMPLATE_PARMS in cp-tree.h.  */
+
+static tree
+template_parms_to_args (tree parms)
+{
+  tree header;
+  tree args = NULL_TREE;
+  int length = TMPL_PARMS_DEPTH (parms);
+  int l = length;
+
+  /* If there is only one level of template parameters, we do not
+     create a TREE_VEC of TREE_VECs.  Instead, we return a single
+     TREE_VEC containing the arguments.  */
+  if (length > 1)
+    args = make_tree_vec (length);
+
+  for (header = parms; header; header = TREE_CHAIN (header))
+    {
+      tree a = copy_node (TREE_VALUE (header));
+      int i;
+
+      TREE_TYPE (a) = NULL_TREE;
+      for (i = TREE_VEC_LENGTH (a) - 1; i >= 0; --i)
+	TREE_VEC_ELT (a, i) = template_parm_to_arg (TREE_VEC_ELT (a, i));
+
+#ifdef ENABLE_CHECKING
+      SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (a, TREE_VEC_LENGTH (a));
+#endif
+
+      if (length > 1)
+	TREE_VEC_ELT (args, --l) = a;
+      else
+	args = a;
+    }
+
+    if (length > 1 && TREE_VEC_ELT (args, 0) == NULL_TREE)
+      /* This can happen for template parms of a template template
+	 parameter, e.g:
+
+	 template<template<class T, class U> class TT> struct S;
+
+	 Consider the level of the parms of TT; T and U both have
+	 level 2; TT has no template parm of level 1. So in this case
+	 the first element of full_template_args is NULL_TREE. If we
+	 leave it like this TMPL_ARG_DEPTH on args returns 1 instead
+	 of 2. This will make tsubst wrongly consider that T and U
+	 have level 1. Instead, let's create a dummy vector as the
+	 first element of full_template_args so that TMPL_ARG_DEPTH
+	 returns the correct depth for args.  */
+      TREE_VEC_ELT (args, 0) = make_tree_vec (1);
+  return args;
+}
+
 /* This function returns TRUE if PARM_PACK is a template parameter
    pack and if ARG_PACK is what template_parm_to_arg returned when
    passed PARM_PACK.  */
@@ -4089,60 +4565,92 @@ arg_from_parm_pack_p (tree arg_pack, tree parm_pack)
   return false;
 }
 
-/* Within the declaration of a template, return all levels of template
-   parameters that apply.  The template parameters are represented as
-   a TREE_VEC, in the form documented in cp-tree.h for template
-   arguments.  */
-
-static tree
-current_template_args (void)
-{
-  tree header;
-  tree args = NULL_TREE;
-  int length = TMPL_PARMS_DEPTH (current_template_parms);
-  int l = length;
+/* When a template parameter PARM_PACK is a pack that is part of a
+   pack expansion EXPANSION and when EXPANSION has been partially
+   instantiated (or rather substituted into) with a set of arguments
+   ARGS0 which depth is less than the level of PARM_PACK, the level of
+   PARM_PACK is not reduced, unlike what happens for a non-pack
+   template parameter.
+
+   Rather, EXPANSION remembers ARGS0 and later, when an attempt to
+   instantiate EXPANSION with a set of arguments ARGS1 which is so
+   that the set {ARGS0, ARGS1} is deep enough to fully instantiate
+   EXPANSION, EXPANSION is substituted into with the arguments {ARGS0,
+   ARGS1}.
+
+   So in the time interval between when EXPANSION remembers ARGS0 and
+   when it gets ARGS1, the level of E stays the same, even if it has
+   been morally reduced.  If the type fixup of E happens in that time
+   interval, we'll need to be able to detect that ARG_PACK is the
+   result of template_parm_to_arg called on PARM_PACK' - which is the result
+   of morally reducing the level of PARM_PACK and fixing up its
+   type.
+
+   Note that because of the complication that arises due to the way
+   pack expansions handle partial instantiations of parameter packs,
+   arg_from_parm_pack_p won't work on arg_pack and parm_pack.
+
+   This function should thus return true if ARG_PACK is the result of
+     1/ morally level-reducing parameter pack PARM_PACK
+     2/ fixing-up the result of 1/
+     3/ passing the result 2/ to template_parm_to_arg.
+
+   FIXME: This function does an approximation, as it only checks that
+   the levels of PARM_PACK/EXPANSION and ARG_PACK do match.  For it to
+   be precise, I think the TEMPLATE_PARM_INDEX of PARM_PACK should
+   track its pre-fixup type, so that ARG_PACK could be compared with
+   that type instead.  But that would increase the size of the
+   template_parm_index_s struct, as I don't see where else I could
+   store the pre-fixup type.  */
 
-  /* If there is only one level of template parameters, we do not
-     create a TREE_VEC of TREE_VECs.  Instead, we return a single
-     TREE_VEC containing the arguments.  */
-  if (length > 1)
-    args = make_tree_vec (length);
+static bool
+arg_from_reduced_and_fixedup_parm_pack_of_expansion_p (tree arg_pack,
+						       tree parm_pack,
+						       tree expansion)
+{
+  /* We want parm_pack to be a type or non-type parameter pack.  */
+  if (parm_pack == NULL_TREE
+      || (!template_type_parameter_type_p (parm_pack)
+	  && !(DECL_P (parm_pack) && DECL_TEMPLATE_PARM_P (parm_pack))
+	  && TREE_CODE (parm_pack) != TEMPLATE_PARM_INDEX))
+    return false;
 
-  for (header = current_template_parms; header; header = TREE_CHAIN (header))
+  if (arg_pack
+      && TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack)) == 1
+      && PACK_EXPANSION_P (TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack), 0)))
     {
-      tree a = copy_node (TREE_VALUE (header));
-      int i;
+      tree e = TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack), 0);
+      tree p = PACK_EXPANSION_PATTERN (e);
+      tree extra_args = PACK_EXPANSION_EXTRA_ARGS (expansion);
+      tree index_p, index_parm_pack;
+      int extra_args_depth = extra_args ? TMPL_ARGS_DEPTH (extra_args) : 0;
 
-      TREE_TYPE (a) = NULL_TREE;
-      for (i = TREE_VEC_LENGTH (a) - 1; i >= 0; --i)
-	TREE_VEC_ELT (a, i) = template_parm_to_arg (TREE_VEC_ELT (a, i));
+      if (TREE_CODE (p) != TREE_CODE (parm_pack))
+	return false;
 
-#ifdef ENABLE_CHECKING
-      SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (a, TREE_VEC_LENGTH (a));
-#endif
+      index_p = get_template_parm_index (p);
+      index_parm_pack = get_template_parm_index (parm_pack);
 
-      if (length > 1)
-	TREE_VEC_ELT (args, --l) = a;
-      else
-	args = a;
+      if (extra_args_depth != 0
+	  && (TEMPLATE_PARM_LEVEL (index_p)
+	      == TEMPLATE_PARM_LEVEL (index_parm_pack) - extra_args_depth)
+	  && (TEMPLATE_PARM_IDX (index_p)
+	      == TEMPLATE_PARM_IDX (index_parm_pack)))
+	return true;
     }
 
-    if (length > 1 && TREE_VEC_ELT (args, 0) == NULL_TREE)
-      /* This can happen for template parms of a template template
-	 parameter, e.g:
+  return false;
+}
 
-	 template<template<class T, class U> class TT> struct S;
+/* Within the declaration of a template, return all levels of template
+   parameters that apply.  The template parameters are represented as
+   a TREE_VEC, in the form documented in cp-tree.h for template
+   arguments.  */
 
-	 Consider the level of the parms of TT; T and U both have
-	 level 2; TT has no template parm of level 1. So in this case
-	 the first element of full_template_args is NULL_TREE. If we
-	 leave it like this TMPL_ARG_DEPTH on args returns 1 instead
-	 of 2. This will make tsubst wrongly consider that T and U
-	 have level 1. Instead, let's create a dummy vector as the
-	 first element of full_template_args so that TMPL_ARG_DEPTH
-	 returns the correct depth for args.  */
-      TREE_VEC_ELT (args, 0) = make_tree_vec (1);
-  return args;
+static tree
+current_template_args (void)
+{
+  return template_parms_to_args (current_template_parms);
 }
 
 /* Update the declared TYPE by doing any lookups which were thought to be
@@ -4851,6 +5359,8 @@ push_template_decl_real (tree decl, bool is_friend)
 	       && TYPE_DECL_ALIAS_P (decl))
 	/* alias-declaration */
 	gcc_assert (!DECL_ARTIFICIAL (decl));
+      else if (is_friend && TREE_CODE (TREE_TYPE (decl)) == TYPENAME_TYPE)
+	/* OK */;
       else
 	{
 	  error ("template declaration of %q#D", decl);
@@ -4917,7 +5427,8 @@ push_template_decl_real (tree decl, bool is_friend)
   if (!ctx
       || TREE_CODE (ctx) == FUNCTION_DECL
       || (CLASS_TYPE_P (ctx) && TYPE_BEING_DEFINED (ctx))
-      || (is_friend && !DECL_TEMPLATE_INFO (decl)))
+      || (is_friend && (!DECL_LANG_SPECIFIC (decl)
+			|| !DECL_TEMPLATE_INFO (decl))))
     {
       if (DECL_LANG_SPECIFIC (decl)
 	  && DECL_TEMPLATE_INFO (decl)
@@ -5120,7 +5631,7 @@ template arguments to %qD do not match original template %qD",
     SET_TYPE_TEMPLATE_INFO (TREE_TYPE (tmpl), info);
   else
     {
-      if (primary && !DECL_LANG_SPECIFIC (decl))
+      if ((primary || is_friend) && !DECL_LANG_SPECIFIC (decl))
 	retrofit_lang_decl (decl);
       if (DECL_LANG_SPECIFIC (decl))
 	DECL_TEMPLATE_INFO (decl) = info;
@@ -6909,10 +7420,12 @@ coerce_template_parms (tree parms,
   return new_inner_args;
 }
 
-/* Returns 1 if template args OT and NT are equivalent.  */
+/* Returns 1 if template args OT and NT are equivalent.  STRICT
+   controls how the comparison is done, with the same semantics as
+   for the last parameter of comptypes.  */
 
 static int
-template_args_equal (tree ot, tree nt)
+template_args_equal_guided (tree ot, tree nt, int strict)
 {
   if (nt == ot)
     return 1;
@@ -6921,13 +7434,16 @@ template_args_equal (tree ot, tree nt)
 
   if (TREE_CODE (nt) == TREE_VEC)
     /* For member templates */
-    return TREE_CODE (ot) == TREE_VEC && comp_template_args (ot, nt);
+    return (TREE_CODE (ot) == TREE_VEC
+	    && comp_template_args_guided (ot, nt, NULL, NULL, strict));
   else if (PACK_EXPANSION_P (ot))
     return (PACK_EXPANSION_P (nt)
-	    && template_args_equal (PACK_EXPANSION_PATTERN (ot),
-				    PACK_EXPANSION_PATTERN (nt))
-	    && template_args_equal (PACK_EXPANSION_EXTRA_ARGS (ot),
-				    PACK_EXPANSION_EXTRA_ARGS (nt)));
+	    && template_args_equal_guided (PACK_EXPANSION_PATTERN (ot),
+					   PACK_EXPANSION_PATTERN (nt),
+					   strict)
+	    && template_args_equal_guided (PACK_EXPANSION_EXTRA_ARGS (ot),
+					   PACK_EXPANSION_EXTRA_ARGS (nt),
+					   strict));
   else if (ARGUMENT_PACK_P (ot))
     {
       int i, len;
@@ -6942,8 +7458,9 @@ template_args_equal (tree ot, tree nt)
       if (TREE_VEC_LENGTH (npack) != len)
 	return 0;
       for (i = 0; i < len; ++i)
-	if (!template_args_equal (TREE_VEC_ELT (opack, i),
-				  TREE_VEC_ELT (npack, i)))
+	if (!template_args_equal_guided (TREE_VEC_ELT (opack, i),
+					 TREE_VEC_ELT (npack, i),
+					 strict))
 	  return 0;
       return 1;
     }
@@ -6957,23 +7474,32 @@ template_args_equal (tree ot, tree nt)
       ot = ARGUMENT_PACK_SELECT_FROM_PACK (ot);
       if (nt && TREE_CODE (nt) == ARGUMENT_PACK_SELECT)
 	nt = ARGUMENT_PACK_SELECT_FROM_PACK (nt);
-      return template_args_equal (ot, nt);
+      return template_args_equal_guided (ot, nt, strict);
     }
   else if (TYPE_P (nt))
-    return TYPE_P (ot) && same_type_p (ot, nt);
+    return TYPE_P (ot) && comptypes (ot, nt, strict);
   else if (TREE_CODE (ot) == TREE_VEC || TYPE_P (ot))
     return 0;
   else
     return cp_tree_equal (ot, nt);
 }
 
+/* Returns 1 if template args OT and NT are equivalent.  */
+
+static int
+template_args_equal (tree ot, tree nt)
+{
+  return template_args_equal_guided (ot, nt, COMPARE_STRICT);
+}
+
 /* Returns 1 iff the OLDARGS and NEWARGS are in fact identical sets of
    template arguments.  Returns 0 otherwise, and updates OLDARG_PTR and
    NEWARG_PTR with the offending arguments if they are non-NULL.  */
 
-static int
-comp_template_args_with_info (tree oldargs, tree newargs,
-			      tree *oldarg_ptr, tree *newarg_ptr)
+int
+comp_template_args_guided (tree oldargs, tree newargs,
+			   tree *oldarg_ptr, tree *newarg_ptr,
+			   int strict)
 {
   int i;
 
@@ -6991,7 +7517,7 @@ comp_template_args_with_info (tree oldargs, tree newargs,
       tree nt = TREE_VEC_ELT (newargs, i);
       tree ot = TREE_VEC_ELT (oldargs, i);
 
-      if (! template_args_equal (ot, nt))
+      if (! template_args_equal_guided (ot, nt, strict))
 	{
 	  if (oldarg_ptr != NULL)
 	    *oldarg_ptr = ot;
@@ -7009,7 +7535,8 @@ comp_template_args_with_info (tree oldargs, tree newargs,
 int
 comp_template_args (tree oldargs, tree newargs)
 {
-  return comp_template_args_with_info (oldargs, newargs, NULL, NULL);
+  return comp_template_args_guided (oldargs, newargs,
+				    NULL, NULL, COMPARE_STRICT);
 }
 
 static void
@@ -9362,7 +9889,10 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
 	  return result;
 	}
 
-      if (arg_from_parm_pack_p (arg_pack, parm_pack))
+      if (arg_from_parm_pack_p (arg_pack, parm_pack)
+	  || arg_from_reduced_and_fixedup_parm_pack_of_expansion_p (arg_pack,
+								    parm_pack,
+								    t))
 	/* The argument pack that the parameter maps to is just an
 	   expansion of the parameter itself, such as one would find
 	   in the implicit typedef of a class inside the class itself.
@@ -9716,7 +10246,14 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl)
    PARMS, then the result will contain n levels of PARMS.  For
    example, if PARMS is `template <class T> template <class U>
    template <T*, U, class V>' and ARGS is {{int}, {double}} then the
-   result will be `template <int*, double, class V>'.  */
+   result will be `template <int*, double, class V>'.
+
+   If the depth of ARGS is less than the depth of PARMS, it most
+   probably means we are looking at the partial instantiation of a
+   member template.  This implies that the resulting set of template
+   parms is going to be level-reduced.  In that case, this function
+   does the proper type fixing-up of the reduced template
+   parameters.  */
 
 static tree
 tsubst_template_parms (tree parms, tree args, tsubst_flags_t complain)
@@ -9724,6 +10261,9 @@ tsubst_template_parms (tree parms, tree args, tsubst_flags_t complain)
   tree r = NULL_TREE;
   tree* new_parms;
 
+  if (parms == NULL_TREE || parms == error_mark_node)
+    return parms;
+
   /* When substituting into a template, we must set
      PROCESSING_TEMPLATE_DECL as the template parameters may be
      dependent if they are based on one-another, and the dependency
@@ -9761,6 +10301,7 @@ tsubst_template_parms (tree parms, tree args, tsubst_flags_t complain)
 		   new_vec, NULL_TREE);
     }
 
+  fixup_template_parms (r);
   --processing_template_decl;
 
   return r;
@@ -9829,6 +10370,12 @@ tsubst_aggr_type (tree t,
 	  int saved_unevaluated_operand;
 	  int saved_inhibit_evaluation_warnings;
 
+	  /* If T is a member template being partially instantiated,
+	     fixup its template parameters that are to be
+	     level-reduced.  */
+	  tsubst_template_parms (DECL_TEMPLATE_PARMS (TYPE_TI_TEMPLATE (t)),
+				 args, complain);
+
 	  /* In "sizeof(X<I>)" we need to evaluate "I".  */
 	  saved_unevaluated_operand = cp_unevaluated_operand;
 	  cp_unevaluated_operand = 0;
@@ -9998,6 +10545,15 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	tree spec;
 	tree tmpl_args;
 	tree full_args;
+	tree fixedup_parms;
+
+	/* If T is a member template being partially instantiated,
+	   fixup its template parameters that are to be
+	   level-reduced.  */
+	++processing_template_decl;
+	fixedup_parms = tsubst_template_parms (DECL_TEMPLATE_PARMS (t),
+					       args, complain);
+	--processing_template_decl;
 
 	if (DECL_TEMPLATE_TEMPLATE_PARM_P (t))
 	  {
@@ -10073,6 +10629,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 
 	    TREE_TYPE (r) = new_type;
 	    CLASSTYPE_TI_TEMPLATE (new_type) = r;
+	    DECL_TEMPLATE_PARMS (r) = fixedup_parms;
 	    DECL_TEMPLATE_RESULT (r) = TYPE_MAIN_DECL (new_type);
 	    DECL_TI_ARGS (r) = CLASSTYPE_TI_ARGS (new_type);
 	    DECL_CONTEXT (r) = TYPE_CONTEXT (new_type);
@@ -10088,6 +10645,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 
 	    DECL_TEMPLATE_RESULT (r) = new_decl;
 	    DECL_TI_TEMPLATE (new_decl) = r;
+	    DECL_TEMPLATE_PARMS (r) = fixedup_parms;
 	    TREE_TYPE (r) = TREE_TYPE (new_decl);
 	    DECL_TI_ARGS (r) = DECL_TI_ARGS (new_decl);
 	    DECL_CONTEXT (r) = DECL_CONTEXT (new_decl);
@@ -10097,13 +10655,6 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	DECL_TEMPLATE_INSTANTIATIONS (r) = NULL_TREE;
 	DECL_TEMPLATE_SPECIALIZATIONS (r) = NULL_TREE;
 
-	/* The template parameters for this new template are all the
-	   template parameters for the old template, except the
-	   outermost level of parameters.  */
-	DECL_TEMPLATE_PARMS (r)
-	  = tsubst_template_parms (DECL_TEMPLATE_PARMS (t), args,
-				   complain);
-
 	if (PRIMARY_TEMPLATE_P (t))
 	  DECL_PRIMARY_TEMPLATE (r) = r;
 
@@ -11642,11 +12193,21 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 
     case TYPENAME_TYPE:
       {
-	tree ctx = tsubst_aggr_type (TYPE_CONTEXT (t), args, complain,
-				     in_decl, /*entering_scope=*/1);
-	tree f = tsubst_copy (TYPENAME_TYPE_FULLNAME (t), args,
-			      complain, in_decl);
-
+	tree ctx, f;
+	tree tinfo = get_template_info (t);
+
+	if (tinfo != NULL_TREE)
+	  /* prepare possible partial instantiation of member
+	     template by fixing-up template parms which level are
+	     going to be reduced by the partial instantiation.  */
+	  tsubst_template_parms (DECL_TEMPLATE_PARMS (TI_TEMPLATE (tinfo)),
+				 args, tf_none);
+
+	ctx = tsubst_aggr_type (TYPE_CONTEXT (t), args, complain,
+				in_decl, /*entering_scope=*/1);
+	f = tsubst_copy (TYPENAME_TYPE_FULLNAME (t), args,
+			 complain, in_decl);
+	
 	if (ctx == error_mark_node || f == error_mark_node)
 	  return error_mark_node;
 
@@ -11711,16 +12272,19 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 
     case UNBOUND_CLASS_TEMPLATE:
       {
+	/* If T is to be eventually replaced with a member template
+	   being partially instantiated, fixup its template parmeters
+	   that are to be level-reduced, upfront.  */
+	tree parm_list =
+	  tsubst_template_parms (DECL_TEMPLATE_PARMS (TYPE_NAME (t)),
+				 args, complain);
 	tree ctx = tsubst_aggr_type (TYPE_CONTEXT (t), args, complain,
 				     in_decl, /*entering_scope=*/1);
 	tree name = TYPE_IDENTIFIER (t);
-	tree parm_list = DECL_TEMPLATE_PARMS (TYPE_NAME (t));
 
 	if (ctx == error_mark_node || name == error_mark_node)
 	  return error_mark_node;
 
-	if (parm_list)
-	  parm_list = tsubst_template_parms (parm_list, args, complain);
 	return make_unbound_class_template (ctx, name, parm_list, complain);
       }
 
@@ -15878,22 +16442,43 @@ check_cv_quals_for_unify (int strict, tree arg, tree parm)
   return 1;
 }
 
-/* Determines the LEVEL and INDEX for the template parameter PARM.  */
+/* Determines the LEVEL and INDEX for the template parameter PARM.
+   PARM can be either a DECL for a template parameter, or a the type
+   of a template type parameter, or a TEMPLATE_PARM_INDEX node.
+
+   If the caller wants to get only the LEVEL or only the INDEX, it can
+   set the other argument to NULL.  */
+
 void 
 template_parm_level_and_index (tree parm, int* level, int* index)
 {
+  int l = -1, i = -1;
+
+  if (TREE_CODE (parm) == TYPE_DECL
+      || TREE_CODE (parm) == TEMPLATE_DECL)
+    parm = TREE_TYPE (parm);
+  else if (TREE_CODE (parm) == PARM_DECL)
+    parm = DECL_INITIAL (parm);
+
   if (TREE_CODE (parm) == TEMPLATE_TYPE_PARM
       || TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM
       || TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
     {
-      *index = TEMPLATE_TYPE_IDX (parm);
-      *level = TEMPLATE_TYPE_LEVEL (parm);
+      i = TEMPLATE_TYPE_IDX (parm);
+      l = TEMPLATE_TYPE_LEVEL (parm);
     }
   else
     {
-      *index = TEMPLATE_PARM_IDX (parm);
-      *level = TEMPLATE_PARM_LEVEL (parm);
+      i = TEMPLATE_PARM_IDX (parm);
+      l = TEMPLATE_PARM_LEVEL (parm);
     }
+
+  gcc_assert (l > 0 && i >= 0);
+
+  if (level != NULL)
+    *level = l;
+  if (index != NULL)
+    *index = i;
 }
 
 #define RECUR_AND_CHECK_FAILURE(TP, TA, P, A, S, EP)			\
@@ -16077,8 +16662,9 @@ unify_pack_expansion (tree tparms, tree targs, tree packed_parms,
 	  tree bad_old_arg = NULL_TREE, bad_new_arg = NULL_TREE;
 	  tree old_args = ARGUMENT_PACK_ARGS (old_pack);
 
-	  if (!comp_template_args_with_info (old_args, new_args,
-					     &bad_old_arg, &bad_new_arg))
+	  if (!comp_template_args_guided (old_args, new_args,
+					  &bad_old_arg, &bad_new_arg,
+					  COMPARE_STRICT))
 	    /* Inconsistent unification of this parameter pack.  */
 	    return unify_parameter_pack_inconsistent (explain_p,
 						      bad_old_arg,
@@ -19066,15 +19652,13 @@ get_mostly_instantiated_function_type (tree decl)
       int i;
       tree partial_args;
 
-      /* Replace the innermost level of the TARGS with NULL_TREEs to
-	 let tsubst know not to substitute for those parameters.  */
-      partial_args = make_tree_vec (TREE_VEC_LENGTH (targs));
+      /* Copy all but the innermost level of the TARGS to let tsubst
+	 below know not to substitute for those parameters and
+	 properly perform the partial substituting of fn_type.  */
+      partial_args = make_tree_vec (TREE_VEC_LENGTH (targs) - 1);
       for (i = 1; i < TMPL_ARGS_DEPTH (targs); ++i)
 	SET_TMPL_ARGS_LEVEL (partial_args, i,
 			     TMPL_ARGS_LEVEL (targs, i));
-      SET_TMPL_ARGS_LEVEL (partial_args,
-			   TMPL_ARGS_DEPTH (targs),
-			   make_tree_vec (DECL_NTPARMS (tmpl)));
 
       /* Make sure that we can see identifiers, and compute access
 	 correctly.  */
@@ -19090,7 +19674,6 @@ get_mostly_instantiated_function_type (tree decl)
 	 innermost set of parameters.  This step is important if the
 	 innermost set of template parameters contains value
 	 parameters whose types depend on outer template parameters.  */
-      TREE_VEC_LENGTH (partial_args)--;
       tparms = tsubst_template_parms (tparms, partial_args, tf_error);
 
       pop_access_scope (decl);
@@ -20214,7 +20797,7 @@ make_auto (void)
 			       TYPE_DECL, get_identifier ("auto"), au);
   TYPE_STUB_DECL (au) = TYPE_NAME (au);
   TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index
-    (0, processing_template_decl + 1, processing_template_decl + 1,
+    (0, processing_template_decl + 1, NULL_TREE,
      0, TYPE_NAME (au), NULL_TREE);
   TYPE_CANONICAL (au) = canonical_type_parameter (au);
   DECL_ARTIFICIAL (TYPE_NAME (au)) = 1;
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index b80b52a..04bdedd 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2178,7 +2178,7 @@ decl_anon_ns_mem_p (const_tree decl)
    CALL_EXPRS.  Return whether they are equivalent.  */
 
 static bool
-called_fns_equal (tree t1, tree t2)
+called_fns_equal (tree t1, tree t2, int strict)
 {
   /* Core 1321: dependent names are equivalent even if the overload sets
      are different.  But do compare explicit template arguments.  */
@@ -2195,17 +2195,21 @@ called_fns_equal (tree t1, tree t2)
 	targs1 = TREE_OPERAND (t1, 1);
       if (TREE_CODE (t2) == TEMPLATE_ID_EXPR)
 	targs2 = TREE_OPERAND (t2, 1);
-      return cp_tree_equal (targs1, targs2);
+      return compare_trees (targs1, targs2, strict);
     }
   else
     return cp_tree_equal (t1, t2);
 }
 
 /* Return truthvalue of whether T1 is the same tree structure as T2.
-   Return 1 if they are the same. Return 0 if they are different.  */
+   STRICT controls how the comparison is done, with the same semantics
+   as the for the last parameter of comptypes.  Please make sure that
+   any type or tree comparison function used in this function is a
+   variant that takes this STRICT parameter.  Return 1 if they are the
+   same. Return 0 if they are different.  */
 
 bool
-cp_tree_equal (tree t1, tree t2)
+compare_trees (tree t1, tree t2, int strict)
 {
   enum tree_code code1, code2;
 
@@ -2251,14 +2255,14 @@ cp_tree_equal (tree t1, tree t2)
 				     TREE_FIXED_CST (t2));
 
     case COMPLEX_CST:
-      return cp_tree_equal (TREE_REALPART (t1), TREE_REALPART (t2))
-	&& cp_tree_equal (TREE_IMAGPART (t1), TREE_IMAGPART (t2));
+      return compare_trees (TREE_REALPART (t1), TREE_REALPART (t2), strict)
+	&& compare_trees (TREE_IMAGPART (t1), TREE_IMAGPART (t2), strict);
 
     case CONSTRUCTOR:
       /* We need to do this when determining whether or not two
 	 non-type pointer to member function template arguments
 	 are the same.  */
-      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))
+      if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict)
 	  || CONSTRUCTOR_NELTS (t1) != CONSTRUCTOR_NELTS (t2))
 	return false;
       {
@@ -2267,35 +2271,35 @@ cp_tree_equal (tree t1, tree t2)
 	FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t1), i, field, value)
 	  {
 	    constructor_elt *elt2 = CONSTRUCTOR_ELT (t2, i);
-	    if (!cp_tree_equal (field, elt2->index)
-		|| !cp_tree_equal (value, elt2->value))
+	    if (!compare_trees (field, elt2->index, strict)
+		|| !compare_trees (value, elt2->value, strict))
 	      return false;
 	  }
       }
       return true;
 
     case TREE_LIST:
-      if (!cp_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2)))
+      if (!compare_trees (TREE_PURPOSE (t1), TREE_PURPOSE (t2), strict))
 	return false;
-      if (!cp_tree_equal (TREE_VALUE (t1), TREE_VALUE (t2)))
+      if (!compare_trees (TREE_VALUE (t1), TREE_VALUE (t2), strict))
 	return false;
-      return cp_tree_equal (TREE_CHAIN (t1), TREE_CHAIN (t2));
+      return compare_trees (TREE_CHAIN (t1), TREE_CHAIN (t2), strict);
 
     case SAVE_EXPR:
-      return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+      return compare_trees (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0), strict);
 
     case CALL_EXPR:
       {
 	tree arg1, arg2;
 	call_expr_arg_iterator iter1, iter2;
-	if (!called_fns_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2)))
+	if (!called_fns_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2), strict))
 	  return false;
 	for (arg1 = first_call_expr_arg (t1, &iter1),
 	       arg2 = first_call_expr_arg (t2, &iter2);
 	     arg1 && arg2;
 	     arg1 = next_call_expr_arg (&iter1),
 	       arg2 = next_call_expr_arg (&iter2))
-	  if (!cp_tree_equal (arg1, arg2))
+	  if (!compare_trees (arg1, arg2, strict))
 	    return false;
 	if (arg1 || arg2)
 	  return false;
@@ -2317,28 +2321,30 @@ cp_tree_equal (tree t1, tree t2)
 	else if (TREE_CODE (o2) == VAR_DECL && DECL_NAME (o2) == NULL_TREE
 		 && !DECL_RTL_SET_P (o2))
 	  /*Nop*/;
-	else if (!cp_tree_equal (o1, o2))
+	else if (!compare_trees (o1, o2, strict))
 	  return false;
 
-	return cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
+	return compare_trees (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1),
+			      strict);
       }
 
     case WITH_CLEANUP_EXPR:
-      if (!cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)))
+      if (!compare_trees (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0), strict))
 	return false;
-      return cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t1, 1));
+      return compare_trees (TREE_OPERAND (t1, 1), TREE_OPERAND (t1, 1), strict);
 
     case COMPONENT_REF:
       if (TREE_OPERAND (t1, 1) != TREE_OPERAND (t2, 1))
 	return false;
-      return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+      return compare_trees (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0),
+			    strict);
 
     case PARM_DECL:
       /* For comparing uses of parameters in late-specified return types
 	 with an out-of-class definition of the function, but can also come
 	 up for expressions that involve 'this' in a member function
 	 template.  */
-      if (same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+      if (comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	{
 	  if (DECL_ARTIFICIAL (t1) ^ DECL_ARTIFICIAL (t2))
 	    return false;
@@ -2361,19 +2367,18 @@ cp_tree_equal (tree t1, tree t2)
       return (BASELINK_BINFO (t1) == BASELINK_BINFO (t2)
 	      && BASELINK_ACCESS_BINFO (t1) == BASELINK_ACCESS_BINFO (t2)
 	      && BASELINK_QUALIFIED_P (t1) == BASELINK_QUALIFIED_P (t2)
-	      && cp_tree_equal (BASELINK_FUNCTIONS (t1),
-				BASELINK_FUNCTIONS (t2)));
+	      && compare_trees (BASELINK_FUNCTIONS (t1),
+				BASELINK_FUNCTIONS (t2), strict));
 
     case TEMPLATE_PARM_INDEX:
-      if (TEMPLATE_PARM_NUM_SIBLINGS (t1)
-	  != TEMPLATE_PARM_NUM_SIBLINGS (t2))
+      if (!(TEMPLATE_PARM_IDX (t1) == TEMPLATE_PARM_IDX (t2)
+	    && TEMPLATE_PARM_LEVEL (t1) == TEMPLATE_PARM_LEVEL (t2)
+	    && (TEMPLATE_PARM_PARAMETER_PACK (t1)
+		== TEMPLATE_PARM_PARAMETER_PACK (t2))
+	    && comptypes (TREE_TYPE (TEMPLATE_PARM_DECL (t1)),
+			  TREE_TYPE (TEMPLATE_PARM_DECL (t2)), strict)))
 	return false;
-      return (TEMPLATE_PARM_IDX (t1) == TEMPLATE_PARM_IDX (t2)
-	      && TEMPLATE_PARM_LEVEL (t1) == TEMPLATE_PARM_LEVEL (t2)
-	      && (TEMPLATE_PARM_PARAMETER_PACK (t1)
-		  == TEMPLATE_PARM_PARAMETER_PACK (t2))
-	      && same_type_p (TREE_TYPE (TEMPLATE_PARM_DECL (t1)),
-			      TREE_TYPE (TEMPLATE_PARM_DECL (t2))));
+      return comp_template_parms_siblings (t1, t2, strict);
 
     case TEMPLATE_ID_EXPR:
       return (cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0))
@@ -2385,8 +2390,9 @@ cp_tree_equal (tree t1, tree t2)
 	if (TREE_VEC_LENGTH (t1) != TREE_VEC_LENGTH (t2))
 	  return false;
 	for (ix = TREE_VEC_LENGTH (t1); ix--;)
-	  if (!cp_tree_equal (TREE_VEC_ELT (t1, ix),
-			      TREE_VEC_ELT (t2, ix)))
+	  if (!compare_trees (TREE_VEC_ELT (t1, ix),
+			      TREE_VEC_ELT (t2, ix),
+			      strict))
 	    return false;
 	return true;
       }
@@ -2400,16 +2406,17 @@ cp_tree_equal (tree t1, tree t2)
 	if (TREE_CODE (o1) != TREE_CODE (o2))
 	  return false;
 	if (TYPE_P (o1))
-	  return same_type_p (o1, o2);
+	  return comptypes (o1, o2, strict);
 	else
-	  return cp_tree_equal (o1, o2);
+	  return compare_trees (o1, o2, strict);
       }
 
     case MODOP_EXPR:
       {
 	tree t1_op1, t2_op1;
 
-	if (!cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)))
+	if (!compare_trees (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0),
+			    strict))
 	  return false;
 
 	t1_op1 = TREE_OPERAND (t1, 1);
@@ -2417,7 +2424,7 @@ cp_tree_equal (tree t1, tree t2)
 	if (TREE_CODE (t1_op1) != TREE_CODE (t2_op1))
 	  return false;
 
-	return cp_tree_equal (TREE_OPERAND (t1, 2), TREE_OPERAND (t2, 2));
+	return compare_trees (TREE_OPERAND (t1, 2), TREE_OPERAND (t2, 2), strict);
       }
 
     case PTRMEM_CST:
@@ -2426,18 +2433,18 @@ cp_tree_equal (tree t1, tree t2)
       if (PTRMEM_CST_MEMBER (t1) != PTRMEM_CST_MEMBER (t2))
 	return false;
 
-      return same_type_p (PTRMEM_CST_CLASS (t1), PTRMEM_CST_CLASS (t2));
+      return comptypes (PTRMEM_CST_CLASS (t1), PTRMEM_CST_CLASS (t2), strict);
 
     case OVERLOAD:
       if (OVL_FUNCTION (t1) != OVL_FUNCTION (t2))
 	return false;
-      return cp_tree_equal (OVL_CHAIN (t1), OVL_CHAIN (t2));
+      return compare_trees (OVL_CHAIN (t1), OVL_CHAIN (t2), strict);
 
     case TRAIT_EXPR:
       if (TRAIT_EXPR_KIND (t1) != TRAIT_EXPR_KIND (t2))
 	return false;
-      return same_type_p (TRAIT_EXPR_TYPE1 (t1), TRAIT_EXPR_TYPE1 (t2))
-	&& same_type_p (TRAIT_EXPR_TYPE2 (t1), TRAIT_EXPR_TYPE2 (t2));
+      return comptypes (TRAIT_EXPR_TYPE1 (t1), TRAIT_EXPR_TYPE1 (t2), strict)
+	&& comptypes (TRAIT_EXPR_TYPE2 (t1), TRAIT_EXPR_TYPE2 (t2), strict);
 
     case CAST_EXPR:
     case STATIC_CAST_EXPR:
@@ -2446,16 +2453,18 @@ cp_tree_equal (tree t1, tree t2)
     case DYNAMIC_CAST_EXPR:
     case IMPLICIT_CONV_EXPR:
     case NEW_EXPR:
-      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+      if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	return false;
       /* Now compare operands as usual.  */
       break;
 
     case DEFERRED_NOEXCEPT:
-      return (cp_tree_equal (DEFERRED_NOEXCEPT_PATTERN (t1),
-			     DEFERRED_NOEXCEPT_PATTERN (t2))
-	      && comp_template_args (DEFERRED_NOEXCEPT_ARGS (t1),
-				     DEFERRED_NOEXCEPT_ARGS (t2)));
+      return (compare_trees (DEFERRED_NOEXCEPT_PATTERN (t1),
+			     DEFERRED_NOEXCEPT_PATTERN (t2),
+			     strict)
+	      && comp_template_args_guided (DEFERRED_NOEXCEPT_ARGS (t1),
+					    DEFERRED_NOEXCEPT_ARGS (t2),
+					    NULL, NULL, strict));
       break;
 
     default:
@@ -2480,14 +2489,15 @@ cp_tree_equal (tree t1, tree t2)
 	  return false;
 
 	for (i = 0; i < n; ++i)
-	  if (!cp_tree_equal (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i)))
+	  if (!compare_trees (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i),
+			      strict))
 	    return false;
 
 	return true;
       }
 
     case tcc_type:
-      return same_type_p (t1, t2);
+      return comptypes (t1, t2, strict);
     default:
       gcc_unreachable ();
     }
@@ -2495,6 +2505,15 @@ cp_tree_equal (tree t1, tree t2)
   return false;
 }
 
+/* Return truthvalue of whether T1 is the same tree structure as T2.
+   Return 1 if they are the same. Return 0 if they are different.  */
+
+bool
+cp_tree_equal (tree t1, tree t2)
+{
+  return compare_trees (t1, t2, COMPARE_STRICT);
+}
+
 /* The type of ARG when used as an lvalue.  */
 
 tree
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 643454c..9ca8e5e 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -53,6 +53,7 @@ static tree rationalize_conditional_expr (enum tree_code, tree,
 static int comp_ptr_ttypes_real (tree, tree, int);
 static bool comp_except_types (tree, tree, bool);
 static bool comp_array_types (const_tree, const_tree, bool);
+static bool compparms_guided (const_tree, const_tree, int);
 static tree pointer_diff (tree, tree, tree);
 static tree get_delta_difference (tree, tree, bool, bool, tsubst_flags_t);
 static void casts_away_constness_r (tree *, tree *);
@@ -1119,13 +1120,56 @@ comp_array_types (const_tree t1, const_tree t2, bool allow_redeclaration)
   return true;
 }
 
+/* Return true iff the two instances of TEMPLATE_PARM_INDEX are
+   equivalent.  STRICT controls how the comparison is done, with the
+   same semantics as the last parameter of comptypes.  */
+
+bool
+comp_template_parms_siblings (tree index1,
+			      tree index2,
+			      int strict)
+{
+  tree siblings1, siblings2;
+
+  gcc_assert (index1 != NULL_TREE 
+	      && index2 != NULL_TREE
+	      && TREE_CODE (index1) == TREE_CODE (index2)
+	      && TREE_CODE (index1) == TEMPLATE_PARM_INDEX);
+
+  if (strict & COMPARE_NO_SIBLINGS)
+    return true;
+
+  siblings1 = TEMPLATE_PARM_SIBLINGS (index1);
+  siblings2 = TEMPLATE_PARM_SIBLINGS (index2);
+    
+  if (siblings1 == siblings2)
+    return true;
+
+  /* If T1 and T2 belong to different template parm lists let's assume
+     they are different.  */
+
+  if ((siblings1 != NULL_TREE) != (siblings2 != NULL_TREE))
+    return false;
+
+  if (TREE_VEC_LENGTH (siblings1) != TREE_VEC_LENGTH (siblings2))
+    return false;
+
+  if (!comp_template_parm_levels (siblings1, siblings2,
+				  strict | COMPARE_NO_SIBLINGS))
+    return false;
+
+  return true;
+}
+
 /* Compare the relative position of T1 and T2 into their respective
    template parameter list.
-   T1 and T2 must be template parameter types.
+   T1 and T2 must be template parameter types.  STRICT controls how
+   the comparison is done, with the same semantics as the for the last
+   parameter of comptypes.
    Return TRUE if T1 and T2 have the same position, FALSE otherwise.  */
 
 static bool
-comp_template_parms_position (tree t1, tree t2)
+comp_template_parms_position (tree t1, tree t2, int strict)
 {
   tree index1, index2;
   gcc_assert (t1 && t2
@@ -1137,19 +1181,16 @@ comp_template_parms_position (tree t1, tree t2)
   index1 = TEMPLATE_TYPE_PARM_INDEX (TYPE_MAIN_VARIANT (t1));
   index2 = TEMPLATE_TYPE_PARM_INDEX (TYPE_MAIN_VARIANT (t2));
 
-  /* If T1 and T2 belong to template parm lists of different size,
-     let's assume they are different.  */
-  if (TEMPLATE_PARM_NUM_SIBLINGS (index1)
-      != TEMPLATE_PARM_NUM_SIBLINGS (index2))
-    return false;
-
-  /* Then compare their relative position.  */
+  /* Compare their relative position.  */
   if (TEMPLATE_PARM_IDX (index1) != TEMPLATE_PARM_IDX (index2)
       || TEMPLATE_PARM_LEVEL (index1) != TEMPLATE_PARM_LEVEL (index2)
       || (TEMPLATE_PARM_PARAMETER_PACK (index1)
 	  != TEMPLATE_PARM_PARAMETER_PACK (index2)))
     return false;
 
+  if (!comp_template_parms_siblings (index1, index2, strict))
+    return false;
+
   return true;
 }
 
@@ -1233,11 +1274,12 @@ structural_comptypes (tree t1, tree t2, int strict)
 
     case TEMPLATE_TEMPLATE_PARM:
     case BOUND_TEMPLATE_TEMPLATE_PARM:
-      if (!comp_template_parms_position (t1, t2))
+      if (!comp_template_parms_position (t1, t2, strict))
 	return false;
-      if (!comp_template_parms
+      if (!comp_template_parms_guided
 	  (DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t1)),
-	   DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t2))))
+	   DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t2)),
+	   strict))
 	return false;
       if (TREE_CODE (t1) == TEMPLATE_TEMPLATE_PARM)
 	break;
@@ -1250,7 +1292,9 @@ structural_comptypes (tree t1, tree t2, int strict)
       if (TYPE_TEMPLATE_INFO (t1) && TYPE_TEMPLATE_INFO (t2)
 	  && (TYPE_TI_TEMPLATE (t1) == TYPE_TI_TEMPLATE (t2)
 	      || TREE_CODE (t1) == BOUND_TEMPLATE_TEMPLATE_PARM)
-	  && comp_template_args (TYPE_TI_ARGS (t1), TYPE_TI_ARGS (t2)))
+	  && comp_template_args_guided (TYPE_TI_ARGS (t1),
+					TYPE_TI_ARGS (t2),
+					NULL, NULL, strict))
 	break;
 
       if ((strict & COMPARE_BASE) && DERIVED_FROM_P (t1, t2))
@@ -1264,7 +1308,7 @@ structural_comptypes (tree t1, tree t2, int strict)
       if (!comptypes (TYPE_OFFSET_BASETYPE (t1), TYPE_OFFSET_BASETYPE (t2),
 		      strict & ~COMPARE_REDECLARATION))
 	return false;
-      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+      if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	return false;
       break;
 
@@ -1276,15 +1320,17 @@ structural_comptypes (tree t1, tree t2, int strict)
     case POINTER_TYPE:
       if (TYPE_MODE (t1) != TYPE_MODE (t2)
 	  || TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2)
-	  || !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+	  || !comptypes (TREE_TYPE (t1), TREE_TYPE (t2),
+			 strict & ~COMPARE_REDECLARATION))
 	return false;
       break;
 
     case METHOD_TYPE:
     case FUNCTION_TYPE:
-      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+      if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	return false;
-      if (!compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2)))
+      if (!compparms_guided (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2),
+			   strict))
 	return false;
       break;
 
@@ -1297,43 +1343,48 @@ structural_comptypes (tree t1, tree t2, int strict)
     case TEMPLATE_TYPE_PARM:
       /* If T1 and T2 don't have the same relative position in their
 	 template parameters set, they can't be equal.  */
-      if (!comp_template_parms_position (t1, t2))
+      if (!comp_template_parms_position (t1, t2, strict))
 	return false;
       break;
 
     case TYPENAME_TYPE:
-      if (!cp_tree_equal (TYPENAME_TYPE_FULLNAME (t1),
-			  TYPENAME_TYPE_FULLNAME (t2)))
+      if (!compare_trees (TYPENAME_TYPE_FULLNAME (t1),
+			  TYPENAME_TYPE_FULLNAME (t2),
+			  strict))
 	return false;
       /* Qualifiers don't matter on scopes.  */
-      if (!same_type_ignoring_top_level_qualifiers_p (TYPE_CONTEXT (t1),
-						      TYPE_CONTEXT (t2)))
+      if (!same_type_ignoring_top_level_qualifiers_guided_p (TYPE_CONTEXT (t1),
+							     TYPE_CONTEXT (t2),
+							     strict))
 	return false;
       break;
 
     case UNBOUND_CLASS_TEMPLATE:
-      if (!cp_tree_equal (TYPE_IDENTIFIER (t1), TYPE_IDENTIFIER (t2)))
+      if (!compare_trees (TYPE_IDENTIFIER (t1), TYPE_IDENTIFIER (t2),
+			  strict))
 	return false;
-      if (!same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2)))
+      if (!comptypes (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2), strict))
 	return false;
       break;
 
     case COMPLEX_TYPE:
-      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+      if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	return false;
       break;
 
     case VECTOR_TYPE:
       if (TYPE_VECTOR_SUBPARTS (t1) != TYPE_VECTOR_SUBPARTS (t2)
-	  || !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+	  || !comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	return false;
       break;
 
     case TYPE_PACK_EXPANSION:
-      return (same_type_p (PACK_EXPANSION_PATTERN (t1),
-			   PACK_EXPANSION_PATTERN (t2))
-	      && comp_template_args (PACK_EXPANSION_EXTRA_ARGS (t1),
-				     PACK_EXPANSION_EXTRA_ARGS (t2)));
+	return (comptypes (PACK_EXPANSION_PATTERN (t1), 
+			   PACK_EXPANSION_PATTERN (t2),
+			   strict)
+		&& comp_template_args_guided (PACK_EXPANSION_EXTRA_ARGS (t1),
+					      PACK_EXPANSION_EXTRA_ARGS (t2),
+					      NULL, NULL, strict));
 
     case DECLTYPE_TYPE:
       if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t1)
@@ -1342,14 +1393,16 @@ structural_comptypes (tree t1, tree t2, int strict)
 	      != DECLTYPE_FOR_LAMBDA_CAPTURE (t2))
 	  || (DECLTYPE_FOR_LAMBDA_PROXY (t1)
 	      != DECLTYPE_FOR_LAMBDA_PROXY (t2))
-          || !cp_tree_equal (DECLTYPE_TYPE_EXPR (t1), 
-                             DECLTYPE_TYPE_EXPR (t2)))
+          || !compare_trees (DECLTYPE_TYPE_EXPR (t1), 
+                             DECLTYPE_TYPE_EXPR (t2),
+			     strict))
         return false;
       break;
 
     case UNDERLYING_TYPE:
-      return same_type_p (UNDERLYING_TYPE_TYPE (t1), 
-			  UNDERLYING_TYPE_TYPE (t2));
+      return comptypes (UNDERLYING_TYPE_TYPE (t1), 
+			UNDERLYING_TYPE_TYPE (t2),
+			strict);
 
     default:
       return false;
@@ -1416,15 +1469,31 @@ comptypes (tree t1, tree t2, int strict)
 }
 
 /* Returns nonzero iff TYPE1 and TYPE2 are the same type, ignoring
-   top-level qualifiers.  */
+   top-level qualifiers.  STRICT controls how the type comparison is
+   done, with the same semantics as for the last parameter of
+   comptypes.  */
 
 bool
-same_type_ignoring_top_level_qualifiers_p (tree type1, tree type2)
+same_type_ignoring_top_level_qualifiers_guided_p (tree type1,
+						  tree type2,
+						  int strict)
 {
   if (type1 == error_mark_node || type2 == error_mark_node)
     return false;
 
-  return same_type_p (TYPE_MAIN_VARIANT (type1), TYPE_MAIN_VARIANT (type2));
+  return comptypes (TYPE_MAIN_VARIANT (type1),
+		    TYPE_MAIN_VARIANT (type2),
+		    strict);
+}
+
+/* Returns nonzero iff TYPE1 and TYPE2 are the same type, ignoring
+   top-level qualifiers.  */
+
+bool
+same_type_ignoring_top_level_qualifiers_p (tree type1, tree type2)
+{
+  return same_type_ignoring_top_level_qualifiers_guided_p (type1, type2,
+							   COMPARE_STRICT);
 }
 
 /* Returns 1 if TYPE1 is at least as qualified as TYPE2.  */
@@ -1479,10 +1548,10 @@ comp_cv_qual_signature (tree type1, tree type2)
 /* Return true if two parameter type lists PARMS1 and PARMS2 are
    equivalent in the sense that functions with those parameter types
    can have equivalent types.  The two lists must be equivalent,
-   element by element.  */
+   element by element.  STRICT controls how the comparison is done.  */
 
-bool
-compparms (const_tree parms1, const_tree parms2)
+static bool
+compparms_guided (const_tree parms1, const_tree parms2, int strict)
 {
   const_tree t1, t2;
 
@@ -1497,12 +1566,23 @@ compparms (const_tree parms1, const_tree parms2)
 	 they fail to match.  */
       if (!t1 || !t2)
 	return false;
-      if (!same_type_p (TREE_VALUE (t1), TREE_VALUE (t2)))
+      if (!comptypes (TREE_VALUE (t1), TREE_VALUE (t2), strict))
 	return false;
     }
   return true;
 }
 
+/* Return true if two parameter type lists PARMS1 and PARMS2 are
+   equivalent in the sense that functions with those parameter types
+   can have equivalent types.  The two lists must be equivalent,
+   element by element.  */
+
+bool
+compparms (const_tree parms1, const_tree parms2)
+{
+  return compparms_guided (parms1, parms2, COMPARE_STRICT);
+}
+
 \f
 /* Process a sizeof or alignof expression where the operand is a
    type.  */
diff --git a/gcc/testsuite/g++.dg/template/crash84.C b/gcc/testsuite/g++.dg/template/crash84.C
index c42f85c..69ee87c 100644
--- a/gcc/testsuite/g++.dg/template/crash84.C
+++ b/gcc/testsuite/g++.dg/template/crash84.C
@@ -4,8 +4,8 @@
 
 template<typename T> struct a
 {
-    template <template <typename> class C, typename X, C<X>* =0>
-    struct b // { dg-error "class C' is not a template|is not a valid type" }
+    template <template <typename> class C, typename X, C<X>* = 0>
+    struct b
     {
     };
 };
@@ -13,7 +13,5 @@ template<typename T> struct a
 void
 foo ()
 {
-    a<int> v; // { dg-message "required from here" }
+    a<int> v;
 }
-
-
diff --git a/gcc/testsuite/g++.dg/template/typedef39.C b/gcc/testsuite/g++.dg/template/typedef39.C
new file mode 100644
index 0000000..4ee23a6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef39.C
@@ -0,0 +1,16 @@
+// Origin PR c++/50852
+// { dg-do compile }
+
+template<int d> class A;
+template<class T> struct B {typedef int K;typedef int L;};
+template<class U,class V> struct C
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W;
+};
+template<class U,int d> struct D
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W; // { dg-error "not a member" }
+};
+template class D<B<A<1> >,3>;
diff --git a/gcc/testsuite/g++.dg/template/typedef40.C b/gcc/testsuite/g++.dg/template/typedef40.C
new file mode 100644
index 0000000..6cd9766
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef40.C
@@ -0,0 +1,22 @@
+// Origin PR c++/50852
+// { dg-do compile }
+
+template<int d> class A;
+
+template<class T> struct B {typedef int K;typedef int L;};
+template<class U, void(*)(U&), class V> struct C
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W;
+};
+template<class U, void(*)(U&), int d> struct D
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W; // { dg-error "not a member" }
+};
+
+struct S;
+
+void f(B<A<1> >&);
+
+template class D<B<A<1> >, &f, 3>;
diff --git a/gcc/testsuite/g++.dg/template/typedef41.C b/gcc/testsuite/g++.dg/template/typedef41.C
new file mode 100644
index 0000000..17d2feb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef41.C
@@ -0,0 +1,19 @@
+// Origin PR c++/50852
+// { dg-do compile }
+
+template<int d> class A;
+
+template<class T> struct B {typedef int K;typedef int L;};
+template<class U, typename U::K, class V> struct C
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W;
+};
+template<class U, typename U::K, int d> struct D
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W; // { dg-error "not a member" }
+};
+
+
+template class D<B<A<1> >, 0, 3>;

-- 
		Dodji

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] PR c++/50852 - Revisit dependant template parameter
  2012-03-25 18:12           ` Dodji Seketeli
@ 2012-03-27 17:30             ` Dodji Seketeli
  0 siblings, 0 replies; 18+ messages in thread
From: Dodji Seketeli @ 2012-03-27 17:30 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches

Jason Merrill <jason@redhat.com> writes:

> 
> >    FIXME: This function does an approximation, as it only checks that
> >    the levels of PARM_PACK/EXPANSION and ARG_PACK do match.  For it to
> >    be precise, I think the TEMPLATE_PARM_INDEX of PARM_PACK should
> >    track its pre-fixup type, so that ARG_PACK could be compared with
> >    that type instead.  But that would increase the size of the
> >    template_parm_index_s struct, as I don't see where else I could
> >    store the pre-fixup type.  */
> 
> Doesn't ...ORIG_INDEX work for this?

So I have looked into this a bit more.

TEMPLATE_PARM_ORIG_INDEX now points to the pre-fixed up version of the
original index.  I have added a new TEMPLATE_PARM_FIXED_UP_ORIG_INDEX to
access the fixed-up version of the original index.  That's what we use
to poke the parent which descendant is updated upon level-reduction +
fixup.

>  Indeed, I'd think you could change arg_from_parm_pack_p to compare
> ORIG_INDEX and then it would handle both cases.

Actually, comparing ORIG_INDEXes won't work when we are dealing and the
arg and the parm are equal; that is, when they are not pre-fixup and
post-fixup of the same type, but when they are really equal.  For that
case (as well as for the pref-fixup/post-fixup case), comparing their
TYPE_NAME works.

So I have augmented arg_from_parm_pack_p to compare the ORIG_INDEX of
the arg and the parm when level-reduction is at play, and use TYPE_NAME
comparison otherwise.

Bootstrapped and tested on x86_64-unknown-linux-gnu against trunk.

gcc/cp/

	PR c++/50852
	* cp-tree.h (struct template_parm_index_s)<num_siblings,orig_level>: Remove.
	(struct template_parm_index_s)<siblings, orig_index>: New members.
	(COMPARE_NO_SIBLINGS): New type comparison control flag.
	(TEMPLATE_PARM_SIBLINGS): New accessor macro.
	(TEMPLATE_PARM_DESCENDANTS): Add comments.
	(TEMPLATE_PARM_ORIG_INDEX, TEMPLATE_PARM_FIXED_UP_ORIG_INDEX): New
	accessors.
	(TEMPLATE_PARM_ORIG_LEVEL): Rewrite in terms of
	TEMPLATE_PARM_ORIG_INDEX.
	(process_template_parm): Change the integer num_siblings parm into
	a tree siblings parm.
	(comp_template_parms_siblings, comp_template_parm_levels)
	(comp_template_parms_guided, comp_template_args_guided)
	(same_type_ignoring_top_level_qualifiers_guided_p, compare_trees)
	(template_type_parameter_type_p): Declare new functions.
	(fixup_current_template_parms): New, better name for
	fixup_template_parms.
	(fixup_template_parms): Take the set of parameters to fixup in
	parameters.
	(get_template_parm_index): Declare new function.
	* pt.c (get_root_index_same_level, add_descendant_to_parm_index)
	(get_descendant_of_parm_index, get_template_parm_index)
	(comp_template_parm_levels, template_parms_to_args)
	(template_type_parameter_type_p): Define new functions.
	(current_template_args): Use the new template_parms_to_args
	function.
	(build_template_parm_index, fixup_template_parm_index)
	(process_template_parm, fixup_template_type_parm_type)
	(fixup_template_parm, process_template_parm): Change the integer
	num_siblings parm into a tree siblings parm.  Update comments.
	(fixup_template_type_parm_type, fixup_template_parm_index):
	Likewise.  Propagate the original index to the fixed-up index.
	For level-reduced indexes, update the descendants of the parent.
	(build_template_parm_index): Likewise.  Replace ORIG_LEVEL integer
	parm with an ORIG_INDEX tree.  Add a few asserts.
	(get_template_info): Make this more robust and support getting
	template info from TYPENAME_TYPE nodes.
	(template_parm_level_and_index):  Make this work on template parm
	decls.  Make it  Optionally return the level and the index.
	(arg_from_parm_pack_p): Take a pack expansion parameter.  Make
	this work on level-reduced pack expansions and parameter packs.
	(comp_template_parms_guided): New function.  Takes an additional
	parm to control comparison.  Factorized out of ...
	(comp_template_parms): ... this.
	(reduce_template_parm_level): Use TEMPLATE_PARM_SIBLINGS instead
	of TEMPLATE_PARM_NUM_SIBLINGS.  Update usage of
	TEMPLATE_PARM_DESCENDANTS.  Use the new
	get_descendant_of_parm_index.
	(template_args_equal_guided): Take an additional parm to control
	comparison.  Use template_args_equal_guided instead of
	template_args_equal.  Factorize this out of ...
	(template_args_equal): ... this.
	(comp_template_args_guided): Take an additional parm to control
	comparison.  Renamed from comp_template_args_with_info.  Make this
	public.
	(comp_template_args, unify_pack_expansion): Adjust.
	(fixup_innermost_template_parms): Transformed former
	fixup_template_parms in to this.  Make it take a set of parms to
	fixup and an arglist.  Update comments.
	(fixup_template_parms): Take the parms to fixup in argument.
	(fixup_current_template_parms): This is the new name for the
	former fixup_template_parms.  It has be re-written in terms of
	fixup_innermost_template_parms.
	* tree.c (compare_trees): Factorized this out of cp_tree_equal.
	Take a comparison control parameter. Use tree comparison functions
	that take a comparison control parm.
	(cp_tree_equal): Use the factorized compare_trees.
	(tsubst_template_parms):  Fixup template parameters that are
	level-reduced.
	(push_template_decl_real): Support declarations of friend template
	represented by TYPENAME_TYPE nodes.
	(tsubst_aggr_type, tsubst_decl)
	(tsubst<UNBOUND_CLASS_TEMPLATE, TYPENAME_TYPE>): Call
	tsubst_template_parms upfront to fixup dependant types that are to
	be level-reduced by a possible partial instantiation of a member
	template.
	(tsubst_pack_expansion): Adjust the use of arg_from_parm_pack_p.
	(get_mostly_instantiated_function_type): Fix this by setting the
	proper size for the args of tsubst, so that partial instantiation
	happens there.  Otherwise, tsubst indirectly and wrongly calls
	reduce_template_parm_level with a reduced level of 0.
	(make_auto): Adjust for sibling_parms instead of
	num_sibling_parms.
	* typeck.c (compparms_guided): Take a comparison control parameter.
	Split out of ...
	(compparms): ... this.
	(comp_template_parms_siblings): Define new function.
	(comp_template_parms_position): Take an additional parameter to
	control the comparison.  Use the new comp_template_parms_siblings.
	(structural_comptypes): Use type comparison routines variants that
	take the comparison control parm.
	(same_type_ignoring_top_level_qualifiers_guided_p): Take an
	additional parm to control comparison.  Use comptypes instead of
	comptypes.  Factorize out of ...
	(same_type_ignoring_top_level_qualifiers_p): ... this.
	* parser.c (cp_parser_template_parameter_list): Adjust for the
	change to using sibling_parms instead of num_sibling_parms.
	(cp_parser_template_declaration_after_export): Adjust
	to call fixup_current_template_parms instead of
	fixup_template_parms.
	(cp_parser_single_declaration):  Make friend typename declarations
	carry a template info.

gcc/testsuite/

	PR c++/50852
	* g++.dg/template/typedef39.C: New test.
	* g++.dg/template/typedef40.C: Likewise.
	* g++.dg/template/typedef41.C: Likewise.
	* g++.dg/template/crash84.C: This test should actually pass
	without error.

Address Jason's comments.
---
 gcc/cp/cp-tree.h                          |  110 ++++-
 gcc/cp/parser.c                           |   21 +-
 gcc/cp/pt.c                               |  924 +++++++++++++++++++++++------
 gcc/cp/tree.c                             |  115 +++--
 gcc/cp/typeck.c                           |  162 ++++--
 gcc/testsuite/g++.dg/template/crash84.C   |    8 +-
 gcc/testsuite/g++.dg/template/typedef39.C |   16 +
 gcc/testsuite/g++.dg/template/typedef40.C |   22 +
 gcc/testsuite/g++.dg/template/typedef41.C |   19 +
 9 files changed, 1100 insertions(+), 297 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/typedef39.C
 create mode 100644 gcc/testsuite/g++.dg/template/typedef40.C
 create mode 100644 gcc/testsuite/g++.dg/template/typedef41.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 71573ff..a8ef977 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -247,8 +247,12 @@ struct GTY(()) template_parm_index_s {
   struct tree_common common;
   int index;
   int level;
-  int orig_level;
-  int num_siblings;
+  /* If the current index was reduced from an original index, keep
+     track of the later using this pointer.  */
+  tree orig_index;
+  /* A TREE_VEC containing the set of parms this parameter belongs
+     to. */
+  tree siblings;
   tree decl;
 };
 typedef struct template_parm_index_s template_parm_index;
@@ -4476,6 +4480,9 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
 				   structural. The actual comparison
 				   will be identical to
 				   COMPARE_STRICT.  */
+#define COMPARE_NO_SIBLINGS   16 /* When comparing template
+				    parameters, don't consider their
+				    siblings.  */
 
 /* Used with push_overloaded_decl.  */
 #define PUSH_GLOBAL	     0  /* Push the DECL into namespace scope,
@@ -4509,11 +4516,84 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
 	((template_parm_index*)TEMPLATE_PARM_INDEX_CHECK (NODE))
 #define TEMPLATE_PARM_IDX(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->index)
 #define TEMPLATE_PARM_LEVEL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->level)
-/* The Number of sibling parms this template parm has.  */
-#define TEMPLATE_PARM_NUM_SIBLINGS(NODE) \
-  (TEMPLATE_PARM_INDEX_CAST (NODE)->num_siblings)
-#define TEMPLATE_PARM_DESCENDANTS(NODE) (TREE_CHAIN (NODE))
-#define TEMPLATE_PARM_ORIG_LEVEL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->orig_level)
+/* A TREE_VEC containing the sibling parameters for a given template
+   parm.  */
+#define TEMPLATE_PARM_SIBLINGS(NODE) \
+  (TEMPLATE_PARM_INDEX_CAST (NODE)->siblings)
+
+/* This accessor has to do with partial instantiation of member
+   templates and type fixup.
+
+   Consider the member template M below:
+
+	template<class T>
+	struct S
+	{
+	  template<class U> struct M {};
+	};
+
+   When we say template<class V> S<int>::M<V>, M is partially
+   instantiated and the level of its template parameter V is reduced;
+   it was 2 initially, but in the context of the partial
+   instantiation, it becomes 1.
+
+   TEMPLATE_PARM_DESCENDANTS for U captures the relationship between that
+   parameter and those that result from its level-reducing.
+
+   For template type parameters, TEMPLATE_PARM_DESCENDANTS is a vector
+   in which each element represents a parameter reduced to a level
+   that is the vector index of said element.  In the example above,
+   the element at index 1 of TEMPLATE_PARM_DESCENDANTS (U) will
+   contain V.
+
+   For non-type template parameters, TEMPLATE_PARM_DESCENDANTS is a
+   vector or TREE_LIST.  For a given level (that represents the index
+   of each element of the vector), there is a list of parameters
+   reduced to that level, and each parameter of that list has a
+   different type.  For instance:
+
+	template<class T>
+	struct S
+	{
+	  template<T a>  struct M {};
+	};
+
+   When we say template<> S<int>::M, the level of parameter 'a' is
+   reduced to 1 (from 2), and its type is 'int'.
+
+   When we say template<> S<int>::M, the level of 'a' is reduced to 1
+   as well, but its type is 'char'.
+
+   So in TEMPLATE_PARM_DESCENDANTS for parameter 'a', the element at
+   index 1 will be a TREE_LIST of two elements which first TREE_VALUE
+   is the TEMPLATE_PARM_INDEX for 'int a' and which second TREE_VALUE
+   is the TEMPLATE_PARM_INDEX for 'char a'.
+
+   Note that types of template parameters that are inserted into
+   TEMPLATE_PARM_DESCENDANTS are always fixed-up types.
+
+   Also note that the argument for TEMPLATE_PARM_DESCENDANT must be a
+   TEMPLATE_PARM_INDEX.  */
+#define TEMPLATE_PARM_DESCENDANTS(NODE) (TREE_CHAIN (TEMPLATE_PARM_INDEX_CHECK (NODE)))
+
+/* Returns the original index NODE is a descendant of.  Please look at
+   the comments for TEMPLATE_PARM_DESCENDANTS to know what a
+   descendant for an index is.  Note that after type fixup,
+   fixup_template_parm sets the ORIG_INDEX to the pre-fixup version of
+   the fixed-up type.  After template parameter type level reduction,
+   this (for the reduced index) points to the TEMPLATE_PARM_ORIG_INDEX
+   of the non-reduced index.  */
+#define TEMPLATE_PARM_ORIG_INDEX(NODE) \
+  (TEMPLATE_PARM_INDEX_CAST (NODE)->orig_index)
+
+/* Return the fixed-up type for a given original index.  Please read
+   the comment for TEMPLATE_PARM_ORIG_INDEX to learn what an original
+   index is.  */
+#define TEMPLATE_PARM_FIXED_UP_ORIG_INDEX(NODE)				\
+  (get_template_parm_index (TEMPLATE_PARM_DECL				\
+			    (TEMPLATE_PARM_ORIG_INDEX (NODE))))
+#define TEMPLATE_PARM_ORIG_LEVEL(NODE) \
+  (TEMPLATE_PARM_LEVEL (TEMPLATE_PARM_ORIG_INDEX (NODE)))
 #define TEMPLATE_PARM_DECL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->decl)
 #define TEMPLATE_PARM_PARAMETER_PACK(NODE) \
   (TREE_LANG_FLAG_0 (TEMPLATE_PARM_INDEX_CHECK (NODE)))
@@ -5280,9 +5360,10 @@ extern void append_type_to_template_for_access_check (tree, tree, tree,
 extern tree splice_late_return_type		(tree, tree);
 extern bool is_auto				(const_tree);
 extern tree process_template_parm		(tree, location_t, tree, 
-						 bool, bool, unsigned);
+						 bool, bool, tree);
 extern tree end_template_parm_list		(tree);
-void fixup_template_parms (void);
+extern void fixup_current_template_parms        (void);
+extern void fixup_template_parms                (tree);
 extern void end_template_decl			(void);
 extern tree maybe_update_decl_type		(tree, tree);
 extern bool check_default_tmpl_args             (tree, tree, int, int, int);
@@ -5307,8 +5388,12 @@ extern void do_type_instantiation		(tree, tree, tsubst_flags_t);
 extern bool always_instantiate_p		(tree);
 extern void maybe_instantiate_noexcept		(tree);
 extern tree instantiate_decl			(tree, int, bool);
+extern bool comp_template_parms_siblings        (tree, tree, int);
+extern int comp_template_parm_levels            (const_tree, const_tree, int);
+extern int comp_template_parms_guided		(const_tree, const_tree, int);
 extern int comp_template_parms			(const_tree, const_tree);
 extern bool uses_parameter_packs                (tree);
+extern bool template_type_parameter_type_p      (tree);
 extern bool template_parameter_pack_p           (const_tree);
 extern bool function_parameter_pack_p		(const_tree);
 extern bool function_parameter_expanded_from_pack_p (tree, tree);
@@ -5321,6 +5406,8 @@ extern int template_class_depth			(tree);
 extern int is_specialization_of			(tree, tree);
 extern bool is_specialization_of_friend		(tree, tree);
 extern tree get_pattern_parm			(tree, tree);
+extern int comp_template_args_guided            (tree, tree, tree *,
+						 tree *, int);
 extern int comp_template_args			(tree, tree);
 extern tree maybe_process_partial_specialization (tree);
 extern tree most_specialized_instantiation	(tree);
@@ -5366,6 +5453,7 @@ extern void init_template_processing		(void);
 extern void print_template_statistics		(void);
 bool template_template_parameter_p		(const_tree);
 extern bool primary_template_instantiation_p    (const_tree);
+extern tree get_template_parm_index             (tree);
 extern tree get_primary_template_innermost_parameters	(const_tree);
 extern tree get_template_parms_at_level (tree, int);
 extern tree get_template_innermost_arguments	(const_tree);
@@ -5700,6 +5788,7 @@ extern tree lvalue_type				(tree);
 extern tree error_type				(tree);
 extern int varargs_function_p			(const_tree);
 extern bool really_overloaded_fn		(tree);
+extern bool compare_trees                       (tree, tree, int);
 extern bool cp_tree_equal			(tree, tree);
 extern tree no_linkage_check			(tree, bool);
 extern void debug_binfo				(tree);
@@ -5760,6 +5849,9 @@ extern int type_unknown_p			(const_tree);
 enum { ce_derived, ce_normal, ce_exact };
 extern bool comp_except_specs			(const_tree, const_tree, int);
 extern bool comptypes				(tree, tree, int);
+extern bool same_type_ignoring_top_level_qualifiers_guided_p (tree type1,
+							      tree type2,
+							      int strict);
 extern bool same_type_ignoring_top_level_qualifiers_p (tree, tree);
 extern bool compparms				(const_tree, const_tree);
 extern int comp_cv_qualification		(const_tree, const_tree);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index c6bd290..37e82a9 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -11960,7 +11960,7 @@ cp_parser_template_parameter_list (cp_parser* parser)
 						parameter,
 						is_non_type,
 						is_parameter_pack,
-						0);
+						NULL_TREE);
       else
        {
          tree err_parm = build_tree_list (parameter, parameter);
@@ -21124,7 +21124,7 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
     {
       /* Parse the template parameters.  */
       parameter_list = cp_parser_template_parameter_list (parser);
-      fixup_template_parms ();
+      fixup_current_template_parms ();
     }
 
   /* Get the deferred access checks from the parameter list.  These
@@ -21289,6 +21289,7 @@ cp_parser_single_declaration (cp_parser* parser,
     {
       if (cp_parser_declares_only_class_p (parser))
 	{
+	  bool friend_typename_p = false;
 	  decl = shadow_tag (&decl_specifiers);
 
 	  /* In this case:
@@ -21303,7 +21304,10 @@ cp_parser_single_declaration (cp_parser* parser,
 	      && !decl
 	      && decl_specifiers.type
 	      && TYPE_P (decl_specifiers.type))
-	    decl = decl_specifiers.type;
+	    {
+	      decl = decl_specifiers.type;
+	      friend_typename_p = true;
+	    }
 
 	  if (decl && decl != error_mark_node)
 	    decl = TYPE_NAME (decl);
@@ -21312,6 +21316,17 @@ cp_parser_single_declaration (cp_parser* parser,
 
 	  /* Perform access checks for template parameters.  */
 	  cp_parser_perform_template_parameter_access_checks (checks);
+	  if (friend_typename_p
+	      && parser->num_template_parameter_lists > 0
+	      && decl != error_mark_node)
+	    /*  We are looking a the declaration of a class/enum which
+		name is a typename; that declaration has a template
+		header that declares some template parameters used in
+		the declaration.  Ensure the declaration carries a
+		template info representing that header.  That template
+		info will later be useful when we need to fixup the
+		template parameters used in the declaration.  */
+	    push_template_decl_real (decl, /*is_friend=*/true);
 	}
     }
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 4980c19..5c2379f 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -148,7 +148,7 @@ static tree convert_template_argument (tree, tree, tree,
 static int for_each_template_parm (tree, tree_fn_t, void*,
 				   struct pointer_set_t*, bool);
 static tree expand_template_argument_pack (tree);
-static tree build_template_parm_index (int, int, int, int, tree, tree);
+static tree build_template_parm_index (int, int, tree, tree, tree, tree);
 static bool inline_needs_template_parms (tree);
 static void push_inline_template_parms_recursive (tree, int);
 static tree retrieve_local_specialization (tree);
@@ -183,6 +183,7 @@ static tree try_class_unification (tree, tree, tree, tree, bool);
 static int coerce_template_template_parms (tree, tree, tsubst_flags_t,
 					   tree, tree);
 static bool template_template_parm_bindings_ok_p (tree, tree);
+static int template_args_equal_guided (tree, tree, int);
 static int template_args_equal (tree, tree);
 static void tsubst_default_arguments (tree);
 static tree for_each_template_parm_r (tree *, int *, void *);
@@ -201,12 +202,17 @@ static void append_type_to_template_for_access_check_1 (tree, tree, tree,
 							location_t);
 static tree listify (tree);
 static tree listify_autos (tree, tree);
-static tree template_parm_to_arg (tree t);
-static bool arg_from_parm_pack_p (tree, tree);
+static tree template_parm_to_arg (tree);
+static tree template_parms_to_args (tree);
+static bool arg_from_parm_pack_p (tree, tree, tree);
 static tree current_template_args (void);
-static tree fixup_template_type_parm_type (tree, int);
-static tree fixup_template_parm_index (tree, tree, int);
+static tree get_root_index_same_level (tree);
+static void add_descendant_to_parm_index (tree, tree);
+static tree get_descendant_of_parm_index (tree, int, tree);
+static tree fixup_template_type_parm_type (tree, tree);
+static tree fixup_template_parm_index (tree, tree, tree);
 static tree tsubst_template_parm (tree, tree, tsubst_flags_t);
+static void fixup_innermost_template_parms (tree, tree);
 
 /* Make the current scope suitable for access checking when we are
    processing T.  T can be FUNCTION_DECL for instantiated function
@@ -322,7 +328,16 @@ get_template_info (const_tree t)
     return NULL;
 
   if (DECL_P (t) && DECL_LANG_SPECIFIC (t))
-    tinfo = DECL_TEMPLATE_INFO (t);
+    {     
+      int code = TREE_CODE (t);
+      /* Only the DECLs below are allowed to have template info.  */
+      if (code == VAR_DECL
+	  || code == FIELD_DECL
+	  || code == FUNCTION_DECL
+	  || code == TYPE_DECL
+	  || code == TEMPLATE_DECL)
+	tinfo = DECL_TEMPLATE_INFO (t);
+    }
 
   if (!tinfo && DECL_IMPLICIT_TYPEDEF_P (t))
     t = TREE_TYPE (t);
@@ -331,6 +346,9 @@ get_template_info (const_tree t)
     tinfo = TYPE_TEMPLATE_INFO (t);
   else if (TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM)
     tinfo = TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t);
+  else if (TREE_CODE (t) == TYPENAME_TYPE
+	   && DECL_LANG_SPECIFIC (TYPE_NAME (t)))
+    tinfo = DECL_TEMPLATE_INFO (TYPE_NAME (t));
 
   return tinfo;
 }
@@ -2675,11 +2693,56 @@ check_explicit_specialization (tree declarator,
 }
 
 /* Returns 1 iff PARMS1 and PARMS2 are identical sets of template
+   parameters of a given level, represented by a TREE_VEC of
+   TREE_LIST.  The TREE_VALUE of each TREE_LIST represents a given
+   template parameter.  STRICT controls how the comparison is done.
+   It has the same meaning as the last parameter of the comptypes
+   function.  */
+
+int
+comp_template_parm_levels (const_tree parms_level1,
+			   const_tree parms_level2,
+			   int strict)
+{
+  int i;
+  gcc_assert (TREE_CODE (parms_level1) == TREE_VEC);
+  gcc_assert (TREE_CODE (parms_level2) == TREE_VEC);
+
+  if (TREE_VEC_LENGTH (parms_level1) != TREE_VEC_LENGTH (parms_level2))
+    return 0;
+
+  for (i = 0; i < TREE_VEC_LENGTH (parms_level2); ++i)
+    {
+      tree parm1 = TREE_VALUE (TREE_VEC_ELT (parms_level1, i));
+      tree parm2 = TREE_VALUE (TREE_VEC_ELT (parms_level2, i));
+
+      /* If either of the template parameters are invalid, assume
+	 they match for the sake of error recovery. */
+      if (parm1 == error_mark_node || parm2 == error_mark_node)
+	return 1;
+
+      if (TREE_CODE (parm1) != TREE_CODE (parm2))
+	return 0;
+
+      if (TREE_CODE (parm1) == TEMPLATE_TYPE_PARM
+	  && (TEMPLATE_TYPE_PARAMETER_PACK (parm1)
+	      == TEMPLATE_TYPE_PARAMETER_PACK (parm2)))
+	continue;
+      else if (!comptypes (TREE_TYPE (parm1), TREE_TYPE (parm2), strict))
+	return 0;
+    }
+  return 1;
+}
+
+/* Returns 1 iff PARMS1 and PARMS2 are identical sets of template
    parameters.  These are represented in the same format used for
-   DECL_TEMPLATE_PARMS.  */
+   DECL_TEMPLATE_PARMS.  STRICT controls how the comparison is done.
+   Its semantics are the same as the last parameter of comptypes.  */
 
 int
-comp_template_parms (const_tree parms1, const_tree parms2)
+comp_template_parms_guided (const_tree parms1,
+			    const_tree parms2,
+			    int strict)
 {
   const_tree p1;
   const_tree p2;
@@ -2693,34 +2756,9 @@ comp_template_parms (const_tree parms1, const_tree parms2)
     {
       tree t1 = TREE_VALUE (p1);
       tree t2 = TREE_VALUE (p2);
-      int i;
 
-      gcc_assert (TREE_CODE (t1) == TREE_VEC);
-      gcc_assert (TREE_CODE (t2) == TREE_VEC);
-
-      if (TREE_VEC_LENGTH (t1) != TREE_VEC_LENGTH (t2))
+      if (!comp_template_parm_levels (t1, t2, strict))
 	return 0;
-
-      for (i = 0; i < TREE_VEC_LENGTH (t2); ++i)
-	{
-          tree parm1 = TREE_VALUE (TREE_VEC_ELT (t1, i));
-          tree parm2 = TREE_VALUE (TREE_VEC_ELT (t2, i));
-
-          /* If either of the template parameters are invalid, assume
-             they match for the sake of error recovery. */
-          if (parm1 == error_mark_node || parm2 == error_mark_node)
-            return 1;
-
-	  if (TREE_CODE (parm1) != TREE_CODE (parm2))
-	    return 0;
-
-	  if (TREE_CODE (parm1) == TEMPLATE_TYPE_PARM
-              && (TEMPLATE_TYPE_PARAMETER_PACK (parm1)
-                  == TEMPLATE_TYPE_PARAMETER_PACK (parm2)))
-	    continue;
-	  else if (!same_type_p (TREE_TYPE (parm1), TREE_TYPE (parm2)))
-	    return 0;
-	}
     }
 
   if ((p1 != NULL_TREE) != (p2 != NULL_TREE))
@@ -2731,6 +2769,28 @@ comp_template_parms (const_tree parms1, const_tree parms2)
   return 1;
 }
 
+/* Returns 1 iff PARMS1 and PARMS2 are identical sets of template
+   parameters.  These are represented in the same format used for
+   DECL_TEMPLATE_PARMS.  */
+
+int
+comp_template_parms (const_tree parms1, const_tree parms2)
+{
+  return comp_template_parms_guided (parms1, parms2,
+				     COMPARE_STRICT);
+}
+
+/* Determine wheter PARM is the type of a template type parameter.  */
+
+bool
+template_type_parameter_type_p (tree t)
+{
+  return (t
+	  && (TREE_CODE (t) == TEMPLATE_TYPE_PARM
+	      || TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM
+	      || TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM));
+}
+
 /* Determine whether PARM is a parameter pack.  */
 
 bool 
@@ -3395,22 +3455,27 @@ check_template_shadow (tree decl)
 }
 
 /* Return a new TEMPLATE_PARM_INDEX with the indicated INDEX, LEVEL,
-   ORIG_LEVEL, DECL, and TYPE.  NUM_SIBLINGS is the total number of
-   template parameters.  */
+   ORIG_INDEX, DECL, and TYPE.  SIBLINGS is a TREE_VEC containing the
+   set of parameters the current template parameter belongs to.  */
 
 static tree
 build_template_parm_index (int index,
 			   int level,
-			   int orig_level,
-			   int num_siblings,
+			   tree orig_index,
+			   tree siblings,
 			   tree decl,
 			   tree type)
 {
-  tree t = make_node (TEMPLATE_PARM_INDEX);
+  tree t;
+
+  gcc_assert (level >= 1);
+
+  t = make_node (TEMPLATE_PARM_INDEX);
   TEMPLATE_PARM_IDX (t) = index;
   TEMPLATE_PARM_LEVEL (t) = level;
-  TEMPLATE_PARM_ORIG_LEVEL (t) = orig_level;
-  TEMPLATE_PARM_NUM_SIBLINGS (t) = num_siblings;
+  TEMPLATE_PARM_ORIG_INDEX (t) = orig_index ? orig_index : t;
+  gcc_assert (TREE_CODE (TEMPLATE_PARM_ORIG_INDEX (t)) == TEMPLATE_PARM_INDEX);
+  TEMPLATE_PARM_SIBLINGS (t) = siblings;
   TEMPLATE_PARM_DECL (t) = decl;
   TREE_TYPE (t) = type;
   TREE_CONSTANT (t) = TREE_CONSTANT (decl);
@@ -3458,13 +3523,15 @@ static tree
 reduce_template_parm_level (tree index, tree type, int levels, tree args,
 			    tsubst_flags_t complain)
 {
-  if (TEMPLATE_PARM_DESCENDANTS (index) == NULL_TREE
-      || (TEMPLATE_PARM_LEVEL (TEMPLATE_PARM_DESCENDANTS (index))
-	  != TEMPLATE_PARM_LEVEL (index) - levels)
-      || !same_type_p (type, TREE_TYPE (TEMPLATE_PARM_DESCENDANTS (index))))
+  int new_level = TEMPLATE_PARM_LEVEL (index) - levels;
+  tree t = NULL_TREE;
+
+  gcc_assert (new_level > 0);
+
+  if ((t = get_descendant_of_parm_index (index, new_level, type)) == NULL_TREE)
     {
       tree orig_decl = TEMPLATE_PARM_DECL (index);
-      tree decl, t;
+      tree decl;
 
       decl = build_decl (DECL_SOURCE_LOCATION (orig_decl),
 			 TREE_CODE (orig_decl), DECL_NAME (orig_decl), type);
@@ -3475,10 +3542,18 @@ reduce_template_parm_level (tree index, tree type, int levels, tree args,
 
       t = build_template_parm_index (TEMPLATE_PARM_IDX (index),
 				     TEMPLATE_PARM_LEVEL (index) - levels,
-				     TEMPLATE_PARM_ORIG_LEVEL (index),
-				     TEMPLATE_PARM_NUM_SIBLINGS (index),
+				     TEMPLATE_PARM_ORIG_INDEX (index),
+				     /* We will fixup the siblings for
+				       this index in
+				       tsubst_template_parms, so set
+				       it to NULL here.  */
+				     NULL_TREE,
 				     decl, type);
-      TEMPLATE_PARM_DESCENDANTS (index) = t;
+      /* Do not yet update TEMPLATE_PARM_DESCENDANTS
+	 (TEMPLATE_PARM_ORIG_INDEX (index)) because it will be done
+	 when the new parm index T is fixed up, along with its
+	 siblings, using a call to add_descendant_to_parm_index.  */
+
       TEMPLATE_PARM_PARAMETER_PACK (t) 
 	= TEMPLATE_PARM_PARAMETER_PACK (index);
 
@@ -3489,23 +3564,23 @@ reduce_template_parm_level (tree index, tree type, int levels, tree args,
 	   args, complain);
     }
 
-  return TEMPLATE_PARM_DESCENDANTS (index);
+  return t;
 }
 
 /* Process information from new template parameter PARM and append it
    to the LIST being built.  This new parameter is a non-type
    parameter iff IS_NON_TYPE is true. This new parameter is a
    parameter pack iff IS_PARAMETER_PACK is true.  The location of PARM
-   is in PARM_LOC. NUM_TEMPLATE_PARMS is the size of the template
-   parameter list PARM belongs to. This is used used to create a
+   is in PARM_LOC.  SIBLING_PARMS is a TREE_VEC containing the set of
+   template parameters PARM belongs to.  This is used used to create a
    proper canonical type for the type of PARM that is to be created,
-   iff PARM is a type.  If the size is not known, this parameter shall
-   be set to 0.  */
+   iff PARM is a type.  If the set of parameters is not known, this
+   parameter shall be set to NULL_TREE.  */
 
 tree
 process_template_parm (tree list, location_t parm_loc, tree parm,
 		       bool is_non_type, bool is_parameter_pack,
-		       unsigned num_template_parms)
+		       tree sibling_parms)
 {
   tree decl = 0;
   tree defval;
@@ -3579,8 +3654,8 @@ process_template_parm (tree list, location_t parm_loc, tree parm,
       TREE_READONLY (decl) = 1;
       DECL_INITIAL (parm) = DECL_INITIAL (decl)
 	= build_template_parm_index (idx, processing_template_decl,
-				     processing_template_decl,
-				     num_template_parms,
+				     NULL_TREE,
+				     sibling_parms,
 				     decl, TREE_TYPE (parm));
 
       TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)) 
@@ -3613,8 +3688,8 @@ process_template_parm (tree list, location_t parm_loc, tree parm,
       parm = decl;
       TEMPLATE_TYPE_PARM_INDEX (t)
 	= build_template_parm_index (idx, processing_template_decl,
-				     processing_template_decl,
-				     num_template_parms,
+				     NULL_TREE,
+				     sibling_parms,
 				     decl, TREE_TYPE (parm));
       TEMPLATE_TYPE_PARAMETER_PACK (t) = is_parameter_pack;
       TYPE_CANONICAL (t) = canonical_type_parameter (t);
@@ -3654,34 +3729,292 @@ end_template_parm_list (tree parms)
   return saved_parmlist;
 }
 
+/*  Get the "canonical" INDEX of a given TEMPLATE_PARM_INDEX tree
+    node.
+
+    There can be several equivalent TEMPLATE_PARM_INDEX created for a
+    given template parameter, be it a type or non-type template
+    parameter.
+
+    For a type template parameter P, this function returns the
+    TEMPLATE_PARM_INDEX of the canonical type of P.
+
+    For a non-type template parameter P, this function returns the the
+    "original" (and fixed-up) TEMPLATE_PARM_INDEX P was created from,
+    given that they both have the same level.  Please read the comment
+    of fixup_template_parm_index to learn what type fix-up is.  */
+
+static tree
+get_root_index_same_level (tree index)
+{
+  tree i = index;
+
+  if (TREE_CODE (TEMPLATE_PARM_DECL (i)) == CONST_DECL)
+    {
+      if (TEMPLATE_PARM_ORIG_LEVEL (i) == TEMPLATE_PARM_LEVEL (index))
+	i = TEMPLATE_PARM_FIXED_UP_ORIG_INDEX (i);
+    }
+  else
+    {
+      if (template_type_parameter_type_p (TREE_TYPE (i))
+	  && TYPE_CANONICAL (TREE_TYPE (i)) != NULL_TREE)
+	i = TEMPLATE_TYPE_PARM_INDEX (TYPE_CANONICAL (TREE_TYPE (i)));
+    }
+  return i;
+}
+
+/*  Add a descendant to a given template parameter index INDEX.  A
+    descendant of INDEX is the result of reducing the level of INDEX
+    to another level.  The property TEMPLATE_PARM_DESCENDANT of INDEX
+    is a vector that contains the descendants of INDEX.  This function
+    properly appends the descendant of INDEX to that
+    TEMPLATE_PARM_DESCENDANT vector.  */
+
+static void
+add_descendant_to_parm_index (tree index,
+			      tree descendant)
+{
+  tree *where = NULL;
+
+  gcc_assert (TREE_CODE (index) == TEMPLATE_PARM_INDEX
+	      && TREE_CODE (descendant) == TEMPLATE_PARM_INDEX
+	      && TEMPLATE_PARM_LEVEL (descendant) > 0
+	      && TEMPLATE_PARM_LEVEL (index) > 0
+	      && TEMPLATE_PARM_LEVEL (descendant) <= TEMPLATE_PARM_LEVEL (index));
+
+  if (TYPE_CANONICAL (TREE_TYPE (TEMPLATE_PARM_DECL (descendant)))
+      != NULL_TREE)
+    /*  For a descendant that requires canonical type comparison
+	(unlike for reduced template template parms) we only accept
+	types that have been fixed-up.  */
+    gcc_assert (TEMPLATE_PARM_SIBLINGS (descendant) != NULL_TREE);
+
+  index = get_root_index_same_level (index);
+
+  if (TEMPLATE_PARM_DESCENDANTS (index) == NULL_TREE)
+    TEMPLATE_PARM_DESCENDANTS (index) =
+      make_tree_vec (TEMPLATE_PARM_LEVEL (index));
+
+  where = &TREE_VEC_ELT (TEMPLATE_PARM_DESCENDANTS (index),
+			 TEMPLATE_PARM_LEVEL (descendant) - 1);
+
+  if (TREE_CODE (TEMPLATE_PARM_DECL (index)) == CONST_DECL)
+    {
+    /* INDEX is for a non-type template param.  So each one of its
+       descendant might have a different type.  To see that, consider:
+
+       template<class T> struct S
+       {
+       template<template<T i> class TT> struct Inner;
+       };
+
+       Then if we write:
+
+       S<int> s0;
+
+       As a result, in:
+	 
+       template<> template<template<int i> class TT>
+       S<int>::Inner<TT>
+
+       'i' has level 2, which was reduced from its inital level 3.
+       But look at how its type is 'int'.
+
+       But if we write:
+
+       S<char> s1;
+
+       Then, in:
+
+       template<> template<template<char i> class TT>
+       S<char>::Inner<TT>
+
+       'i' still has level 2 (reduced from initial level 3), but its
+       type is now 'char'.
+
+       So both 'i' of level 2 that are descendants of the initial
+       'i' of level 3, but each of them (might) have a separate
+       type.
+
+       Therefore, at each index of TEMPLATE_PARM_DESCENDANTS (that
+       represent a level) we have a TREE_LIST in which each
+       TREE_PURPOSE has the type of TEMPLATE_PARM_INDEX and each
+       TREE_VALUE has the TEMPLATE_PARM_INDEX itself.  */
+      if (*where != NULL_TREE)
+	gcc_assert (TEMPLATE_PARM_LEVEL (TREE_VALUE (*where)) 
+		    == TEMPLATE_PARM_LEVEL (descendant));
+      *where = tree_cons (TREE_TYPE (descendant),
+			  descendant,
+			  *where);
+    }
+  else
+    {
+      if (*where == NULL_TREE)
+	*where = descendant;
+      else
+	gcc_assert (same_type_p (TREE_TYPE (*where),
+				 TREE_TYPE (descendant)));
+    }
+}
+
+/*  Inspect the TEMPLATE_PARM_DESCENDANTS vector associated to INDEX
+    to return its descendant for a given level and type.  */
+
+static tree
+get_descendant_of_parm_index (tree index,
+			      int level,
+			      tree type)
+{
+  tree result = NULL_TREE, orig_index = index;
+
+  gcc_assert (TREE_CODE (index) == TEMPLATE_PARM_INDEX
+	      && TEMPLATE_PARM_LEVEL (index) > 0
+	      && level > 0);
+
+  index = get_root_index_same_level (index);
+
+  if (TEMPLATE_PARM_DESCENDANTS (index))
+    {
+      gcc_assert (TREE_CODE (TEMPLATE_PARM_DESCENDANTS (index)) == TREE_VEC);
+      if (TREE_VEC_LENGTH (TEMPLATE_PARM_DESCENDANTS (index)) >= level)
+	{
+	  tree elem = TREE_VEC_ELT (TEMPLATE_PARM_DESCENDANTS (index),
+				    level - 1);
+	  if (TREE_CODE (TEMPLATE_PARM_DECL (index)) == CONST_DECL)
+	    /* We are looking for the index of a non-type template
+	       parm.  */
+	    for (; elem != NULL_TREE; elem = TREE_CHAIN (elem))
+	      {
+		if (same_type_p (TREE_TYPE (TREE_VALUE (elem)),
+				 type))
+		  result = TREE_VALUE (elem);
+	      }
+	  else
+	    /* We are looking for the index of type template parm.  */
+	    result = elem;
+	  if (result != NULL_TREE
+	      && (TEMPLATE_PARM_LEVEL (result) != TEMPLATE_PARM_LEVEL (orig_index))
+	      && (DECL_SOURCE_LOCATION (TEMPLATE_PARM_DECL (result))
+		  != DECL_SOURCE_LOCATION (TEMPLATE_PARM_DECL (orig_index))))
+	    {
+	      /*  We have gotten an equivalent index, that was reduced
+		  from an index equivalent to ORIG_INDEX, but which
+		  (location of) DECL is different.  This can lead to
+		  having error messages pointing to the wrong
+		  location, so let's build an equivalent
+		  TEMPLATE_PARM_INDEX with a DECL pointing to the same
+		  location as ORIG_INDEX for RESULT.  */
+	      tree decl, orig_decl, orig_result = result, decl_type;
+
+	      decl = orig_decl = TEMPLATE_PARM_DECL (orig_index);
+
+	      if (TREE_CODE (decl) == TYPE_DECL
+		  || TREE_CODE (decl) == PARM_DECL
+		  || TREE_CODE (decl) == CONST_DECL)
+		{
+		  decl_type = copy_type (TREE_TYPE (result));
+		  TYPE_MAIN_VARIANT (decl_type) = decl_type;
+		  TYPE_NEXT_VARIANT (decl_type)= NULL_TREE;
+		  TYPE_POINTER_TO (decl_type) = 0;
+		  TYPE_REFERENCE_TO (decl_type) = 0;
+
+		  decl = build_decl (DECL_SOURCE_LOCATION (orig_decl),
+				     TREE_CODE (orig_decl), DECL_NAME (orig_decl),
+				     decl_type);
+		  TREE_CONSTANT (decl) = TREE_CONSTANT (orig_decl);
+		  TREE_READONLY (decl) = TREE_READONLY (orig_decl);
+		  DECL_ARTIFICIAL (decl) = 1;
+		  SET_DECL_TEMPLATE_PARM_P (decl);
+
+		  TYPE_NAME (decl_type) = decl;
+
+		  result = build_template_parm_index (TEMPLATE_PARM_IDX (result),
+						      TEMPLATE_PARM_LEVEL (result),
+						      TEMPLATE_PARM_ORIG_INDEX (result),
+						      TEMPLATE_PARM_SIBLINGS (result),
+						      decl,
+						      decl_type);
+		  TEMPLATE_PARM_PARAMETER_PACK (result) =
+		    TEMPLATE_PARM_PARAMETER_PACK (orig_result);
+		  TEMPLATE_PARM_DESCENDANTS (result) =
+		    TEMPLATE_PARM_DESCENDANTS (orig_result);
+		}
+	    }
+
+	}
+    }
+  return result;
+}
+
+/*  Return the TEMPLATE_PARM_INDEX of a template parameter PARM.  PARM
+    can be either the type of a template parameter, or its DECL.  */
+
+tree
+get_template_parm_index (tree parm)
+{
+  tree result = NULL_TREE;
+
+  switch (TREE_CODE (parm))
+    {
+    case TEMPLATE_PARM_INDEX:
+      result = parm;
+      break;
+
+    case TEMPLATE_TYPE_PARM:
+    case TEMPLATE_TEMPLATE_PARM:
+    case BOUND_TEMPLATE_TEMPLATE_PARM:
+      result = TEMPLATE_TYPE_PARM_INDEX (parm);
+      break;
+
+    case PARM_DECL:
+    case CONST_DECL:
+      gcc_assert (DECL_TEMPLATE_PARM_P (parm));
+      return get_template_parm_index (DECL_INITIAL (parm));
+
+    case TEMPLATE_DECL:
+    case TYPE_DECL:
+      gcc_assert (DECL_TEMPLATE_PARM_P (parm));      
+      return get_template_parm_index (TREE_TYPE (parm));
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return result;
+}
+
 /* Create a new type almost identical to TYPE but which has the
    following differences:
 
-     1/ T has a new TEMPLATE_PARM_INDEX that carries the new number of
-     template sibling parameters of T.
+     1/ T has a new TEMPLATE_PARM_INDEX that carries the set of
+     sibling template parameters of T.
 
-     2/ T has a new canonical type that matches the new number
-     of sibling parms.
+     2/ T has a new canonical type that matches the set of sibling
+     parms.
 
      3/ From now on, T is going to be what lookups referring to the
-     name of TYPE will return. No lookup should return TYPE anymore.
+     name of TYPE will return.  No lookup should return TYPE anymore.
 
-   NUM_PARMS is the new number of sibling parms TYPE belongs to.
+   SIBLING_PARMS is the set of sibling parms TYPE belongs to.
 
-   This is a subroutine of fixup_template_parms.  */
+   This is a subroutine of fixup_innermost_template_parms.  */
 
 static tree
-fixup_template_type_parm_type (tree type, int num_parms)
-{
-  tree orig_idx = TEMPLATE_TYPE_PARM_INDEX (type), idx;
-  tree t;
+fixup_template_type_parm_type (tree type, tree sibling_parms)
+{
+  tree orig_idx = TEMPLATE_TYPE_PARM_INDEX (type);
+  tree t, idx;
+  /* This is going to be the TEMPLATE_PARM_ORIG_INDEX of the fixed-up
+     type.  It points to the non-fixed-up version of the original
+     index of TYPE.  */
+  tree parent_idx = TEMPLATE_PARM_ORIG_INDEX (orig_idx);
   /* This is the decl which name is inserted into the symbol table for
      the template parm type. So whenever we lookup the type name, this
      is the DECL we get.  */
   tree decl;
 
   /* Do not fix up the type twice.  */
-  if (orig_idx && TEMPLATE_PARM_NUM_SIBLINGS (orig_idx) != 0)
+  if (orig_idx && TEMPLATE_PARM_SIBLINGS (orig_idx) != NULL_TREE)
     return type;
 
   t = copy_type (type);
@@ -3694,10 +4027,10 @@ fixup_template_type_parm_type (tree type, int num_parms)
 
   idx = build_template_parm_index (TEMPLATE_PARM_IDX (orig_idx),
 				   TEMPLATE_PARM_LEVEL (orig_idx),
-				   TEMPLATE_PARM_ORIG_LEVEL (orig_idx),
-				   num_parms,
+				   parent_idx,
+				   sibling_parms,
 				   decl, t);
-  TEMPLATE_PARM_DESCENDANTS (idx) = TEMPLATE_PARM_DESCENDANTS (orig_idx);
+
   TEMPLATE_PARM_PARAMETER_PACK (idx) = TEMPLATE_PARM_PARAMETER_PACK (orig_idx);
   TEMPLATE_TYPE_PARM_INDEX (t) = idx;
 
@@ -3711,7 +4044,15 @@ fixup_template_type_parm_type (tree type, int num_parms)
      type is properly fixed up.  */
   TREE_TYPE (decl) = t;
 
-  TYPE_CANONICAL (t) = canonical_type_parameter (t);
+  /* Don't set canonical type if the original type was requiring
+     structural equality.  This can happen for e.g, types of template
+     template parms that got level-reduced.  */
+  if (!TYPE_STRUCTURAL_EQUALITY_P (type))
+    TYPE_CANONICAL (t) = canonical_type_parameter (t);
+
+  /* Update descendants of the fixed-up version of the original index
+     IDX is reduced from.  */
+  add_descendant_to_parm_index (TEMPLATE_PARM_FIXED_UP_ORIG_INDEX (idx), idx);
 
   return t;
 }
@@ -3719,50 +4060,57 @@ fixup_template_type_parm_type (tree type, int num_parms)
 /* Create and return a new TEMPLATE_PARM_INDEX that is almost
    identical to I, but that is fixed up as to:
 
-   1/ carry the number of sibling parms (NUM_PARMS) of the template
+   1/ carry the set of sibling parms (SIBLING_PARMS) of the template
    parm represented by I.
 
    2/ replace all references to template parm types declared before I
    (in the same template parm list as I) by references to template
-   parm types contained in ARGS. ARGS should contain the list of
+   parm types contained in ARGS.  ARGS should contain the list of
    template parms that have been fixed up so far, in a form suitable
    to be passed to tsubst.
 
-   This is a subroutine of fixup_template_parms.  */
+   This is a subroutine of fixup_innermost_template_parms.  */
 
 static tree
-fixup_template_parm_index (tree i, tree args, int num_parms)
+fixup_template_parm_index (tree i, tree args, tree sibling_parms)
 {
-  tree index, decl, type;
+  tree index, decl, type, parent_idx;
 
   if (i == NULL_TREE
       || TREE_CODE (i) != TEMPLATE_PARM_INDEX
       /* Do not fix up the index twice.  */
-      || (TEMPLATE_PARM_NUM_SIBLINGS (i) != 0))
+      || (TEMPLATE_PARM_SIBLINGS (i) != NULL_TREE))
     return i;
 
+  /* This is going to be the TEMPLATE_PARM_ORIG_INDEX of the fixed-up
+     index.  It points to the non-fixed-up version of the original
+     index of I.  */
+  parent_idx = TEMPLATE_PARM_ORIG_INDEX (i);
   decl = TEMPLATE_PARM_DECL (i);
   type = TREE_TYPE (decl);
 
   index = build_template_parm_index (TEMPLATE_PARM_IDX (i),
 				     TEMPLATE_PARM_LEVEL (i),
-				     TEMPLATE_PARM_ORIG_LEVEL (i),
-				     num_parms,
+				     parent_idx, sibling_parms,
 				     decl, type);
 
   TEMPLATE_PARM_DESCENDANTS (index) = TEMPLATE_PARM_DESCENDANTS (i);
   TEMPLATE_PARM_PARAMETER_PACK (index) = TEMPLATE_PARM_PARAMETER_PACK (i);
 
   type = tsubst (type, args, tf_none, NULL_TREE);
-  
+
   TREE_TYPE (decl) = type;
   TREE_TYPE (index) = type;
 
+  /* Update descendants of the fixed-up version of the original index
+     INDEX is reduced from.  */
+  add_descendant_to_parm_index (TEMPLATE_PARM_FIXED_UP_ORIG_INDEX (index),
+				index);
   return index;
 }
 
 /* 
-   This is a subroutine of fixup_template_parms.
+   This is a subroutine of fixup_innermost_template_parms.
 
    It computes the canonical type of the type of the template
    parameter PARM_DESC and update all references to that type so that
@@ -3770,8 +4118,8 @@ fixup_template_parm_index (tree i, tree args, int num_parms)
    performed during the fixup. PARM_DESC is a TREE_LIST which
    TREE_VALUE is the template parameter and its TREE_PURPOSE is the
    default argument of the template parm if any. IDX is the index of
-   the template parameter, starting at 0. NUM_PARMS is the number of
-   template parameters in the set PARM_DESC belongs to. ARGLIST is a
+   the template parameter, starting at 0. SIBLING_PARMS is the set of
+   template parameters the PARM_DESC belongs to. ARGLIST is a
    TREE_VEC containing the full set of template parameters in a form
    suitable to be passed to substs functions as their ARGS
    argument. This is what current_template_args returns for a given
@@ -3782,11 +4130,18 @@ fixup_template_parm_index (tree i, tree args, int num_parms)
 static void
 fixup_template_parm (tree parm_desc,
 		     int idx,
-		     int num_parms,
+		     tree sibling_parms,
 		     tree arglist)
 {
   tree parm = TREE_VALUE (parm_desc);
-  tree fixedup_args = INNERMOST_TEMPLATE_ARGS (arglist);
+  tree fixedup_args;
+  int level;
+
+  if (parm == error_mark_node)
+    return;
+
+  template_parm_level_and_index (parm, &level, NULL);
+  fixedup_args = TMPL_ARGS_LEVEL (arglist, level);
 
   push_deferring_access_checks (dk_no_check);
 
@@ -3798,7 +4153,7 @@ fixup_template_parm (tree parm_desc,
 	 template parms into the default argument of this
 	 parameter.  */
       tree t =
-	fixup_template_type_parm_type (TREE_TYPE (parm), num_parms);
+	fixup_template_type_parm_type (TREE_TYPE (parm), sibling_parms);
       TREE_TYPE (parm) = t;
 
       TREE_VEC_ELT (fixedup_args, idx) = template_parm_to_arg (parm_desc);
@@ -3852,13 +4207,12 @@ fixup_template_parm (tree parm_desc,
 	    template_parm_to_arg (parameter);
 
 	  fixup_template_parm (parameter, j,
-			       TREE_VEC_LENGTH (tparms),
-			       targs);
+			       tparms, targs);
 	}
 
       /* Now fix up the type of the template template parm.  */
 
-      t = fixup_template_type_parm_type (TREE_TYPE (parm), num_parms);
+      t = fixup_template_type_parm_type (TREE_TYPE (parm), sibling_parms);
       TREE_TYPE (parm) = t;
 
       TREE_VEC_ELT (fixedup_args, idx) =
@@ -3898,7 +4252,7 @@ fixup_template_parm (tree parm_desc,
 	 fixup the type of PUSHED_DECL as well and luckily
 	 fixup_template_parm_index does it for us too.  */
       tree fixed_up_index =
-	fixup_template_parm_index (index, arglist, num_parms);
+	fixup_template_parm_index (index, arglist, sibling_parms);
 
       DECL_INITIAL (pushed_decl) = DECL_INITIAL (parm) = fixed_up_index;
 
@@ -3918,39 +4272,99 @@ fixup_template_parm (tree parm_desc,
   pop_deferring_access_checks ();
 }
 
-/* Walk the current template parms and properly compute the canonical
-   types of the dependent types created during
-   cp_parser_template_parameter_list.  */
+/* Walk the innermost template parameters of PARMS parms and properly
+   compute the canonical types of the dependent types created during
+   cp_parser_template_parameter_list.  ARGLIST contains a TREE_VEC of
+   arguments built from the elements of PARMS that have been fixed-up
+   so far.  This function  udpates ARGLIST as it runs.  If the caller
+   of this function  is not interested in getting ARGLIST, it can
+   set it to NULL_TREE.  */
 
-void
-fixup_template_parms (void)
+static void
+fixup_innermost_template_parms (tree parms, tree arglist)
 {
-  tree arglist;
   tree parameter_vec;
-  tree fixedup_args;
   int i, num_parms;
 
-  parameter_vec = INNERMOST_TEMPLATE_PARMS (current_template_parms);
+  if (parms == NULL_TREE || parms == error_mark_node)
+    return;
+
+  parameter_vec = INNERMOST_TEMPLATE_PARMS (parms);
   if (parameter_vec == NULL_TREE)
     return;
 
   num_parms = TREE_VEC_LENGTH (parameter_vec);
 
-  /* This vector contains the current innermost template parms that
-     have been fixed up so far.  The form of FIXEDUP_ARGS is suitable
-     to be passed to tsubst* functions as their ARGS argument.  */
-  fixedup_args = make_tree_vec (num_parms);
-
   /* This vector contains the full set of template parms in a form
      suitable to be passed to substs functions as their ARGS
      argument.  */
-  arglist = current_template_args ();
-  arglist = add_outermost_template_args (arglist, fixedup_args);
+  if (arglist == NULL_TREE)
+    {
+      tree fixedup_args;
+      arglist = template_parms_to_args (parms);
+      /* This vector contains the current innermost template parms
+	 that have been fixed up so far.  The form of ARGLIST is
+	 suitable to be passed to tsubst* functions as their ARGS
+	 argument.  */
+      fixedup_args = make_tree_vec (num_parms);
+      arglist = add_outermost_template_args (arglist, fixedup_args);
+    }
 
   /* Let's do the proper fixup now.  */
   for (i = 0; i < num_parms; ++i)
     fixup_template_parm (TREE_VEC_ELT (parameter_vec, i),
-			 i, num_parms, arglist);
+			 i, parameter_vec, arglist);
+}
+
+/*  Fixup the template parameters PARMS; that is, compute the
+    canonical types of each parameter therein.
+
+    Note that PARMS must be of the form described in the comments of
+    the DECL_TEMPLATE_PARMS accessor in cp-tree.h.  */
+
+void
+fixup_template_parms (tree parms)
+{
+  tree level, args;
+  int i;
+
+  if (parms == NULL_TREE || parms == error_mark_node)
+    return;
+
+
+  if (TMPL_PARMS_DEPTH (parms) > 1)
+    {
+      int parms_depth = TMPL_PARMS_DEPTH (parms);
+      args = make_tree_vec (parms_depth);
+      for (i = 0; i < parms_depth; ++i)
+	{
+	  level = get_template_parms_at_level (parms, i + 1);
+	  if (level == NULL_TREE)
+	    continue;
+	  TREE_VEC_ELT (args, i) =
+	    make_tree_vec (TREE_VEC_LENGTH (TREE_VALUE (level)));
+	}
+    }
+  else
+    args = make_tree_vec (TREE_VEC_LENGTH (TREE_VALUE (parms)));
+
+  /* Template parms ought to be fixed-up from left to right.  */
+  parms = nreverse (parms);
+
+  for (level = parms; level != NULL_TREE; level = TREE_CHAIN (level))
+    fixup_innermost_template_parms (level, args);
+
+  parms = nreverse (parms);
+}
+
+/* Walk the current template parms and properly compute the canonical
+   types of the dependent types created during
+   cp_parser_template_parameter_list.  */
+
+void
+fixup_current_template_parms (void)
+{
+  fixup_innermost_template_parms (current_template_parms, NULL_TREE);
 }
 
 /* end_template_decl is called after a template declaration is seen.  */
@@ -4034,11 +4448,19 @@ template_parm_to_arg (tree t)
 
 /* This function returns TRUE if PARM_PACK is a template parameter
    pack and if ARG_PACK is what template_parm_to_arg returned when
-   passed PARM_PACK.  */
+   passed PARM_PACK.  PACK_EXPANSION is the pack expansion PARM_PACK
+   is part of.  This function is used in tsubst_pack_expansion.  */
 
 static bool
-arg_from_parm_pack_p (tree arg_pack, tree parm_pack)
+arg_from_parm_pack_p (tree arg_pack, tree parm_pack, tree pack_expansion)
 {
+  /* We want parm_pack to be a type or non-type parameter pack.  */
+  if (parm_pack == NULL_TREE
+      || (!template_type_parameter_type_p (parm_pack)
+	  && !(DECL_P (parm_pack) && DECL_TEMPLATE_PARM_P (parm_pack))
+	  && TREE_CODE (parm_pack) != TEMPLATE_PARM_INDEX))
+    return false;
+
   /* For clarity in the comments below let's use the representation
      argument_pack<elements>' to denote an argument pack and its
      elements.
@@ -4056,50 +4478,87 @@ arg_from_parm_pack_p (tree arg_pack, tree parm_pack)
     {
       tree expansion = TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack), 0);
       tree pattern = PACK_EXPANSION_PATTERN (expansion);
+      tree extra_args = PACK_EXPANSION_EXTRA_ARGS (pack_expansion);
+      tree index_pattern = get_template_parm_index (pattern);
+      tree index_parm_pack = get_template_parm_index (parm_pack);
+      int extra_args_depth = extra_args ? TMPL_ARGS_DEPTH (extra_args) : 0;
+
       /* So we have an argument_pack<P...>.  We want to test if P
 	 is actually PARM_PACK.  We will not use cp_tree_equal to
 	 test P and PARM_PACK because during type fixup (by
-	 fixup_template_parm) P can be a pre-fixup version of a
-	 type and PARM_PACK be its post-fixup version.
+	 fixup_template_parm) P can be a post-fixup version of a
+	 type and PARM_PACK be its pre-fixup version.
 	 cp_tree_equal would consider them as different even
 	 though we would want to consider them compatible for our
-	 precise purpose here.
-
-	 Thus we are going to consider that P and PARM_PACK are
-	 compatible if they have the same DECL.  */
-      if ((/* If ARG_PACK is a type parameter pack named by the
-	      same DECL as parm_pack ...  */
-	   (TYPE_P (pattern)
-	    && TYPE_P (parm_pack)
-	    && TYPE_NAME (pattern) == TYPE_NAME (parm_pack))
-	   /* ... or if PARM_PACK is a non-type parameter named by the
-	      same DECL as ARG_PACK.  Note that PARM_PACK being a
-	      non-type parameter means it's either a PARM_DECL or a
-	      TEMPLATE_PARM_INDEX.  */
-	   || (TREE_CODE (pattern) == TEMPLATE_PARM_INDEX
-	       && ((TREE_CODE (parm_pack) == PARM_DECL
-		    && (TEMPLATE_PARM_DECL (pattern)
-			== TEMPLATE_PARM_DECL (DECL_INITIAL (parm_pack))))
-		   || (TREE_CODE (parm_pack) == TEMPLATE_PARM_INDEX
-		       && (TEMPLATE_PARM_DECL (pattern)
-			   == TEMPLATE_PARM_DECL (parm_pack))))))
-	  && template_parameter_pack_p (pattern))
+	 precise purpose here.  */
+
+      /* Thus, if P and PARM_PACK have the same level (that is, P is
+	 not the result of level-reducing PARM_PACK), we are going to
+	 consider that P and PARM_PACK are compatible if they have the
+	 same DECL.  Testing this works if P and PARM_PACK are
+	 post-fixup and pre-fixup versions of the same type, or if
+	 they are equal.  */
+
+      if (TEMPLATE_PARM_DECL (index_pattern)
+	  == TEMPLATE_PARM_DECL (index_parm_pack))
 	return true;
+
+      /*  But if P is the result of level-reducing PARM_PACK, then we
+	  are in a different business.
+
+	  In that case, PARM_PACK is a pack that is part of the pack
+	  expansion PACK_EXPANSION that has been partially
+	  instantiated (or rather substituted into) with a set of
+	  arguments ARGS0 which depth is less than the level of
+	  PARM_PACK; the level of PARM_PACK is not reduced, unlike
+	  what happens for a non-pack template parameter.
+
+	  Rather, PACK_EXPANSION remembers ARGS0 and later, when an
+	  attempt to instantiate PACK_EXPANSION with a set of
+	  arguments ARGS1 which is so that the set {ARGS0, ARGS1} is
+	  deep enough to fully instantiate PACK_EXPANSION,
+	  PACK_EXPANSION is substituted into with the arguments
+	  {ARGS0, ARGS1}.
+
+	  So in the time interval between when PACK_EXPANSION
+	  remembers ARGS0 and when it gets ARGS1, the level of
+	  PARM_PACK stays the same, even if it has been "morally
+	  reduced".  If the type fixup of PARM_PACK happens in that
+	  time interval, we'll need to be able to detect that ARG_PACK
+	  is the result of template_parm_to_arg called on PARM_PACK' -
+	  which is the result of morally reducing the level of
+	  PARM_PACK and fixing up its type.
+
+	  For this case, TEMPLATE_PARM_ORIG_INDEX of the type in
+	  ARG_PACK (which is P) must point to the type original
+	  (non-fixed-up) type it was reduced from and fixed -up; that
+	  is, PARM_PACK.  */
+      if (TEMPLATE_PARM_LEVEL (index_pattern)
+	  == (TEMPLATE_PARM_LEVEL (index_parm_pack) - extra_args_depth))
+	{
+	  /* So the moral level-reducing happened.  Let's see if the
+	     original non-fixed-up parent index of the
+	     reduced-and-fixed-up index matches the index of the
+	     parameter pack.  */
+	  if (cp_tree_equal (TEMPLATE_PARM_ORIG_INDEX (index_pattern),
+			     index_parm_pack))
+	    return true;
+	}
     }
   return false;
 }
 
-/* Within the declaration of a template, return all levels of template
-   parameters that apply.  The template parameters are represented as
-   a TREE_VEC, in the form documented in cp-tree.h for template
-   arguments.  */
+/*  Transform a list of of template parameters into a list of
+    arguments, suitable to be passed to tsubst as its ARGS parameter.
+    The list of template parameters has the same format as the one
+    described in the comments of DECL_TEMPLATE_PARMS in cp-tree.h.  */
 
 static tree
-current_template_args (void)
+template_parms_to_args (tree parms)
 {
   tree header;
   tree args = NULL_TREE;
-  int length = TMPL_PARMS_DEPTH (current_template_parms);
+  int length = TMPL_PARMS_DEPTH (parms);
   int l = length;
 
   /* If there is only one level of template parameters, we do not
@@ -4108,7 +4567,7 @@ current_template_args (void)
   if (length > 1)
     args = make_tree_vec (length);
 
-  for (header = current_template_parms; header; header = TREE_CHAIN (header))
+  for (header = parms; header; header = TREE_CHAIN (header))
     {
       tree a = copy_node (TREE_VALUE (header));
       int i;
@@ -4145,6 +4604,17 @@ current_template_args (void)
   return args;
 }
 
+/* Within the declaration of a template, return all levels of template
+   parameters that apply.  The template parameters are represented as
+   a TREE_VEC, in the form documented in cp-tree.h for template
+   arguments.  */
+
+static tree
+current_template_args (void)
+{
+  return template_parms_to_args (current_template_parms);
+}
+
 /* Update the declared TYPE by doing any lookups which were thought to be
    dependent, but are not now that we know the SCOPE of the declarator.  */
 
@@ -4851,6 +5321,8 @@ push_template_decl_real (tree decl, bool is_friend)
 	       && TYPE_DECL_ALIAS_P (decl))
 	/* alias-declaration */
 	gcc_assert (!DECL_ARTIFICIAL (decl));
+      else if (is_friend && TREE_CODE (TREE_TYPE (decl)) == TYPENAME_TYPE)
+	/* OK */;
       else
 	{
 	  error ("template declaration of %q#D", decl);
@@ -4917,7 +5389,8 @@ push_template_decl_real (tree decl, bool is_friend)
   if (!ctx
       || TREE_CODE (ctx) == FUNCTION_DECL
       || (CLASS_TYPE_P (ctx) && TYPE_BEING_DEFINED (ctx))
-      || (is_friend && !DECL_TEMPLATE_INFO (decl)))
+      || (is_friend && (!DECL_LANG_SPECIFIC (decl)
+			|| !DECL_TEMPLATE_INFO (decl))))
     {
       if (DECL_LANG_SPECIFIC (decl)
 	  && DECL_TEMPLATE_INFO (decl)
@@ -5120,7 +5593,7 @@ template arguments to %qD do not match original template %qD",
     SET_TYPE_TEMPLATE_INFO (TREE_TYPE (tmpl), info);
   else
     {
-      if (primary && !DECL_LANG_SPECIFIC (decl))
+      if ((primary || is_friend) && !DECL_LANG_SPECIFIC (decl))
 	retrofit_lang_decl (decl);
       if (DECL_LANG_SPECIFIC (decl))
 	DECL_TEMPLATE_INFO (decl) = info;
@@ -6909,10 +7382,12 @@ coerce_template_parms (tree parms,
   return new_inner_args;
 }
 
-/* Returns 1 if template args OT and NT are equivalent.  */
+/* Returns 1 if template args OT and NT are equivalent.  STRICT
+   controls how the comparison is done, with the same semantics as
+   for the last parameter of comptypes.  */
 
 static int
-template_args_equal (tree ot, tree nt)
+template_args_equal_guided (tree ot, tree nt, int strict)
 {
   if (nt == ot)
     return 1;
@@ -6921,13 +7396,16 @@ template_args_equal (tree ot, tree nt)
 
   if (TREE_CODE (nt) == TREE_VEC)
     /* For member templates */
-    return TREE_CODE (ot) == TREE_VEC && comp_template_args (ot, nt);
+    return (TREE_CODE (ot) == TREE_VEC
+	    && comp_template_args_guided (ot, nt, NULL, NULL, strict));
   else if (PACK_EXPANSION_P (ot))
     return (PACK_EXPANSION_P (nt)
-	    && template_args_equal (PACK_EXPANSION_PATTERN (ot),
-				    PACK_EXPANSION_PATTERN (nt))
-	    && template_args_equal (PACK_EXPANSION_EXTRA_ARGS (ot),
-				    PACK_EXPANSION_EXTRA_ARGS (nt)));
+	    && template_args_equal_guided (PACK_EXPANSION_PATTERN (ot),
+					   PACK_EXPANSION_PATTERN (nt),
+					   strict)
+	    && template_args_equal_guided (PACK_EXPANSION_EXTRA_ARGS (ot),
+					   PACK_EXPANSION_EXTRA_ARGS (nt),
+					   strict));
   else if (ARGUMENT_PACK_P (ot))
     {
       int i, len;
@@ -6942,8 +7420,9 @@ template_args_equal (tree ot, tree nt)
       if (TREE_VEC_LENGTH (npack) != len)
 	return 0;
       for (i = 0; i < len; ++i)
-	if (!template_args_equal (TREE_VEC_ELT (opack, i),
-				  TREE_VEC_ELT (npack, i)))
+	if (!template_args_equal_guided (TREE_VEC_ELT (opack, i),
+					 TREE_VEC_ELT (npack, i),
+					 strict))
 	  return 0;
       return 1;
     }
@@ -6957,23 +7436,32 @@ template_args_equal (tree ot, tree nt)
       ot = ARGUMENT_PACK_SELECT_FROM_PACK (ot);
       if (nt && TREE_CODE (nt) == ARGUMENT_PACK_SELECT)
 	nt = ARGUMENT_PACK_SELECT_FROM_PACK (nt);
-      return template_args_equal (ot, nt);
+      return template_args_equal_guided (ot, nt, strict);
     }
   else if (TYPE_P (nt))
-    return TYPE_P (ot) && same_type_p (ot, nt);
+    return TYPE_P (ot) && comptypes (ot, nt, strict);
   else if (TREE_CODE (ot) == TREE_VEC || TYPE_P (ot))
     return 0;
   else
     return cp_tree_equal (ot, nt);
 }
 
+/* Returns 1 if template args OT and NT are equivalent.  */
+
+static int
+template_args_equal (tree ot, tree nt)
+{
+  return template_args_equal_guided (ot, nt, COMPARE_STRICT);
+}
+
 /* Returns 1 iff the OLDARGS and NEWARGS are in fact identical sets of
    template arguments.  Returns 0 otherwise, and updates OLDARG_PTR and
    NEWARG_PTR with the offending arguments if they are non-NULL.  */
 
-static int
-comp_template_args_with_info (tree oldargs, tree newargs,
-			      tree *oldarg_ptr, tree *newarg_ptr)
+int
+comp_template_args_guided (tree oldargs, tree newargs,
+			   tree *oldarg_ptr, tree *newarg_ptr,
+			   int strict)
 {
   int i;
 
@@ -6991,7 +7479,7 @@ comp_template_args_with_info (tree oldargs, tree newargs,
       tree nt = TREE_VEC_ELT (newargs, i);
       tree ot = TREE_VEC_ELT (oldargs, i);
 
-      if (! template_args_equal (ot, nt))
+      if (! template_args_equal_guided (ot, nt, strict))
 	{
 	  if (oldarg_ptr != NULL)
 	    *oldarg_ptr = ot;
@@ -7009,7 +7497,8 @@ comp_template_args_with_info (tree oldargs, tree newargs,
 int
 comp_template_args (tree oldargs, tree newargs)
 {
-  return comp_template_args_with_info (oldargs, newargs, NULL, NULL);
+  return comp_template_args_guided (oldargs, newargs,
+				    NULL, NULL, COMPARE_STRICT);
 }
 
 static void
@@ -9362,7 +9851,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
 	  return result;
 	}
 
-      if (arg_from_parm_pack_p (arg_pack, parm_pack))
+      if (arg_from_parm_pack_p (arg_pack, parm_pack, t))
 	/* The argument pack that the parameter maps to is just an
 	   expansion of the parameter itself, such as one would find
 	   in the implicit typedef of a class inside the class itself.
@@ -9716,7 +10205,14 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl)
    PARMS, then the result will contain n levels of PARMS.  For
    example, if PARMS is `template <class T> template <class U>
    template <T*, U, class V>' and ARGS is {{int}, {double}} then the
-   result will be `template <int*, double, class V>'.  */
+   result will be `template <int*, double, class V>'.
+
+   If the depth of ARGS is less than the depth of PARMS, it most
+   probably means we are looking at the partial instantiation of a
+   member template.  This implies that the resulting set of template
+   parms is going to be level-reduced.  In that case, this function
+   does the proper type fixing-up of the reduced template
+   parameters.  */
 
 static tree
 tsubst_template_parms (tree parms, tree args, tsubst_flags_t complain)
@@ -9724,6 +10220,9 @@ tsubst_template_parms (tree parms, tree args, tsubst_flags_t complain)
   tree r = NULL_TREE;
   tree* new_parms;
 
+  if (parms == NULL_TREE || parms == error_mark_node)
+    return parms;
+
   /* When substituting into a template, we must set
      PROCESSING_TEMPLATE_DECL as the template parameters may be
      dependent if they are based on one-another, and the dependency
@@ -9761,6 +10260,7 @@ tsubst_template_parms (tree parms, tree args, tsubst_flags_t complain)
 		   new_vec, NULL_TREE);
     }
 
+  fixup_template_parms (r);
   --processing_template_decl;
 
   return r;
@@ -9829,6 +10329,12 @@ tsubst_aggr_type (tree t,
 	  int saved_unevaluated_operand;
 	  int saved_inhibit_evaluation_warnings;
 
+	  /* If T is a member template being partially instantiated,
+	     fixup its template parameters that are to be
+	     level-reduced.  */
+	  tsubst_template_parms (DECL_TEMPLATE_PARMS (TYPE_TI_TEMPLATE (t)),
+				 args, complain);
+
 	  /* In "sizeof(X<I>)" we need to evaluate "I".  */
 	  saved_unevaluated_operand = cp_unevaluated_operand;
 	  cp_unevaluated_operand = 0;
@@ -9998,6 +10504,15 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	tree spec;
 	tree tmpl_args;
 	tree full_args;
+	tree fixedup_parms;
+
+	/* If T is a member template being partially instantiated,
+	   fixup its template parameters that are to be
+	   level-reduced.  */
+	++processing_template_decl;
+	fixedup_parms = tsubst_template_parms (DECL_TEMPLATE_PARMS (t),
+					       args, complain);
+	--processing_template_decl;
 
 	if (DECL_TEMPLATE_TEMPLATE_PARM_P (t))
 	  {
@@ -10073,6 +10588,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 
 	    TREE_TYPE (r) = new_type;
 	    CLASSTYPE_TI_TEMPLATE (new_type) = r;
+	    DECL_TEMPLATE_PARMS (r) = fixedup_parms;
 	    DECL_TEMPLATE_RESULT (r) = TYPE_MAIN_DECL (new_type);
 	    DECL_TI_ARGS (r) = CLASSTYPE_TI_ARGS (new_type);
 	    DECL_CONTEXT (r) = TYPE_CONTEXT (new_type);
@@ -10088,6 +10604,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 
 	    DECL_TEMPLATE_RESULT (r) = new_decl;
 	    DECL_TI_TEMPLATE (new_decl) = r;
+	    DECL_TEMPLATE_PARMS (r) = fixedup_parms;
 	    TREE_TYPE (r) = TREE_TYPE (new_decl);
 	    DECL_TI_ARGS (r) = DECL_TI_ARGS (new_decl);
 	    DECL_CONTEXT (r) = DECL_CONTEXT (new_decl);
@@ -10097,13 +10614,6 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	DECL_TEMPLATE_INSTANTIATIONS (r) = NULL_TREE;
 	DECL_TEMPLATE_SPECIALIZATIONS (r) = NULL_TREE;
 
-	/* The template parameters for this new template are all the
-	   template parameters for the old template, except the
-	   outermost level of parameters.  */
-	DECL_TEMPLATE_PARMS (r)
-	  = tsubst_template_parms (DECL_TEMPLATE_PARMS (t), args,
-				   complain);
-
 	if (PRIMARY_TEMPLATE_P (t))
 	  DECL_PRIMARY_TEMPLATE (r) = r;
 
@@ -11642,11 +12152,21 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 
     case TYPENAME_TYPE:
       {
-	tree ctx = tsubst_aggr_type (TYPE_CONTEXT (t), args, complain,
-				     in_decl, /*entering_scope=*/1);
-	tree f = tsubst_copy (TYPENAME_TYPE_FULLNAME (t), args,
-			      complain, in_decl);
-
+	tree ctx, f;
+	tree tinfo = get_template_info (t);
+
+	if (tinfo != NULL_TREE)
+	  /* prepare possible partial instantiation of member
+	     template by fixing-up template parms which level are
+	     going to be reduced by the partial instantiation.  */
+	  tsubst_template_parms (DECL_TEMPLATE_PARMS (TI_TEMPLATE (tinfo)),
+				 args, tf_none);
+
+	ctx = tsubst_aggr_type (TYPE_CONTEXT (t), args, complain,
+				in_decl, /*entering_scope=*/1);
+	f = tsubst_copy (TYPENAME_TYPE_FULLNAME (t), args,
+			 complain, in_decl);
+	
 	if (ctx == error_mark_node || f == error_mark_node)
 	  return error_mark_node;
 
@@ -11711,16 +12231,19 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 
     case UNBOUND_CLASS_TEMPLATE:
       {
+	/* If T is to be eventually replaced with a member template
+	   being partially instantiated, fixup its template parmeters
+	   that are to be level-reduced, upfront.  */
+	tree parm_list =
+	  tsubst_template_parms (DECL_TEMPLATE_PARMS (TYPE_NAME (t)),
+				 args, complain);
 	tree ctx = tsubst_aggr_type (TYPE_CONTEXT (t), args, complain,
 				     in_decl, /*entering_scope=*/1);
 	tree name = TYPE_IDENTIFIER (t);
-	tree parm_list = DECL_TEMPLATE_PARMS (TYPE_NAME (t));
 
 	if (ctx == error_mark_node || name == error_mark_node)
 	  return error_mark_node;
 
-	if (parm_list)
-	  parm_list = tsubst_template_parms (parm_list, args, complain);
 	return make_unbound_class_template (ctx, name, parm_list, complain);
       }
 
@@ -15878,22 +16401,43 @@ check_cv_quals_for_unify (int strict, tree arg, tree parm)
   return 1;
 }
 
-/* Determines the LEVEL and INDEX for the template parameter PARM.  */
+/* Determines the LEVEL and INDEX for the template parameter PARM.
+   PARM can be either a DECL for a template parameter, or a the type
+   of a template type parameter, or a TEMPLATE_PARM_INDEX node.
+
+   If the caller wants to get only the LEVEL or only the INDEX, it can
+   set the other argument to NULL.  */
+
 void 
 template_parm_level_and_index (tree parm, int* level, int* index)
 {
+  int l = -1, i = -1;
+
+  if (TREE_CODE (parm) == TYPE_DECL
+      || TREE_CODE (parm) == TEMPLATE_DECL)
+    parm = TREE_TYPE (parm);
+  else if (TREE_CODE (parm) == PARM_DECL)
+    parm = DECL_INITIAL (parm);
+
   if (TREE_CODE (parm) == TEMPLATE_TYPE_PARM
       || TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM
       || TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
     {
-      *index = TEMPLATE_TYPE_IDX (parm);
-      *level = TEMPLATE_TYPE_LEVEL (parm);
+      i = TEMPLATE_TYPE_IDX (parm);
+      l = TEMPLATE_TYPE_LEVEL (parm);
     }
   else
     {
-      *index = TEMPLATE_PARM_IDX (parm);
-      *level = TEMPLATE_PARM_LEVEL (parm);
+      i = TEMPLATE_PARM_IDX (parm);
+      l = TEMPLATE_PARM_LEVEL (parm);
     }
+
+  gcc_assert (l > 0 && i >= 0);
+
+  if (level != NULL)
+    *level = l;
+  if (index != NULL)
+    *index = i;
 }
 
 #define RECUR_AND_CHECK_FAILURE(TP, TA, P, A, S, EP)			\
@@ -16077,8 +16621,9 @@ unify_pack_expansion (tree tparms, tree targs, tree packed_parms,
 	  tree bad_old_arg = NULL_TREE, bad_new_arg = NULL_TREE;
 	  tree old_args = ARGUMENT_PACK_ARGS (old_pack);
 
-	  if (!comp_template_args_with_info (old_args, new_args,
-					     &bad_old_arg, &bad_new_arg))
+	  if (!comp_template_args_guided (old_args, new_args,
+					  &bad_old_arg, &bad_new_arg,
+					  COMPARE_STRICT))
 	    /* Inconsistent unification of this parameter pack.  */
 	    return unify_parameter_pack_inconsistent (explain_p,
 						      bad_old_arg,
@@ -19066,15 +19611,13 @@ get_mostly_instantiated_function_type (tree decl)
       int i;
       tree partial_args;
 
-      /* Replace the innermost level of the TARGS with NULL_TREEs to
-	 let tsubst know not to substitute for those parameters.  */
-      partial_args = make_tree_vec (TREE_VEC_LENGTH (targs));
+      /* Copy all but the innermost level of the TARGS to let tsubst
+	 below know not to substitute for those parameters and
+	 properly perform the partial substituting of fn_type.  */
+      partial_args = make_tree_vec (TREE_VEC_LENGTH (targs) - 1);
       for (i = 1; i < TMPL_ARGS_DEPTH (targs); ++i)
 	SET_TMPL_ARGS_LEVEL (partial_args, i,
 			     TMPL_ARGS_LEVEL (targs, i));
-      SET_TMPL_ARGS_LEVEL (partial_args,
-			   TMPL_ARGS_DEPTH (targs),
-			   make_tree_vec (DECL_NTPARMS (tmpl)));
 
       /* Make sure that we can see identifiers, and compute access
 	 correctly.  */
@@ -19090,7 +19633,6 @@ get_mostly_instantiated_function_type (tree decl)
 	 innermost set of parameters.  This step is important if the
 	 innermost set of template parameters contains value
 	 parameters whose types depend on outer template parameters.  */
-      TREE_VEC_LENGTH (partial_args)--;
       tparms = tsubst_template_parms (tparms, partial_args, tf_error);
 
       pop_access_scope (decl);
@@ -20214,7 +20756,7 @@ make_auto (void)
 			       TYPE_DECL, get_identifier ("auto"), au);
   TYPE_STUB_DECL (au) = TYPE_NAME (au);
   TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index
-    (0, processing_template_decl + 1, processing_template_decl + 1,
+    (0, processing_template_decl + 1, NULL_TREE,
      0, TYPE_NAME (au), NULL_TREE);
   TYPE_CANONICAL (au) = canonical_type_parameter (au);
   DECL_ARTIFICIAL (TYPE_NAME (au)) = 1;
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index b80b52a..04bdedd 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2178,7 +2178,7 @@ decl_anon_ns_mem_p (const_tree decl)
    CALL_EXPRS.  Return whether they are equivalent.  */
 
 static bool
-called_fns_equal (tree t1, tree t2)
+called_fns_equal (tree t1, tree t2, int strict)
 {
   /* Core 1321: dependent names are equivalent even if the overload sets
      are different.  But do compare explicit template arguments.  */
@@ -2195,17 +2195,21 @@ called_fns_equal (tree t1, tree t2)
 	targs1 = TREE_OPERAND (t1, 1);
       if (TREE_CODE (t2) == TEMPLATE_ID_EXPR)
 	targs2 = TREE_OPERAND (t2, 1);
-      return cp_tree_equal (targs1, targs2);
+      return compare_trees (targs1, targs2, strict);
     }
   else
     return cp_tree_equal (t1, t2);
 }
 
 /* Return truthvalue of whether T1 is the same tree structure as T2.
-   Return 1 if they are the same. Return 0 if they are different.  */
+   STRICT controls how the comparison is done, with the same semantics
+   as the for the last parameter of comptypes.  Please make sure that
+   any type or tree comparison function used in this function is a
+   variant that takes this STRICT parameter.  Return 1 if they are the
+   same. Return 0 if they are different.  */
 
 bool
-cp_tree_equal (tree t1, tree t2)
+compare_trees (tree t1, tree t2, int strict)
 {
   enum tree_code code1, code2;
 
@@ -2251,14 +2255,14 @@ cp_tree_equal (tree t1, tree t2)
 				     TREE_FIXED_CST (t2));
 
     case COMPLEX_CST:
-      return cp_tree_equal (TREE_REALPART (t1), TREE_REALPART (t2))
-	&& cp_tree_equal (TREE_IMAGPART (t1), TREE_IMAGPART (t2));
+      return compare_trees (TREE_REALPART (t1), TREE_REALPART (t2), strict)
+	&& compare_trees (TREE_IMAGPART (t1), TREE_IMAGPART (t2), strict);
 
     case CONSTRUCTOR:
       /* We need to do this when determining whether or not two
 	 non-type pointer to member function template arguments
 	 are the same.  */
-      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))
+      if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict)
 	  || CONSTRUCTOR_NELTS (t1) != CONSTRUCTOR_NELTS (t2))
 	return false;
       {
@@ -2267,35 +2271,35 @@ cp_tree_equal (tree t1, tree t2)
 	FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t1), i, field, value)
 	  {
 	    constructor_elt *elt2 = CONSTRUCTOR_ELT (t2, i);
-	    if (!cp_tree_equal (field, elt2->index)
-		|| !cp_tree_equal (value, elt2->value))
+	    if (!compare_trees (field, elt2->index, strict)
+		|| !compare_trees (value, elt2->value, strict))
 	      return false;
 	  }
       }
       return true;
 
     case TREE_LIST:
-      if (!cp_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2)))
+      if (!compare_trees (TREE_PURPOSE (t1), TREE_PURPOSE (t2), strict))
 	return false;
-      if (!cp_tree_equal (TREE_VALUE (t1), TREE_VALUE (t2)))
+      if (!compare_trees (TREE_VALUE (t1), TREE_VALUE (t2), strict))
 	return false;
-      return cp_tree_equal (TREE_CHAIN (t1), TREE_CHAIN (t2));
+      return compare_trees (TREE_CHAIN (t1), TREE_CHAIN (t2), strict);
 
     case SAVE_EXPR:
-      return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+      return compare_trees (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0), strict);
 
     case CALL_EXPR:
       {
 	tree arg1, arg2;
 	call_expr_arg_iterator iter1, iter2;
-	if (!called_fns_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2)))
+	if (!called_fns_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2), strict))
 	  return false;
 	for (arg1 = first_call_expr_arg (t1, &iter1),
 	       arg2 = first_call_expr_arg (t2, &iter2);
 	     arg1 && arg2;
 	     arg1 = next_call_expr_arg (&iter1),
 	       arg2 = next_call_expr_arg (&iter2))
-	  if (!cp_tree_equal (arg1, arg2))
+	  if (!compare_trees (arg1, arg2, strict))
 	    return false;
 	if (arg1 || arg2)
 	  return false;
@@ -2317,28 +2321,30 @@ cp_tree_equal (tree t1, tree t2)
 	else if (TREE_CODE (o2) == VAR_DECL && DECL_NAME (o2) == NULL_TREE
 		 && !DECL_RTL_SET_P (o2))
 	  /*Nop*/;
-	else if (!cp_tree_equal (o1, o2))
+	else if (!compare_trees (o1, o2, strict))
 	  return false;
 
-	return cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
+	return compare_trees (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1),
+			      strict);
       }
 
     case WITH_CLEANUP_EXPR:
-      if (!cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)))
+      if (!compare_trees (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0), strict))
 	return false;
-      return cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t1, 1));
+      return compare_trees (TREE_OPERAND (t1, 1), TREE_OPERAND (t1, 1), strict);
 
     case COMPONENT_REF:
       if (TREE_OPERAND (t1, 1) != TREE_OPERAND (t2, 1))
 	return false;
-      return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+      return compare_trees (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0),
+			    strict);
 
     case PARM_DECL:
       /* For comparing uses of parameters in late-specified return types
 	 with an out-of-class definition of the function, but can also come
 	 up for expressions that involve 'this' in a member function
 	 template.  */
-      if (same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+      if (comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	{
 	  if (DECL_ARTIFICIAL (t1) ^ DECL_ARTIFICIAL (t2))
 	    return false;
@@ -2361,19 +2367,18 @@ cp_tree_equal (tree t1, tree t2)
       return (BASELINK_BINFO (t1) == BASELINK_BINFO (t2)
 	      && BASELINK_ACCESS_BINFO (t1) == BASELINK_ACCESS_BINFO (t2)
 	      && BASELINK_QUALIFIED_P (t1) == BASELINK_QUALIFIED_P (t2)
-	      && cp_tree_equal (BASELINK_FUNCTIONS (t1),
-				BASELINK_FUNCTIONS (t2)));
+	      && compare_trees (BASELINK_FUNCTIONS (t1),
+				BASELINK_FUNCTIONS (t2), strict));
 
     case TEMPLATE_PARM_INDEX:
-      if (TEMPLATE_PARM_NUM_SIBLINGS (t1)
-	  != TEMPLATE_PARM_NUM_SIBLINGS (t2))
+      if (!(TEMPLATE_PARM_IDX (t1) == TEMPLATE_PARM_IDX (t2)
+	    && TEMPLATE_PARM_LEVEL (t1) == TEMPLATE_PARM_LEVEL (t2)
+	    && (TEMPLATE_PARM_PARAMETER_PACK (t1)
+		== TEMPLATE_PARM_PARAMETER_PACK (t2))
+	    && comptypes (TREE_TYPE (TEMPLATE_PARM_DECL (t1)),
+			  TREE_TYPE (TEMPLATE_PARM_DECL (t2)), strict)))
 	return false;
-      return (TEMPLATE_PARM_IDX (t1) == TEMPLATE_PARM_IDX (t2)
-	      && TEMPLATE_PARM_LEVEL (t1) == TEMPLATE_PARM_LEVEL (t2)
-	      && (TEMPLATE_PARM_PARAMETER_PACK (t1)
-		  == TEMPLATE_PARM_PARAMETER_PACK (t2))
-	      && same_type_p (TREE_TYPE (TEMPLATE_PARM_DECL (t1)),
-			      TREE_TYPE (TEMPLATE_PARM_DECL (t2))));
+      return comp_template_parms_siblings (t1, t2, strict);
 
     case TEMPLATE_ID_EXPR:
       return (cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0))
@@ -2385,8 +2390,9 @@ cp_tree_equal (tree t1, tree t2)
 	if (TREE_VEC_LENGTH (t1) != TREE_VEC_LENGTH (t2))
 	  return false;
 	for (ix = TREE_VEC_LENGTH (t1); ix--;)
-	  if (!cp_tree_equal (TREE_VEC_ELT (t1, ix),
-			      TREE_VEC_ELT (t2, ix)))
+	  if (!compare_trees (TREE_VEC_ELT (t1, ix),
+			      TREE_VEC_ELT (t2, ix),
+			      strict))
 	    return false;
 	return true;
       }
@@ -2400,16 +2406,17 @@ cp_tree_equal (tree t1, tree t2)
 	if (TREE_CODE (o1) != TREE_CODE (o2))
 	  return false;
 	if (TYPE_P (o1))
-	  return same_type_p (o1, o2);
+	  return comptypes (o1, o2, strict);
 	else
-	  return cp_tree_equal (o1, o2);
+	  return compare_trees (o1, o2, strict);
       }
 
     case MODOP_EXPR:
       {
 	tree t1_op1, t2_op1;
 
-	if (!cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)))
+	if (!compare_trees (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0),
+			    strict))
 	  return false;
 
 	t1_op1 = TREE_OPERAND (t1, 1);
@@ -2417,7 +2424,7 @@ cp_tree_equal (tree t1, tree t2)
 	if (TREE_CODE (t1_op1) != TREE_CODE (t2_op1))
 	  return false;
 
-	return cp_tree_equal (TREE_OPERAND (t1, 2), TREE_OPERAND (t2, 2));
+	return compare_trees (TREE_OPERAND (t1, 2), TREE_OPERAND (t2, 2), strict);
       }
 
     case PTRMEM_CST:
@@ -2426,18 +2433,18 @@ cp_tree_equal (tree t1, tree t2)
       if (PTRMEM_CST_MEMBER (t1) != PTRMEM_CST_MEMBER (t2))
 	return false;
 
-      return same_type_p (PTRMEM_CST_CLASS (t1), PTRMEM_CST_CLASS (t2));
+      return comptypes (PTRMEM_CST_CLASS (t1), PTRMEM_CST_CLASS (t2), strict);
 
     case OVERLOAD:
       if (OVL_FUNCTION (t1) != OVL_FUNCTION (t2))
 	return false;
-      return cp_tree_equal (OVL_CHAIN (t1), OVL_CHAIN (t2));
+      return compare_trees (OVL_CHAIN (t1), OVL_CHAIN (t2), strict);
 
     case TRAIT_EXPR:
       if (TRAIT_EXPR_KIND (t1) != TRAIT_EXPR_KIND (t2))
 	return false;
-      return same_type_p (TRAIT_EXPR_TYPE1 (t1), TRAIT_EXPR_TYPE1 (t2))
-	&& same_type_p (TRAIT_EXPR_TYPE2 (t1), TRAIT_EXPR_TYPE2 (t2));
+      return comptypes (TRAIT_EXPR_TYPE1 (t1), TRAIT_EXPR_TYPE1 (t2), strict)
+	&& comptypes (TRAIT_EXPR_TYPE2 (t1), TRAIT_EXPR_TYPE2 (t2), strict);
 
     case CAST_EXPR:
     case STATIC_CAST_EXPR:
@@ -2446,16 +2453,18 @@ cp_tree_equal (tree t1, tree t2)
     case DYNAMIC_CAST_EXPR:
     case IMPLICIT_CONV_EXPR:
     case NEW_EXPR:
-      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+      if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	return false;
       /* Now compare operands as usual.  */
       break;
 
     case DEFERRED_NOEXCEPT:
-      return (cp_tree_equal (DEFERRED_NOEXCEPT_PATTERN (t1),
-			     DEFERRED_NOEXCEPT_PATTERN (t2))
-	      && comp_template_args (DEFERRED_NOEXCEPT_ARGS (t1),
-				     DEFERRED_NOEXCEPT_ARGS (t2)));
+      return (compare_trees (DEFERRED_NOEXCEPT_PATTERN (t1),
+			     DEFERRED_NOEXCEPT_PATTERN (t2),
+			     strict)
+	      && comp_template_args_guided (DEFERRED_NOEXCEPT_ARGS (t1),
+					    DEFERRED_NOEXCEPT_ARGS (t2),
+					    NULL, NULL, strict));
       break;
 
     default:
@@ -2480,14 +2489,15 @@ cp_tree_equal (tree t1, tree t2)
 	  return false;
 
 	for (i = 0; i < n; ++i)
-	  if (!cp_tree_equal (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i)))
+	  if (!compare_trees (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i),
+			      strict))
 	    return false;
 
 	return true;
       }
 
     case tcc_type:
-      return same_type_p (t1, t2);
+      return comptypes (t1, t2, strict);
     default:
       gcc_unreachable ();
     }
@@ -2495,6 +2505,15 @@ cp_tree_equal (tree t1, tree t2)
   return false;
 }
 
+/* Return truthvalue of whether T1 is the same tree structure as T2.
+   Return 1 if they are the same. Return 0 if they are different.  */
+
+bool
+cp_tree_equal (tree t1, tree t2)
+{
+  return compare_trees (t1, t2, COMPARE_STRICT);
+}
+
 /* The type of ARG when used as an lvalue.  */
 
 tree
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 643454c..9ca8e5e 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -53,6 +53,7 @@ static tree rationalize_conditional_expr (enum tree_code, tree,
 static int comp_ptr_ttypes_real (tree, tree, int);
 static bool comp_except_types (tree, tree, bool);
 static bool comp_array_types (const_tree, const_tree, bool);
+static bool compparms_guided (const_tree, const_tree, int);
 static tree pointer_diff (tree, tree, tree);
 static tree get_delta_difference (tree, tree, bool, bool, tsubst_flags_t);
 static void casts_away_constness_r (tree *, tree *);
@@ -1119,13 +1120,56 @@ comp_array_types (const_tree t1, const_tree t2, bool allow_redeclaration)
   return true;
 }
 
+/* Return true iff the two instances of TEMPLATE_PARM_INDEX are
+   equivalent.  STRICT controls how the comparison is done, with the
+   same semantics as the last parameter of comptypes.  */
+
+bool
+comp_template_parms_siblings (tree index1,
+			      tree index2,
+			      int strict)
+{
+  tree siblings1, siblings2;
+
+  gcc_assert (index1 != NULL_TREE 
+	      && index2 != NULL_TREE
+	      && TREE_CODE (index1) == TREE_CODE (index2)
+	      && TREE_CODE (index1) == TEMPLATE_PARM_INDEX);
+
+  if (strict & COMPARE_NO_SIBLINGS)
+    return true;
+
+  siblings1 = TEMPLATE_PARM_SIBLINGS (index1);
+  siblings2 = TEMPLATE_PARM_SIBLINGS (index2);
+    
+  if (siblings1 == siblings2)
+    return true;
+
+  /* If T1 and T2 belong to different template parm lists let's assume
+     they are different.  */
+
+  if ((siblings1 != NULL_TREE) != (siblings2 != NULL_TREE))
+    return false;
+
+  if (TREE_VEC_LENGTH (siblings1) != TREE_VEC_LENGTH (siblings2))
+    return false;
+
+  if (!comp_template_parm_levels (siblings1, siblings2,
+				  strict | COMPARE_NO_SIBLINGS))
+    return false;
+
+  return true;
+}
+
 /* Compare the relative position of T1 and T2 into their respective
    template parameter list.
-   T1 and T2 must be template parameter types.
+   T1 and T2 must be template parameter types.  STRICT controls how
+   the comparison is done, with the same semantics as the for the last
+   parameter of comptypes.
    Return TRUE if T1 and T2 have the same position, FALSE otherwise.  */
 
 static bool
-comp_template_parms_position (tree t1, tree t2)
+comp_template_parms_position (tree t1, tree t2, int strict)
 {
   tree index1, index2;
   gcc_assert (t1 && t2
@@ -1137,19 +1181,16 @@ comp_template_parms_position (tree t1, tree t2)
   index1 = TEMPLATE_TYPE_PARM_INDEX (TYPE_MAIN_VARIANT (t1));
   index2 = TEMPLATE_TYPE_PARM_INDEX (TYPE_MAIN_VARIANT (t2));
 
-  /* If T1 and T2 belong to template parm lists of different size,
-     let's assume they are different.  */
-  if (TEMPLATE_PARM_NUM_SIBLINGS (index1)
-      != TEMPLATE_PARM_NUM_SIBLINGS (index2))
-    return false;
-
-  /* Then compare their relative position.  */
+  /* Compare their relative position.  */
   if (TEMPLATE_PARM_IDX (index1) != TEMPLATE_PARM_IDX (index2)
       || TEMPLATE_PARM_LEVEL (index1) != TEMPLATE_PARM_LEVEL (index2)
       || (TEMPLATE_PARM_PARAMETER_PACK (index1)
 	  != TEMPLATE_PARM_PARAMETER_PACK (index2)))
     return false;
 
+  if (!comp_template_parms_siblings (index1, index2, strict))
+    return false;
+
   return true;
 }
 
@@ -1233,11 +1274,12 @@ structural_comptypes (tree t1, tree t2, int strict)
 
     case TEMPLATE_TEMPLATE_PARM:
     case BOUND_TEMPLATE_TEMPLATE_PARM:
-      if (!comp_template_parms_position (t1, t2))
+      if (!comp_template_parms_position (t1, t2, strict))
 	return false;
-      if (!comp_template_parms
+      if (!comp_template_parms_guided
 	  (DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t1)),
-	   DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t2))))
+	   DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t2)),
+	   strict))
 	return false;
       if (TREE_CODE (t1) == TEMPLATE_TEMPLATE_PARM)
 	break;
@@ -1250,7 +1292,9 @@ structural_comptypes (tree t1, tree t2, int strict)
       if (TYPE_TEMPLATE_INFO (t1) && TYPE_TEMPLATE_INFO (t2)
 	  && (TYPE_TI_TEMPLATE (t1) == TYPE_TI_TEMPLATE (t2)
 	      || TREE_CODE (t1) == BOUND_TEMPLATE_TEMPLATE_PARM)
-	  && comp_template_args (TYPE_TI_ARGS (t1), TYPE_TI_ARGS (t2)))
+	  && comp_template_args_guided (TYPE_TI_ARGS (t1),
+					TYPE_TI_ARGS (t2),
+					NULL, NULL, strict))
 	break;
 
       if ((strict & COMPARE_BASE) && DERIVED_FROM_P (t1, t2))
@@ -1264,7 +1308,7 @@ structural_comptypes (tree t1, tree t2, int strict)
       if (!comptypes (TYPE_OFFSET_BASETYPE (t1), TYPE_OFFSET_BASETYPE (t2),
 		      strict & ~COMPARE_REDECLARATION))
 	return false;
-      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+      if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	return false;
       break;
 
@@ -1276,15 +1320,17 @@ structural_comptypes (tree t1, tree t2, int strict)
     case POINTER_TYPE:
       if (TYPE_MODE (t1) != TYPE_MODE (t2)
 	  || TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2)
-	  || !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+	  || !comptypes (TREE_TYPE (t1), TREE_TYPE (t2),
+			 strict & ~COMPARE_REDECLARATION))
 	return false;
       break;
 
     case METHOD_TYPE:
     case FUNCTION_TYPE:
-      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+      if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	return false;
-      if (!compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2)))
+      if (!compparms_guided (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2),
+			   strict))
 	return false;
       break;
 
@@ -1297,43 +1343,48 @@ structural_comptypes (tree t1, tree t2, int strict)
     case TEMPLATE_TYPE_PARM:
       /* If T1 and T2 don't have the same relative position in their
 	 template parameters set, they can't be equal.  */
-      if (!comp_template_parms_position (t1, t2))
+      if (!comp_template_parms_position (t1, t2, strict))
 	return false;
       break;
 
     case TYPENAME_TYPE:
-      if (!cp_tree_equal (TYPENAME_TYPE_FULLNAME (t1),
-			  TYPENAME_TYPE_FULLNAME (t2)))
+      if (!compare_trees (TYPENAME_TYPE_FULLNAME (t1),
+			  TYPENAME_TYPE_FULLNAME (t2),
+			  strict))
 	return false;
       /* Qualifiers don't matter on scopes.  */
-      if (!same_type_ignoring_top_level_qualifiers_p (TYPE_CONTEXT (t1),
-						      TYPE_CONTEXT (t2)))
+      if (!same_type_ignoring_top_level_qualifiers_guided_p (TYPE_CONTEXT (t1),
+							     TYPE_CONTEXT (t2),
+							     strict))
 	return false;
       break;
 
     case UNBOUND_CLASS_TEMPLATE:
-      if (!cp_tree_equal (TYPE_IDENTIFIER (t1), TYPE_IDENTIFIER (t2)))
+      if (!compare_trees (TYPE_IDENTIFIER (t1), TYPE_IDENTIFIER (t2),
+			  strict))
 	return false;
-      if (!same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2)))
+      if (!comptypes (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2), strict))
 	return false;
       break;
 
     case COMPLEX_TYPE:
-      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+      if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	return false;
       break;
 
     case VECTOR_TYPE:
       if (TYPE_VECTOR_SUBPARTS (t1) != TYPE_VECTOR_SUBPARTS (t2)
-	  || !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+	  || !comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
 	return false;
       break;
 
     case TYPE_PACK_EXPANSION:
-      return (same_type_p (PACK_EXPANSION_PATTERN (t1),
-			   PACK_EXPANSION_PATTERN (t2))
-	      && comp_template_args (PACK_EXPANSION_EXTRA_ARGS (t1),
-				     PACK_EXPANSION_EXTRA_ARGS (t2)));
+	return (comptypes (PACK_EXPANSION_PATTERN (t1), 
+			   PACK_EXPANSION_PATTERN (t2),
+			   strict)
+		&& comp_template_args_guided (PACK_EXPANSION_EXTRA_ARGS (t1),
+					      PACK_EXPANSION_EXTRA_ARGS (t2),
+					      NULL, NULL, strict));
 
     case DECLTYPE_TYPE:
       if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t1)
@@ -1342,14 +1393,16 @@ structural_comptypes (tree t1, tree t2, int strict)
 	      != DECLTYPE_FOR_LAMBDA_CAPTURE (t2))
 	  || (DECLTYPE_FOR_LAMBDA_PROXY (t1)
 	      != DECLTYPE_FOR_LAMBDA_PROXY (t2))
-          || !cp_tree_equal (DECLTYPE_TYPE_EXPR (t1), 
-                             DECLTYPE_TYPE_EXPR (t2)))
+          || !compare_trees (DECLTYPE_TYPE_EXPR (t1), 
+                             DECLTYPE_TYPE_EXPR (t2),
+			     strict))
         return false;
       break;
 
     case UNDERLYING_TYPE:
-      return same_type_p (UNDERLYING_TYPE_TYPE (t1), 
-			  UNDERLYING_TYPE_TYPE (t2));
+      return comptypes (UNDERLYING_TYPE_TYPE (t1), 
+			UNDERLYING_TYPE_TYPE (t2),
+			strict);
 
     default:
       return false;
@@ -1416,15 +1469,31 @@ comptypes (tree t1, tree t2, int strict)
 }
 
 /* Returns nonzero iff TYPE1 and TYPE2 are the same type, ignoring
-   top-level qualifiers.  */
+   top-level qualifiers.  STRICT controls how the type comparison is
+   done, with the same semantics as for the last parameter of
+   comptypes.  */
 
 bool
-same_type_ignoring_top_level_qualifiers_p (tree type1, tree type2)
+same_type_ignoring_top_level_qualifiers_guided_p (tree type1,
+						  tree type2,
+						  int strict)
 {
   if (type1 == error_mark_node || type2 == error_mark_node)
     return false;
 
-  return same_type_p (TYPE_MAIN_VARIANT (type1), TYPE_MAIN_VARIANT (type2));
+  return comptypes (TYPE_MAIN_VARIANT (type1),
+		    TYPE_MAIN_VARIANT (type2),
+		    strict);
+}
+
+/* Returns nonzero iff TYPE1 and TYPE2 are the same type, ignoring
+   top-level qualifiers.  */
+
+bool
+same_type_ignoring_top_level_qualifiers_p (tree type1, tree type2)
+{
+  return same_type_ignoring_top_level_qualifiers_guided_p (type1, type2,
+							   COMPARE_STRICT);
 }
 
 /* Returns 1 if TYPE1 is at least as qualified as TYPE2.  */
@@ -1479,10 +1548,10 @@ comp_cv_qual_signature (tree type1, tree type2)
 /* Return true if two parameter type lists PARMS1 and PARMS2 are
    equivalent in the sense that functions with those parameter types
    can have equivalent types.  The two lists must be equivalent,
-   element by element.  */
+   element by element.  STRICT controls how the comparison is done.  */
 
-bool
-compparms (const_tree parms1, const_tree parms2)
+static bool
+compparms_guided (const_tree parms1, const_tree parms2, int strict)
 {
   const_tree t1, t2;
 
@@ -1497,12 +1566,23 @@ compparms (const_tree parms1, const_tree parms2)
 	 they fail to match.  */
       if (!t1 || !t2)
 	return false;
-      if (!same_type_p (TREE_VALUE (t1), TREE_VALUE (t2)))
+      if (!comptypes (TREE_VALUE (t1), TREE_VALUE (t2), strict))
 	return false;
     }
   return true;
 }
 
+/* Return true if two parameter type lists PARMS1 and PARMS2 are
+   equivalent in the sense that functions with those parameter types
+   can have equivalent types.  The two lists must be equivalent,
+   element by element.  */
+
+bool
+compparms (const_tree parms1, const_tree parms2)
+{
+  return compparms_guided (parms1, parms2, COMPARE_STRICT);
+}
+
 \f
 /* Process a sizeof or alignof expression where the operand is a
    type.  */
diff --git a/gcc/testsuite/g++.dg/template/crash84.C b/gcc/testsuite/g++.dg/template/crash84.C
index c42f85c..69ee87c 100644
--- a/gcc/testsuite/g++.dg/template/crash84.C
+++ b/gcc/testsuite/g++.dg/template/crash84.C
@@ -4,8 +4,8 @@
 
 template<typename T> struct a
 {
-    template <template <typename> class C, typename X, C<X>* =0>
-    struct b // { dg-error "class C' is not a template|is not a valid type" }
+    template <template <typename> class C, typename X, C<X>* = 0>
+    struct b
     {
     };
 };
@@ -13,7 +13,5 @@ template<typename T> struct a
 void
 foo ()
 {
-    a<int> v; // { dg-message "required from here" }
+    a<int> v;
 }
-
-
diff --git a/gcc/testsuite/g++.dg/template/typedef39.C b/gcc/testsuite/g++.dg/template/typedef39.C
new file mode 100644
index 0000000..4ee23a6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef39.C
@@ -0,0 +1,16 @@
+// Origin PR c++/50852
+// { dg-do compile }
+
+template<int d> class A;
+template<class T> struct B {typedef int K;typedef int L;};
+template<class U,class V> struct C
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W;
+};
+template<class U,int d> struct D
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W; // { dg-error "not a member" }
+};
+template class D<B<A<1> >,3>;
diff --git a/gcc/testsuite/g++.dg/template/typedef40.C b/gcc/testsuite/g++.dg/template/typedef40.C
new file mode 100644
index 0000000..6cd9766
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef40.C
@@ -0,0 +1,22 @@
+// Origin PR c++/50852
+// { dg-do compile }
+
+template<int d> class A;
+
+template<class T> struct B {typedef int K;typedef int L;};
+template<class U, void(*)(U&), class V> struct C
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W;
+};
+template<class U, void(*)(U&), int d> struct D
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W; // { dg-error "not a member" }
+};
+
+struct S;
+
+void f(B<A<1> >&);
+
+template class D<B<A<1> >, &f, 3>;
diff --git a/gcc/testsuite/g++.dg/template/typedef41.C b/gcc/testsuite/g++.dg/template/typedef41.C
new file mode 100644
index 0000000..17d2feb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef41.C
@@ -0,0 +1,19 @@
+// Origin PR c++/50852
+// { dg-do compile }
+
+template<int d> class A;
+
+template<class T> struct B {typedef int K;typedef int L;};
+template<class U, typename U::K, class V> struct C
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W;
+};
+template<class U, typename U::K, int d> struct D
+{
+    typedef typename U::L X;
+    typedef A<X::a-1> W; // { dg-error "not a member" }
+};
+
+
+template class D<B<A<1> >, 0, 3>;
-- 
1.7.6.5


-- 
		Dodji

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] PR c++/50852 - Revisit dependant template parameter
  2012-03-13 21:33         ` Jason Merrill
  2012-03-25 18:12           ` Dodji Seketeli
@ 2012-03-28 15:02           ` Dodji Seketeli
  2012-03-28 15:26             ` Jason Merrill
  1 sibling, 1 reply; 18+ messages in thread
From: Dodji Seketeli @ 2012-03-28 15:02 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches

Jason Merrill <jason@redhat.com> writes:


>> +      /* This can happen for template parms of a template template
>> +        parameter, e.g:
>> +
>> +        template<template<class T, class U> class TT> struct S;
>> +
>> +        Consider the level of the parms of TT; T and U both have
>> +        level 2; TT has no template parm of level 1. So in this case
>> +        the first element of full_template_args is NULL_TREE. If we
>> +        leave it like this TMPL_ARG_DEPTH on args returns 1 instead
>> +        of 2. This will make tsubst wrongly consider that T and U
>> +        have level 1. Instead, let's create a dummy vector as the
>> +        first element of full_template_args so that TMPL_ARG_DEPTH
>> +        returns the correct depth for args.  */
>
> Hmm, it seems odd that the parms wouldn't have level 1.

Finally, thinking about this a little more, this situation does not seem
completely crazy to me.

For:

 template<class T, template<class U, T> class TT> struct S;

the parms of TT do have a level 1 that contains the parm T.  It seems to
me that we need T and U to have different levels here, so both cannot
have level 1.

>  I wonder if changing that would also avoid needing to use structural
> equality for template template parameters.

What do you mean exactly by "changing that"?  I am getting confused now.

-- 
		Dodji

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] PR c++/50852 - Revisit dependant template parameter
  2012-03-28 15:02           ` Dodji Seketeli
@ 2012-03-28 15:26             ` Jason Merrill
  2012-03-28 17:10               ` Dodji Seketeli
  0 siblings, 1 reply; 18+ messages in thread
From: Jason Merrill @ 2012-03-28 15:26 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: GCC Patches

On 03/28/2012 11:02 AM, Dodji Seketeli wrote:
> For:
>
>   template<class T, template<class U, T>  class TT>  struct S;
>
> the parms of TT do have a level 1 that contains the parm T.  It seems to
> me that we need T and U to have different levels here, so both cannot
> have level 1.

Why do we need them to have different levels?  They are parameters of 
different templates.

Jason

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] PR c++/50852 - Revisit dependant template parameter
  2012-03-28 15:26             ` Jason Merrill
@ 2012-03-28 17:10               ` Dodji Seketeli
  2012-03-28 20:38                 ` Jason Merrill
  0 siblings, 1 reply; 18+ messages in thread
From: Dodji Seketeli @ 2012-03-28 17:10 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches

Jason Merrill <jason@redhat.com> writes:

> On 03/28/2012 11:02 AM, Dodji Seketeli wrote:
>> For:
>>
>>   template<class T, template<class U, T>  class TT>  struct S;
>>
>> the parms of TT do have a level 1 that contains the parm T.  It seems to
>> me that we need T and U to have different levels here, so both cannot
>> have level 1.
>
> Why do we need them to have different levels?  They are parameters of
> different templates.

Then, if U and T have the same level, how do we represent the full set
of template parms up to U for instance? I mean if that TREE_LIST of
parms still has two entries - one for level 1 that contains T and one
for level N (which you say should be 1 as well) that contains U - would
the TREE_PURPOSEs of both entries have a 1 as their level number?

I agree there are parameters of different templates at play here, but it
seems like there are cases when we need to tie them together, like what
lookup_template_class_1 does when the relevant template is a template
template parameter.

What am I missing?

-- 
		Dodji

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] PR c++/50852 - Revisit dependant template parameter
  2012-03-28 17:10               ` Dodji Seketeli
@ 2012-03-28 20:38                 ` Jason Merrill
  0 siblings, 0 replies; 18+ messages in thread
From: Jason Merrill @ 2012-03-28 20:38 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: GCC Patches

On 03/28/2012 12:08 PM, Dodji Seketeli wrote:
>> On 03/28/2012 11:02 AM, Dodji Seketeli wrote:
>>>    template<class T, template<class U, T>   class TT>   struct S;
>
> Then, if U and T have the same level, how do we represent the full set
> of template parms up to U for instance? I mean if that TREE_LIST of
> parms still has two entries - one for level 1 that contains T and one
> for level N (which you say should be 1 as well) that contains U - would
> the TREE_PURPOSEs of both entries have a 1 as their level number?

Hmm, no, I guess you're right; T is an enclosing parameter of TT.  Never 
mind.

Jason

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] PR c++/50852 - loose template parameter comparison
  2011-11-17 21:56 [PATCH] PR c++/50852 - loose template parameter comparison Dodji Seketeli
  2012-01-17 19:03 ` Jason Merrill
@ 2012-04-12 21:08 ` Jason Merrill
  2012-07-05 18:11   ` Jason Merrill
  1 sibling, 1 reply; 18+ messages in thread
From: Jason Merrill @ 2012-04-12 21:08 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: GCC Patches

Sorry for the delay in getting back to you on this; I just keep thinking 
there has to be a better way to deal with this issue than this 
increasingly complex fixup machinery.

The basic problem we're dealing with is that two typedefs from different 
contexts are considered identical for the purpose of template argument 
comparison, and we are leaving them in non-type template arguments, so 
when we look for a pre-existing specialization one typedef gets replaced 
by the other, which breaks.

The fixup stuff is a solution to the problem of typedefs with 
incompatible template parameters leading to crashes, but it seems to me 
that this is just a symptom of the problem of replacing one typedef with 
another, and we should attack that underlying problem instead.  That 
problem is also visible when the typedefs have different names and an 
error message ends up talking about the wrong one.

It seems to me that the way to do this is to strip typedefs from 
non-type arguments like strip_typedefs does for types.  Did we try this 
before?

Ideal would be to treat a specialization using the typedef-using 
arguments as a typedef to the specialization using the canonical 
arguments, but that could follow on later.

Jason

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] PR c++/50852 - loose template parameter comparison
  2012-04-12 21:08 ` [PATCH] PR c++/50852 - loose template parameter comparison Jason Merrill
@ 2012-07-05 18:11   ` Jason Merrill
  0 siblings, 0 replies; 18+ messages in thread
From: Jason Merrill @ 2012-07-05 18:11 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: GCC Patches

On 04/12/2012 05:08 PM, Jason Merrill wrote:
> The fixup stuff is a solution to the problem of typedefs with incompatible template parameters leading to crashes, but it seems to me that this is just a symptom of the problem of replacing one typedef with another, and we should attack that underlying problem instead.  That problem is also visible when the typedefs have different names and an error message ends up talking about the wrong one.

> It seems to me that the way to do this is to strip typedefs from
> non-type arguments like strip_typedefs does for types.  Did we try this
> before?

I'm going to give this a try.

Jason

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2012-07-05 18:11 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-11-17 21:56 [PATCH] PR c++/50852 - loose template parameter comparison Dodji Seketeli
2012-01-17 19:03 ` Jason Merrill
2012-01-24  9:45   ` Dodji Seketeli
2012-01-26 21:43     ` Jason Merrill
2012-01-26 22:16       ` Dodji Seketeli
2012-01-26 22:52         ` Jason Merrill
2012-03-08 13:22       ` [PATCH] PR c++/50852 - Revisit dependant template parameter Dodji Seketeli
2012-03-08 20:17         ` Jason Merrill
2012-03-09 10:04           ` Dodji Seketeli
2012-03-13 21:33         ` Jason Merrill
2012-03-25 18:12           ` Dodji Seketeli
2012-03-27 17:30             ` Dodji Seketeli
2012-03-28 15:02           ` Dodji Seketeli
2012-03-28 15:26             ` Jason Merrill
2012-03-28 17:10               ` Dodji Seketeli
2012-03-28 20:38                 ` Jason Merrill
2012-04-12 21:08 ` [PATCH] PR c++/50852 - loose template parameter comparison Jason Merrill
2012-07-05 18:11   ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).