diff mbox

PR c++/50852 - Revisit dependant template parameter

Message ID m3iphswnxm.fsf@redhat.com
State New
Headers show

Commit Message

Dodji Seketeli March 25, 2012, 6:11 p.m. UTC
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 mbox

Patch

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);
+}
+
 
 /* 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>;