Template as template parameter patch

Kriang Lerdsuwanakij lerdsuwa@scf-fs.usc.edu
Tue Feb 10 03:34:00 GMT 1998


Hi,

The included patch is my implementation of template template parameter
together with test cases.  The patch is against egcs-971225.  It passes
the regression test.  Only 2 new test cases (ttp22.C and ttp23.C) fails.
I will post a fix to these 2 cases as a separate patch since it has
nothing to do with template template parameter.  (The failure is due to
deriving a template class, the base class name D should not be introduced
to the derived class scope to mean D<int>.)

Implementation details:

The design involves a new TEMPLATE_TEMPLATE_PARM node.  It is similar to
TEMPLATE_TYPE_PARM except that its TYPE_NAME is a TEMPLATE_DECL and its
template arguments, if present, are kept inside the template_info field.

Most of the changes are TEMPLATE_TEMPLATE_PARM and TEMPLATE_DECL handling.
In tsubst(), a TEMPLATE_TEMPLATE_PARM with template arguments (which is a
type using template template parameter like TT<int>) is turned into a
RECORD_TYPE while the one without template arguments (template template
paramter that is part of template signature like int f<TT>() ) is turned
into a TEMPLATE_DECL.

For name mangling, a special character 'z' is used in signatures that
contain template template parameters.  If used as a type, template name is
encoded as zX??.  As a comparison, ordinary template uses <length of
template name>+<template name> .
If used as template argument in signature, the argument is encoded as
	z + <number of arguments> + <argument list>
	  + <length of substituted template name> + <subst. template name>
(Ordinary type parameter is encoded as Z + <substituded type> .)

Enjoy!

Kriang

===============================================================

Changelog entry for gcc/ and libiberty/

Tue Jan 13 17:33:34 1998  Kriang Lerdsuwanakij  <lerdsuwa@scf.usc.edu>

	* cplus-dem.c (demangle_template_template_parm): New function.
	(demangle_template): Handle template template parameters.

Changelog entry for gcc/cp/

Tue Jan 13 17:33:34 1998  Kriang Lerdsuwanakij  <lerdsuwa@scf.usc.edu>

	* class.c (finish_struct): Handle TEMPLATE_TEMPLATE_PARM.
	(push_nested_class): Likewise.

	* cp-tree.def (TEMPLATE_TEMPLATE_PARM): New tree code.

	* cp-tree.h (DECL_TEMPLATE_TEMPLATE_PARM_P): New macro.
	(copy_template_template_parm): Declare.

	* decl.c (arg_looking_for_template): New variable.
	(lookup_name_real): Handle TEMPLATE_TEMPLATE_PARM.
	Try to return TEMPLATE_DECL or TEMPLATE_TEMPLATE_PARM
	node if arg_looking_for_template is nonzero.
	(pushdecl): Handle TEMPLATE_TEMPLATE_PARM.
	(grok_op_properties, xref_tag, xref_basetypes): Likewise.
	(grokdeclarator): Handle TEMPLATE_DECL.

	* decl2.c (constructor_name_full): Handle TEMPLATE_TEMPLATE_PARM.

	* error.c (dump_type): Add TEMPLATE_DECL and TEMPLATE_TEMPLATE_PARM.
	(dump_type_prefix, dump_type_suffix) Handle TEMPLATE_TEMPLATE_PARM.
	(dump_decl): Handle unnamed template type parameters.
	Handle template template parameters.
	(dump_function_name): Handle template template parameters.

	* init.c (is_aggr_typedef, is_aggr_type, get_aggr_from_typedef): 
	Handle TEMPLATE_TEMPLATE_PARM.

	* method.c (build_template_template_parm_names): New function.
	(build_template_parm_names): Handle TEMPLATE_DECL.
	(build_overload_nested_name, build_overload_name): 
	Handle TEMPLATE_TEMPLATE_PARM.

	* parse.y (maybe_identifier): New nonterminal.
	(template_type_parm): Use it.
	(template_template_parm, template_arg1): New nonterminal.
	(template_parm): Add template_template_parm rules.
	(template_arg): Set processing_template_arg.
	(template_arg1): Rules moved from template_arg.
	(primary, nonnested_type): Set arg_looking_for_template if we are
	processing template arguments.

	* pt.c (begin_member_template_processing): Handle TEMPLATE_DECL.
	(process_template_parm): Handle template template parameters.
	(coerce_template_parms, comp_template_args): Likewise.
	(mangle_class_name_for_template, lookup_template_class): Likewise.
	(uses_template_parms): Handle TEMPLATE_DECL and 
	TEMPLATE_TEMPLATE_PARM.
	(current_template_args): Handle TEMPLATE_DECL.
	(tsubst, tsubst_copy, unify): Handle TEMPLATE_TEMPLATE_PARM.

	* search.c (dfs_walk, dfs_record_inheritance): 
	Handle TEMPLATE_TEMPLATE_PARM.
	
	* tree.c (copy_template_template_parm): New function.
	(mapcar): Handle TEMPLATE_TEMPLATE_PARM.

	* typeck.c (comptypes): Handle TEMPLATE_TEMPLATE_PARM.

============== Diff for cplus-dem.c in gcc/ and libiberty/ ================

diff -rNpu3 gcc-old/cplus-dem.c gcc/cplus-dem.c
--- gcc-old/cplus-dem.c	Sat Jan 10 02:25:42 1998
+++ gcc/cplus-dem.c	Tue Jan 13 17:33:34 1998
@@ -223,6 +223,10 @@ demangle_method_args PARAMS ((struct wor
 #endif
 
 static int
+demangle_template_template_parm PARAMS ((struct work_stuff *work, 
+					 const char **, string *));
+
+static int
 demangle_template PARAMS ((struct work_stuff *work, const char **, string *,
 			   string *, int));
 
@@ -923,6 +927,70 @@ demangle_method_args (work, mangled, dec
 #endif
 
 static int
+demangle_template_template_parm (work, mangled, tname)
+     struct work_stuff *work;
+     const char **mangled;
+     string *tname;
+{
+  int i;
+  int r;
+  int need_comma = 0;
+  int success = 1;
+  string temp;
+
+  string_append (tname, "template <");
+  /* get size of template parameter list */
+  if (get_count (mangled, &r))
+    {
+      for (i = 0; i < r; i++)
+	{
+	  if (need_comma)
+	    {
+	      string_append (tname, ", ");
+	    }
+
+	    /* Z for type parameters */
+	    if (**mangled == 'Z')
+	      {
+		(*mangled)++;
+		string_append (tname, "class");
+	      }
+	      /* z for template parameters */
+	    else if (**mangled == 'z')
+	      {
+		(*mangled)++;
+		success = 
+		  demangle_template_template_parm (work, mangled, tname);
+		if (!success)
+		  {
+		    break;
+		  }
+	      }
+	    else
+	      {
+		/* temp is initialized in do_type */
+		success = do_type (work, mangled, &temp);
+		if (success)
+		  {
+		    string_appends (tname, &temp);
+		  }
+		string_delete(&temp);
+		if (!success)
+		  {
+		    break;
+		  }
+	      }
+	  need_comma = 1;
+	}
+
+    }
+  if (tname->p[-1] == '>')
+    string_append (tname, " ");
+  string_append (tname, "> class");
+  return (success);
+}
+
+static int
 demangle_template (work, mangled, tname, trawname, is_type)
      struct work_stuff *work;
      const char **mangled;
@@ -951,19 +1019,50 @@ demangle_template (work, mangled, tname,
     {
       start = *mangled;
       /* get template name */
-      if ((r = consume_count (mangled)) == 0 || strlen (*mangled) < r)
+      if (**mangled == 'z')
 	{
-	  return (0);
+	  int idx;
+	  (*mangled)++;
+	  (*mangled)++;
+
+	  idx = consume_count_with_underscores (mangled);
+	  if (idx == -1 
+	      || (work->tmpl_argvec && idx >= work->ntmpl_args)
+	      || consume_count_with_underscores (mangled) == -1)
+	    {
+	      return (0);
+	    }
+	  if (work->tmpl_argvec)
+	    {
+	      string_append (tname, work->tmpl_argvec[idx]);
+	      if (trawname)
+		string_append (trawname, work->tmpl_argvec[idx]);
+	    }
+	  else
+	    {
+	      char buf[10];
+	      sprintf(buf, "T%d", idx);
+	      string_append (tname, buf);
+	      if (trawname)
+		string_append (trawname, work->tmpl_argvec[idx]);
+	    }
 	}
-      if (trawname)
-	string_appendn (trawname, *mangled, r);
-      is_java_array = (work -> options & DMGL_JAVA)
-	&& strncmp (*mangled, "JArray1Z", 8) == 0;
-      if (! is_java_array)
+      else
 	{
-	  string_appendn (tname, *mangled, r);
+	  if ((r = consume_count (mangled)) == 0 || strlen (*mangled) < r)
+	    {
+	      return (0);
+	    }
+	  if (trawname)
+	    string_appendn (trawname, *mangled, r);
+	  is_java_array = (work -> options & DMGL_JAVA)
+	    && strncmp (*mangled, "JArray1Z", 8) == 0;
+	  if (! is_java_array)
+	    {
+	      string_appendn (tname, *mangled, r);
+	    }
+	  *mangled += r;
 	}
-      *mangled += r;
     }
   if (!is_java_array)
     string_append (tname, "<");
@@ -1006,6 +1105,33 @@ demangle_template (work, mangled, tname,
 		}
 	    }
 	  string_delete(&temp);
+	  if (!success)
+	    {
+	      break;
+	    }
+	}
+      /* z for template parameters */
+      else if (**mangled == 'z')
+	{
+	  int r2;
+	  (*mangled)++;
+	  success = demangle_template_template_parm (work, mangled, tname);
+	  
+	  if (success
+	      && (r2 = consume_count (mangled)) > 0 && strlen (*mangled) >= r2)
+	    {
+	      string_append (tname, " ");
+	      string_appendn (tname, *mangled, r2);
+	      if (!is_type)
+		{
+		  /* Save the template argument. */
+		  int len = r2;
+		  work->tmpl_argvec[i] = xmalloc (len + 1);
+		  memcpy (work->tmpl_argvec[i], *mangled, len);
+		  work->tmpl_argvec[i][len] = '\0';
+		}
+	      *mangled += r2;
+	    }
 	  if (!success)
 	    {
 	      break;

============== Diff for files in gcc/cp/ and gcc/testsuite/ ================

diff -rNpu3 gcc-old/cp/class.c gcc/cp/class.c
--- gcc-old/cp/class.c	Sat Jan 10 02:27:52 1998
+++ gcc/cp/class.c	Sat Jan 10 02:27:33 1998
@@ -4506,7 +4506,8 @@ finish_struct (t, list_of_fieldlists, at
              parms, we've seen all the injected decls.  */
 	  if ((TREE_CODE (d) == TYPE_DECL
 	       && (TREE_TYPE (d) == t
-		   || TREE_CODE (TREE_TYPE (d)) == TEMPLATE_TYPE_PARM))
+		   || TREE_CODE (TREE_TYPE (d)) == TEMPLATE_TYPE_PARM
+		   || TREE_CODE (TREE_TYPE (d)) == TEMPLATE_TEMPLATE_PARM))
 	      || TREE_CODE (d) == CONST_DECL)
 	    break;
 	  /* Don't inject cache decls.  */
@@ -4870,7 +4871,8 @@ push_nested_class (type, modify)
   tree context;
 
   if (type == NULL_TREE || type == error_mark_node || ! IS_AGGR_TYPE (type)
-      || TREE_CODE (type) == TEMPLATE_TYPE_PARM)
+      || TREE_CODE (type) == TEMPLATE_TYPE_PARM
+      || TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM)
     return;
   
   context = DECL_CONTEXT (TYPE_MAIN_DECL (type));
diff -rNpu3 gcc-old/cp/cp-tree.def gcc/cp/cp-tree.def
--- gcc-old/cp/cp-tree.def	Sat Jan 10 02:27:52 1998
+++ gcc/cp/cp-tree.def	Sat Jan 10 02:27:33 1998
@@ -91,6 +91,12 @@ DEFTREECODE (TEMPLATE_DECL, "template_de
    Use TYPE_FIELDS to find parmlist and index.  */
 DEFTREECODE (TEMPLATE_TYPE_PARM, "template_type_parm", 't', 0)
 
+/* Index into a template parameter list.  This parameter must be a type.
+   If it is used in signature of a template, TEMPLATE_INFO is NULL_TREE.
+   Otherwise it is used to declare a type like TT<int>.
+   Use TYPE_FIELDS to find parmlist and index.  */
+DEFTREECODE (TEMPLATE_TEMPLATE_PARM, "template_template_parm", 't', 0)
+
 /* A type designated by 'typename T::t'. */
 DEFTREECODE (TYPENAME_TYPE, "typename_type", 't', 0)
 
diff -rNpu3 gcc-old/cp/cp-tree.h gcc/cp/cp-tree.h
--- gcc-old/cp/cp-tree.h	Sat Jan 10 02:27:52 1998
+++ gcc/cp/cp-tree.h	Sat Jan 10 02:27:33 1998
@@ -1348,6 +1348,12 @@ extern int flag_new_for_scope;
 #define DECL_TEMPLATE_INSTANTIATIONS(NODE) DECL_VINDEX(NODE)
 #define DECL_TEMPLATE_INJECT(NODE)	DECL_INITIAL(NODE)
 
+/* Nonzero for TEMPLATE_DECL nodes that represents template template
+   parameters */
+#define DECL_TEMPLATE_TEMPLATE_PARM_P(NODE) \
+  (TREE_CODE (NODE) == TEMPLATE_DECL && TREE_TYPE (NODE) \
+   && TREE_CODE (TREE_TYPE (NODE)) == TEMPLATE_TEMPLATE_PARM)
+
 #define DECL_FUNCTION_TEMPLATE_P(NODE)  \
   (TREE_CODE (NODE) == TEMPLATE_DECL \
    && TREE_CODE (DECL_TEMPLATE_RESULT (NODE)) == FUNCTION_DECL)
@@ -1917,11 +1923,13 @@ extern tree current_class_type;	/* _TYPE
 #define FRIEND_NAME(LIST) (TREE_PURPOSE (LIST))
 #define FRIEND_DECLS(LIST) (TREE_VALUE (LIST))
 
-/* These macros are for accessing the fields of TEMPLATE...PARM nodes.  */
+/* These macros are for accessing the fields of TEMPLATE_TYPE_PARM 
+   and TEMPLATE_TEMPLATE_PARM nodes.  */
 #define TEMPLATE_TYPE_IDX(NODE) TREE_INT_CST_LOW (TYPE_FIELDS (NODE))
 #define TEMPLATE_TYPE_LEVEL(NODE) TREE_INT_CST_HIGH (TYPE_FIELDS (NODE))
 #define TEMPLATE_TYPE_SET_INFO(NODE,I,L) \
   (TYPE_FIELDS (NODE) = build_int_2 (I, L))
+/* These macros are for accessing the fields of TEMPLATE_CONST_PARM nodes.  */
 #define TEMPLATE_CONST_IDX(NODE) (TREE_INT_CST_LOW(NODE))
 #define TEMPLATE_CONST_LEVEL(NODE) (TREE_INT_CST_HIGH(NODE))
 #define TEMPLATE_CONST_SET_INFO(NODE,I,L) \
@@ -2450,6 +2458,7 @@ extern int promotes_to_aggr_type		PROTO(
 extern int is_aggr_type_2			PROTO((tree, tree));
 extern char *lang_printable_name		PROTO((tree, int));
 extern tree build_exception_variant		PROTO((tree, tree));
+extern tree copy_template_template_parm		PROTO((tree));
 extern tree copy_to_permanent			PROTO((tree));
 extern void print_lang_statistics		PROTO((void));
 extern void __eprintf
diff -rNpu3 gcc-old/cp/decl.c gcc/cp/decl.c
--- gcc-old/cp/decl.c	Sat Jan 10 02:27:52 1998
+++ gcc/cp/decl.c	Sat Jan 10 02:27:33 1998
@@ -397,6 +397,9 @@ static struct named_label_list *named_la
    in the TREE_PURPOSE slot.  */
 tree static_aggregates;
 
+/* Nonzero if we lookup name inside template argument.  */
+int arg_looking_for_template;
+
 /* -- end of C++ */
 
 /* Two expressions that are constants with value zero.
@@ -3038,7 +3041,8 @@ pushdecl (x)
   /* Type are looked up using the DECL_NAME, as that is what the rest of the
      compiler wants to use.  */
   if (TREE_CODE (x) == TYPE_DECL || TREE_CODE (x) == VAR_DECL
-      || TREE_CODE (x) == NAMESPACE_DECL || TREE_CODE (x) == TEMPLATE_TYPE_PARM)
+      || TREE_CODE (x) == NAMESPACE_DECL || TREE_CODE (x) == TEMPLATE_TYPE_PARM
+      || TREE_CODE (x) == TEMPLATE_TEMPLATE_PARM)
     name = DECL_NAME (x);
 
   if (name)
@@ -4468,6 +4472,7 @@ lookup_name_real (name, prefer_type, non
 	    }
 	  else if (! IS_AGGR_TYPE (type)
 		   || TREE_CODE (type) == TEMPLATE_TYPE_PARM
+		   || TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM
 		   || TREE_CODE (type) == TYPENAME_TYPE)
 	    /* Someone else will give an error about this if needed.  */
 	    val = NULL_TREE;
@@ -4601,7 +4606,13 @@ lookup_name_real (name, prefer_type, non
 	  val = from_obj;
 	}
 
-      if ((TREE_CODE (val) == TEMPLATE_DECL && looking_for_template)
+      if (TREE_CODE (val) == TEMPLATE_DECL && arg_looking_for_template)
+	{
+	  /* TEMPLATE_TEMPLATE_PARM node is preferred over TEMPLATE_DECL.  */
+	  if (DECL_TEMPLATE_TEMPLATE_PARM_P (val))
+	  	val = TREE_TYPE (val);
+	}
+      else if ((TREE_CODE (val) == TEMPLATE_DECL && looking_for_template)
 	  || TREE_CODE (val) == TYPE_DECL || prefer_type <= 0)
 	;
       else if (IDENTIFIER_HAS_TYPE_VALUE (name))
@@ -8100,7 +8111,7 @@ grokdeclarator (declarator, declspecs, d
 	    }
 	}
       /* C++ aggregate types.  */
-      else if (TREE_CODE (id) == TYPE_DECL)
+      else if (TREE_CODE (id) == TYPE_DECL || TREE_CODE (id) == TEMPLATE_DECL)
 	{
 	  if (type)
 	    cp_error ("multiple declarations `%T' and `%T'", type,
@@ -10486,7 +10497,8 @@ grok_op_properties (decl, virtualp, frie
 		    /* This lets bad template code slip through.  */
 		    if (IS_AGGR_TYPE (arg)
 			|| TREE_CODE (arg) == ENUMERAL_TYPE
-			|| TREE_CODE (arg) == TEMPLATE_TYPE_PARM)
+			|| TREE_CODE (arg) == TEMPLATE_TYPE_PARM
+			|| TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
 		      goto foundaggr;
 		  }
 	      cp_error
@@ -10715,12 +10727,14 @@ xref_tag (code_type_node, name, binfo, g
     }
   else
     t = IDENTIFIER_TYPE_VALUE (name);
-  if (t && TREE_CODE (t) != code && TREE_CODE (t) != TEMPLATE_TYPE_PARM)
+  if (t && TREE_CODE (t) != code && TREE_CODE (t) != TEMPLATE_TYPE_PARM
+      && TREE_CODE (t) != TEMPLATE_TEMPLATE_PARM)
     t = NULL_TREE;
 
   if (! globalize)
     {
-      if (pedantic && t && TREE_CODE (t) == TEMPLATE_TYPE_PARM)
+      if (pedantic && t && (TREE_CODE (t) == TEMPLATE_TYPE_PARM 
+			    || TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM))
 	{
 	  cp_pedwarn ("redeclaration of template type-parameter `%T'", name);
 	  cp_pedwarn_at ("  previously declared here", t);
@@ -10917,7 +10931,8 @@ xref_basetypes (code_type_node, name, re
       if (!basetype
 	  || (TREE_CODE (basetype) != RECORD_TYPE
 	      && TREE_CODE (basetype) != TYPENAME_TYPE
-	      && TREE_CODE (basetype) != TEMPLATE_TYPE_PARM))
+	      && TREE_CODE (basetype) != TEMPLATE_TYPE_PARM
+	      && TREE_CODE (basetype) != TEMPLATE_TEMPLATE_PARM))
 	{
 	  cp_error ("base type `%T' fails to be a struct or class type",
 		    TREE_VALUE (binfo));
diff -rNpu3 gcc-old/cp/decl2.c gcc/cp/decl2.c
--- gcc-old/cp/decl2.c	Sat Jan 10 02:27:52 1998
+++ gcc/cp/decl2.c	Sat Jan 10 02:27:33 1998
@@ -1997,7 +1997,8 @@ tree
 constructor_name_full (thing)
      tree thing;
 {
-  if (TREE_CODE (thing) == TEMPLATE_TYPE_PARM)
+  if (TREE_CODE (thing) == TEMPLATE_TYPE_PARM
+      || TREE_CODE (thing) == TEMPLATE_TEMPLATE_PARM)
     thing = TYPE_NAME (thing);
   else if (IS_AGGR_TYPE_CODE (TREE_CODE (thing)))
     {
diff -rNpu3 gcc-old/cp/error.c gcc/cp/error.c
--- gcc-old/cp/error.c	Sat Jan 10 02:27:52 1998
+++ gcc/cp/error.c	Sat Jan 10 02:27:33 1998
@@ -229,6 +229,86 @@ dump_type (t, v)
       OB_PUTID (TYPE_IDENTIFIER (t));
       break;
 
+      /* A substituted template template parameter.  Default template 
+	 argument handling are different from dump_decl.  */
+    case TEMPLATE_DECL:
+      {
+	tree orig_args = DECL_TEMPLATE_PARMS (t);
+	tree args;
+	int i; 
+	for (args = orig_args = nreverse (orig_args); 
+	     args;
+	     args = TREE_CHAIN (args))
+	  {
+	    int len = TREE_VEC_LENGTH (TREE_VALUE (args));
+
+	    OB_PUTS ("template <");
+	    for (i = 0; i < len; i++)
+	      {
+		tree arg = TREE_VEC_ELT (TREE_VALUE (args), i);
+		tree defval = TREE_PURPOSE (arg);
+		arg = TREE_VALUE (arg);
+		if (TREE_CODE (arg) == TYPE_DECL)
+		  {
+		    OB_PUTS ("class ");
+		    if (DECL_NAME (arg))
+		      OB_PUTID (DECL_NAME (arg));
+		    else
+		      OB_PUTS ("{anon}");
+		  }
+		else
+		  dump_decl (arg, 1);
+		
+		if (defval)
+		  {
+		    OB_PUTS (" = ");
+		    if (TREE_CODE (arg) == TYPE_DECL)
+		      dump_type (defval, 1);
+		    else
+		      dump_expr (defval, 1);
+		  }
+		
+		OB_PUTC2 (',', ' ');
+	      }
+	    if (len != 0)
+	      OB_UNPUT (2);
+	    OB_PUTC2 ('>', ' ');
+	  }
+	nreverse(orig_args);
+	dump_type (TREE_TYPE (t), v);
+      }
+      break;
+
+    case TEMPLATE_TEMPLATE_PARM:
+      if (!CLASSTYPE_TEMPLATE_INFO (t))
+	{
+	  /* For parameters inside template signature. */
+	  if (TYPE_IDENTIFIER (t))
+	    OB_PUTID (TYPE_IDENTIFIER (t));
+	  else
+	    OB_PUTS ("{anonymous template template parm}");
+	}
+      else
+	{
+	  int i;
+	  tree args = CLASSTYPE_TI_ARGS (t);
+	  OB_PUTID (TYPE_IDENTIFIER (t));
+	  OB_PUTC ('<');
+	  for (i = 0; i < TREE_VEC_LENGTH (args); i++)
+	    {
+	      tree arg = TREE_VEC_ELT (args, i);
+	      if (TREE_CODE_CLASS (TREE_CODE (arg)) == 't'
+		  || TREE_CODE (arg) == TEMPLATE_DECL)
+	        dump_type (arg, 0);
+	      else
+	        dump_expr (arg, 0);
+	      if (i < TREE_VEC_LENGTH (args)-1)
+	        OB_PUTC2 (',', ' ');
+	    }
+	  OB_PUTC ('>');
+	}
+      break;
+
     case TEMPLATE_TYPE_PARM:
       dump_readonly_or_volatile (t, after);
       if (TYPE_IDENTIFIER (t))
@@ -447,6 +527,7 @@ dump_type_prefix (t, v)
     case REAL_TYPE:
     case RECORD_TYPE:
     case TEMPLATE_TYPE_PARM:
+    case TEMPLATE_TEMPLATE_PARM:
     case TREE_LIST:
     case TYPE_DECL:
     case TREE_VEC:
@@ -529,6 +610,7 @@ dump_type_suffix (t, v)
     case REAL_TYPE:
     case RECORD_TYPE:
     case TEMPLATE_TYPE_PARM:
+    case TEMPLATE_TEMPLATE_PARM:
     case TREE_LIST:
     case TYPE_DECL:
     case TREE_VEC:
@@ -740,7 +822,10 @@ dump_decl (t, v)
 		if (TREE_CODE (arg) == TYPE_DECL)
 		  {
 		    OB_PUTS ("class ");
-		    OB_PUTID (DECL_NAME (arg));
+		    if (DECL_NAME (arg))
+		      OB_PUTID (DECL_NAME (arg));
+		    else
+		      OB_PUTS ("{anon}");
 		  }
 		else
 		  dump_decl (arg, 1);
@@ -786,7 +871,8 @@ dump_decl (t, v)
 	OB_PUTC ('<');
 	for (args = TREE_OPERAND (t, 1); args; args = TREE_CHAIN (args))
 	  {
-	    if (TREE_CODE_CLASS (TREE_CODE (TREE_VALUE (args))) == 't')
+	    if (TREE_CODE_CLASS (TREE_CODE (TREE_VALUE (args))) == 't'
+		|| TREE_CODE (TREE_VALUE (args)) == TEMPLATE_DECL)
 	      dump_type (TREE_VALUE (args), 0);
 	    else
 	      dump_expr (TREE_VALUE (args), 0);
@@ -977,7 +1063,8 @@ dump_function_name (t)
 
 		  if (a)
 		    {
-		      if (TREE_CODE_CLASS (TREE_CODE (a)) == 't')
+		      if (TREE_CODE_CLASS (TREE_CODE (a)) == 't'
+			  || TREE_CODE (a) == TEMPLATE_DECL)
 			dump_type (a, 0);
 		      else
 			dump_expr (a, 0);
@@ -1004,7 +1091,8 @@ dump_function_name (t)
 
 		  if (a)
 		    {
-		      if (TREE_CODE_CLASS (TREE_CODE (a)) == 't')
+		      if (TREE_CODE_CLASS (TREE_CODE (a)) == 't'
+			  || TREE_CODE (a) == TEMPLATE_DECL)
 			dump_type (a, 0);
 		      else
 			dump_expr (a, 0);
diff -rNpu3 gcc-old/cp/init.c gcc/cp/init.c
--- gcc-old/cp/init.c	Sat Jan 10 02:27:52 1998
+++ gcc/cp/init.c	Sat Jan 10 02:27:33 1998
@@ -1606,7 +1606,8 @@ is_aggr_typedef (name, or_else)
     }
 
   if (! IS_AGGR_TYPE (type)
-      && TREE_CODE (type) != TEMPLATE_TYPE_PARM)
+      && TREE_CODE (type) != TEMPLATE_TYPE_PARM
+      && TREE_CODE (type) != TEMPLATE_TEMPLATE_PARM)
     {
       if (or_else)
 	cp_error ("`%T' is not an aggregate type", type);
@@ -1627,7 +1628,8 @@ is_aggr_type (type, or_else)
     return 0;
 
   if (! IS_AGGR_TYPE (type)
-      && TREE_CODE (type) != TEMPLATE_TYPE_PARM)
+      && TREE_CODE (type) != TEMPLATE_TYPE_PARM
+      && TREE_CODE (type) != TEMPLATE_TEMPLATE_PARM)
     {
       if (or_else)
 	cp_error ("`%T' is not an aggregate type", type);
@@ -1658,7 +1660,8 @@ get_aggr_from_typedef (name, or_else)
     }
 
   if (! IS_AGGR_TYPE (type)
-      && TREE_CODE (type) != TEMPLATE_TYPE_PARM)
+      && TREE_CODE (type) != TEMPLATE_TYPE_PARM
+      && TREE_CODE (type) != TEMPLATE_TEMPLATE_PARM)
     {
       if (or_else)
 	cp_error ("type `%T' is of non-aggregate type", type);
diff -rNpu3 gcc-old/cp/method.c gcc/cp/method.c
--- gcc-old/cp/method.c	Sat Jan 10 02:27:53 1998
+++ gcc/cp/method.c	Sat Jan 10 02:40:59 1998
@@ -73,6 +73,7 @@ static void do_build_copy_constructor PR
 static tree largest_union_member PROTO((tree));
 static tree build_decl_overload_real PROTO((tree, tree, tree, tree,
 					    tree, int)); 
+static void build_template_template_parm_names PROTO((tree));
 static void build_template_parm_names PROTO((tree, tree));
 static void build_underscore_int PROTO((int));
 
@@ -388,8 +389,11 @@ build_overload_nested_name (decl)
     {
       tree context = DECL_CONTEXT (decl);
       /* For a template type parameter, we want to output an 'Xn'
-	 rather than 'T' or some such. */
-      if (TREE_CODE (context) == TEMPLATE_TYPE_PARM)
+	 rather than 'T' or some such.  For a template template 
+	 parameter, we also want an extra prefix 'z' and the
+	 parameter list.  */
+      if (TREE_CODE (context) == TEMPLATE_TYPE_PARM 
+	  || TREE_CODE (context) == TEMPLATE_TEMPLATE_PARM)
 	build_overload_name (context, 0, 0);
       else
 	{
@@ -661,6 +665,41 @@ build_overload_value (type, value, in_te
 }
 
 
+/* Add encodings for the declaration of template template parameters.
+   PARMLIST must be a TREE_VEC */
+
+static void
+build_template_template_parm_names (parmlist)
+     tree parmlist;
+{
+  int i, nparms;
+
+  my_friendly_assert (TREE_CODE (parmlist) == TREE_VEC, 246.5);
+  nparms = TREE_VEC_LENGTH (parmlist);
+  icat (nparms);
+  for (i = 0; i < nparms; i++)
+    {
+      tree parm = TREE_VALUE (TREE_VEC_ELT (parmlist, i));
+      if (TREE_CODE (parm) == TYPE_DECL)
+	{
+	  /* This parameter is a type.  */
+	  OB_PUTC ('Z');
+	}
+      else if (TREE_CODE (parm) == TEMPLATE_DECL)
+	{
+	  /* This parameter is a template. */
+	  OB_PUTC ('z');
+	  build_template_template_parm_names (DECL_INNERMOST_TEMPLATE_PARMS (parm));
+	}
+      else
+	{
+	  /* It's a PARM_DECL.  */
+	  build_overload_name (TREE_TYPE (parm), 0, 0);
+	}
+    }
+}
+
+
 /* Add encodings for the vector of template parameters in PARMLIST,
    given the vector of arguments to be substituted in ARGLIST.  */
 
@@ -683,6 +722,23 @@ build_template_parm_names (parmlist, arg
 	  OB_PUTC ('Z');
 	  build_overload_name (arg, 0, 0);
 	}
+      else if (TREE_CODE (parm) == TEMPLATE_DECL)
+	{
+	  /* This parameter is a template. */
+	  if (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
+	    /* Output parameter declaration, argument index and level */
+	    build_overload_name (arg, 0, 0);
+	  else
+	    {
+	      /* A TEMPLATE_DECL node, output the parameter declaration 
+		 and template name */
+
+	      OB_PUTC ('z');
+	      build_template_template_parm_names (DECL_INNERMOST_TEMPLATE_PARMS (parm));
+	      icat (IDENTIFIER_LENGTH (DECL_NAME (arg)));
+	      OB_PUTID (DECL_NAME (arg));
+	    }
+	}
       else
 	{
 	  parm = tsubst (parm, arglist,
@@ -1049,6 +1105,34 @@ build_overload_name (parmtypes, begin, e
 	case UNKNOWN_TYPE:
 	  /* This will take some work.  */
 	  OB_PUTC ('?');
+	  break;
+
+	case TEMPLATE_TEMPLATE_PARM:
+	  /* Find and output the original template parameter 
+	     declaration. */
+	  if (CLASSTYPE_TEMPLATE_INFO (parmtype))
+	    {
+	      OB_PUTC ('t');
+	      OB_PUTC ('z');
+	      OB_PUTC ('X');
+	      build_underscore_int (TEMPLATE_TYPE_IDX (parmtype));
+	      build_underscore_int (TEMPLATE_TYPE_LEVEL (parmtype));
+
+	      build_template_parm_names (
+		DECL_INNERMOST_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (parmtype)),
+		CLASSTYPE_TI_ARGS (parmtype));
+	    }
+	  else
+	    {
+	      OB_PUTC ('Z');
+	      OB_PUTC ('z');
+	      OB_PUTC ('X');
+	      build_underscore_int (TEMPLATE_TYPE_IDX (parmtype));
+	      build_underscore_int (TEMPLATE_TYPE_LEVEL (parmtype));
+
+	      build_template_template_parm_names (
+		DECL_INNERMOST_TEMPLATE_PARMS (TYPE_STUB_DECL (parmtype)));
+	    }
 	  break;
 
 	case TEMPLATE_TYPE_PARM:
diff -rNpu3 gcc-old/cp/parse.y gcc/cp/parse.y
--- gcc-old/cp/parse.y	Sat Jan 10 02:27:53 1998
+++ gcc/cp/parse.y	Sat Jan 10 02:27:34 1998
@@ -72,6 +72,12 @@ extern tree strip_attrs		PROTO((tree));
    error message if the user supplies an empty conditional expression.  */
 static char *cond_stmt_keyword;
 
+/* If nonzero, we try to treat TEMPLATE_DECL as argument in template
+   template parameter. */
+static int processing_template_arg;
+
+extern int arg_looking_for_template;
+
 static tree empty_parms PROTO((void));
 
 /* Nonzero if we have an `extern "C"' acting as an extern specifier.  */
@@ -196,7 +202,7 @@ empty_parms ()
 %type <code> unop
 
 %type <ttype> identifier IDENTIFIER TYPENAME CONSTANT expr nonnull_exprlist
-%type <ttype> PFUNCNAME
+%type <ttype> PFUNCNAME maybe_identifier
 %type <ttype> paren_expr_or_null nontrivial_exprlist SELFNAME
 %type <ttype> expr_no_commas cast_expr unary_expr primary string STRING
 %type <ttype> reserved_declspecs boolean.literal
@@ -258,9 +264,9 @@ empty_parms ()
 %type <ttype> nonmomentary_expr maybe_parmlist
 %type <itype> initdcl0 notype_initdcl0 member_init_list
 %type <ttype> template_header template_parm_list template_parm
-%type <ttype> template_type_parm
+%type <ttype> template_type_parm template_template_parm
 %type <code>  template_close_bracket
-%type <ttype> template_type template_arg_list template_arg
+%type <ttype> template_type template_arg_list template_arg template_arg1
 %type <ttype> condition xcond paren_cond_or_null
 %type <ttype> type_name nested_name_specifier nested_type ptr_to_mem
 %type <ttype> complete_type_name notype_identifier nonnested_type
@@ -447,11 +453,16 @@ template_parm_list:
 		{ $$ = process_template_parm ($1, $3); }
 	;
 
+maybe_identifier:
+	  identifier
+	  	{ $$ = $1; }
+	|	/* empty */
+		{ $$ = NULL_TREE; }
+
 template_type_parm:
-	  aggr
+	  aggr maybe_identifier
 		{ 
-		  $$ = build_tree_list ($1, NULL_TREE);
-		 ttpa:
+		  $$ = build_tree_list ($1, $2);
 		  if (TREE_PURPOSE ($$) == signature_type_node)
 		    sorry ("signature as template type parameter");
 		  else if (TREE_PURPOSE ($$) != class_type_node)
@@ -460,14 +471,31 @@ template_type_parm:
 		      TREE_PURPOSE ($$) = class_type_node;
 		    }
 		}
-	| aggr identifier
-		{ $$ = build_tree_list ($1, $2); goto ttpa; }
-	| TYPENAME_KEYWORD
-		{ $$ = build_tree_list (class_type_node, NULL_TREE); }
-	| TYPENAME_KEYWORD identifier
+	| TYPENAME_KEYWORD maybe_identifier
 		{ $$ = build_tree_list (class_type_node, $2); }
 	;
 
+template_template_parm:
+	  template_header aggr maybe_identifier
+		{
+		  tree decl = build_decl (TYPE_DECL, $3, NULL_TREE);
+		  tree tmpl = build_lang_decl (TEMPLATE_DECL, $3, NULL_TREE);
+		  DECL_TEMPLATE_PARMS (tmpl) = current_template_parms;
+		  DECL_TEMPLATE_RESULT (tmpl) = decl;
+		  SET_DECL_ARTIFICIAL (decl);
+		  end_template_decl ();
+
+		  if ($2 == signature_type_node)
+		    sorry ("signature as template template parameter");
+		  else if ($2 != class_type_node)
+		    {
+		      pedwarn ("template template parameters must use the keyword `class'");
+		      TREE_PURPOSE ($$) = class_type_node;
+		    }
+		  $$ = build_tree_list (class_type_node, tmpl);
+		}
+	;
+
 template_parm:
 	/* The following rules introduce a new reduce/reduce
 	   conflict on the ',' and '>' input tokens: they are valid
@@ -484,6 +512,21 @@ template_parm:
 		{ $$ = build_tree_list (NULL_TREE, $1.t); }
 	| parm '=' expr_no_commas  %prec ARITHCOMPARE
 		{ $$ = build_tree_list ($3, $1.t); }
+	| template_template_parm
+		{ $$ = build_tree_list (NULL_TREE, $1); }
+	| template_template_parm '=' PTYPENAME
+	  	{
+		  tree defarg;
+	  	  arg_looking_for_template = 1;
+	  	  defarg = lookup_name ($3, 0);
+	  	  arg_looking_for_template = 0;
+			
+		  if (!defarg || defarg == error_mark_node
+		      || (TREE_CODE (defarg) != TEMPLATE_DECL
+			  && TREE_CODE (defarg) != TEMPLATE_TEMPLATE_PARM))
+		    defarg = do_identifier ($3, 1);
+		  $$ = build_tree_list (defarg, $1);
+	  	}
 	;
 
 template_def:
@@ -935,6 +978,12 @@ template_arg_list:
 	;
 
 template_arg:
+		{ processing_template_arg = 1; }
+	  template_arg1
+		{ $$ = $2;
+		  processing_template_arg = 0; }
+
+template_arg1:
 	  type_id
 		{ $$ = groktypename ($1.t); }
 	| expr_no_commas  %prec ARITHCOMPARE
@@ -1353,7 +1402,21 @@ primary:
 		  if (TREE_CODE ($$) == BIT_NOT_EXPR)
 		    $$ = build_x_unary_op (BIT_NOT_EXPR, TREE_OPERAND ($$, 0));
 		  else if (TREE_CODE ($$) != TEMPLATE_ID_EXPR)
-		    $$ = do_identifier ($$, 1);
+		    if (processing_template_arg)
+		      {
+			tree id;
+			arg_looking_for_template = processing_template_arg;
+			id = lookup_name ($$, 0);
+			arg_looking_for_template = 0;
+			
+			if (!id || id == error_mark_node
+			    || (TREE_CODE (id) != TEMPLATE_DECL
+				&& TREE_CODE (id) != TEMPLATE_TEMPLATE_PARM))
+			  id = do_identifier ($$, 1);
+			$$ = id;
+		      } 
+		    else
+		      $$ = do_identifier ($$, 1);
 		}		
 	| CONSTANT
 	| boolean.literal
@@ -3018,7 +3081,10 @@ nonnested_type:
 		{
 		  if (TREE_CODE ($1) == IDENTIFIER_NODE)
 		    {
+		      arg_looking_for_template = processing_template_arg;
 		      $$ = lookup_name ($1, 1);
+		      arg_looking_for_template = 0;
+
 		      if (current_class_type
 			  && TYPE_BEING_DEFINED (current_class_type)
 			  && ! IDENTIFIER_CLASS_VALUE ($1))
diff -rNpu3 gcc-old/cp/pt.c gcc/cp/pt.c
--- gcc-old/cp/pt.c	Sat Jan 10 02:27:53 1998
+++ gcc/cp/pt.c	Tue Jan 13 17:10:23 1998
@@ -108,6 +108,7 @@ begin_member_template_processing (decl)
       switch (TREE_CODE (parm))
 	{
 	case TYPE_DECL:
+	case TEMPLATE_DECL:
 	  pushdecl (parm);
 	  break;
 
@@ -665,6 +666,8 @@ process_template_parm (list, next)
 
       if (TREE_CODE (p) == TYPE_DECL)
 	idx = TEMPLATE_TYPE_IDX (TREE_TYPE (p));
+      else if (TREE_CODE (p) == TEMPLATE_DECL)
+	idx = TEMPLATE_TYPE_IDX (TREE_TYPE (DECL_TEMPLATE_RESULT (p)));
       else
 	idx = TEMPLATE_CONST_IDX (DECL_INITIAL (p));
       ++idx;
@@ -710,9 +713,26 @@ process_template_parm (list, next)
     }
   else
     {
-      tree t = make_lang_type (TEMPLATE_TYPE_PARM);
+      tree t;
+      parm = TREE_VALUE (parm);
+      
+      if (parm && TREE_CODE (parm) == TEMPLATE_DECL)
+	{
+	  t = make_lang_type (TEMPLATE_TEMPLATE_PARM);
+	  /* This is for distinguishing between real templates and template 
+	     template parameters */
+	  TREE_TYPE (parm) = t;
+	  TREE_TYPE (DECL_TEMPLATE_RESULT (parm)) = t;
+	  decl = parm;
+	}
+      else
+	{
+	  t = make_lang_type (TEMPLATE_TYPE_PARM);
+	  /* parm is either IDENTIFIER_NODE or NULL_TREE */
+	  decl = build_decl (TYPE_DECL, parm, t);
+	}
+        
       CLASSTYPE_GOT_SEMICOLON (t) = 1;
-      decl = build_decl (TYPE_DECL, TREE_VALUE (parm), t);
       TYPE_NAME (t) = decl;
       TYPE_STUB_DECL (t) = decl;
       parm = decl;
@@ -791,7 +811,8 @@ current_template_args ()
 	    {
 	      t = TREE_VALUE (t);
 	      
-	      if (TREE_CODE (t) == TYPE_DECL)
+	      if (TREE_CODE (t) == TYPE_DECL 
+		  || TREE_CODE (t) == TEMPLATE_DECL)
 		t = TREE_TYPE (t);
 	      else
 		t = DECL_INITIAL (t);
@@ -970,6 +991,7 @@ coerce_template_parms (parms, arglist, i
      tree in_decl;
 {
   int nparms, nargs, i, lost = 0;
+  int is_tmpl_parm = 0;
   tree vec;
 
   if (arglist == NULL_TREE)
@@ -993,7 +1015,23 @@ coerce_template_parms (parms, arglist, i
     }
 
   if (arglist && TREE_CODE (arglist) == TREE_VEC)
-    vec = copy_node (arglist);
+    if (nargs == nparms)
+      vec = copy_node (arglist);
+    else
+      {
+	/* We arrive here when a template is used in template template
+	   parameter with some default arguments */
+	is_tmpl_parm = 1;
+	vec = make_tree_vec (nparms);
+	for (i = 0; i < nparms; i++)
+	  {
+	    tree arg = TREE_VEC_ELT (arglist, i);
+	    if (arg)
+	      TREE_VEC_ELT (vec, i) = arg;
+	    else
+	      TREE_VEC_ELT (vec, i) = TREE_PURPOSE (TREE_VEC_ELT (parms, i));
+	  }
+      }
   else
     {
       vec = make_tree_vec (nparms);
@@ -1027,10 +1065,32 @@ coerce_template_parms (parms, arglist, i
       tree arg = TREE_VEC_ELT (vec, i);
       tree parm = TREE_VALUE (TREE_VEC_ELT (parms, i));
       tree val = 0;
-      int is_type, requires_type;
 
-      is_type = TREE_CODE_CLASS (TREE_CODE (arg)) == 't';
-      requires_type = TREE_CODE (parm) == TYPE_DECL;
+      int is_type, requires_type, is_tmpl_type, requires_tmpl_type;
+
+      /* In case we are checking arguments inside a template template
+	 parameter, ARG that does not come from default argument is 
+	 also a TREE_LIST node */
+      if (TREE_CODE (arg) == TREE_LIST)
+	{
+          is_tmpl_parm = 1;
+	  arg = TREE_VALUE (arg);
+	}
+
+      /* Check if it is a class template.  */
+      is_tmpl_type = (TREE_CODE (arg) == TEMPLATE_DECL
+		      && TREE_CODE (DECL_TEMPLATE_RESULT (arg)) == TYPE_DECL)
+		     || (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM
+			 && !CLASSTYPE_TEMPLATE_INFO (arg));
+      if (is_tmpl_type && TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
+	arg = TYPE_STUB_DECL (arg);
+      
+      requires_tmpl_type = TREE_CODE (parm) == TEMPLATE_DECL;
+      is_type = TREE_CODE_CLASS (TREE_CODE (arg)) == 't'
+		|| is_tmpl_type
+		|| (is_tmpl_parm && TREE_CODE (arg) == TYPE_DECL);
+      requires_type = TREE_CODE (parm) == TYPE_DECL
+		      || requires_tmpl_type;
 
       if (requires_type && ! is_type && TREE_CODE (arg) == SCOPE_REF
 	  && TREE_CODE (TREE_OPERAND (arg, 0)) == TEMPLATE_TYPE_PARM)
@@ -1049,7 +1109,8 @@ coerce_template_parms (parms, arglist, i
 			i, in_decl);
 	      if (is_type)
 		cp_error ("  expected a constant of type `%T', got `%T'",
-			  TREE_TYPE (parm), arg);
+			  TREE_TYPE (parm),
+			  (is_tmpl_type ? DECL_NAME (arg) : arg));
 	      else
 		cp_error ("  expected a type, got `%E'", arg);
 	    }
@@ -1057,18 +1118,77 @@ coerce_template_parms (parms, arglist, i
 	  TREE_VEC_ELT (vec, i) = error_mark_node;
 	  continue;
 	}
+      if (is_tmpl_type ^ requires_tmpl_type)
+	{
+	  if (in_decl)
+	    {
+	      cp_error ("type/value mismatch at argument %d in template parameter list for `%D'",
+			i, in_decl);
+	      if (is_tmpl_type)
+		cp_error ("  expected a type, got `%T'", DECL_NAME (arg));
+	      else
+		cp_error ("  expected a class template, got `%T'", arg);
+	    }
+	  lost++;
+	  TREE_VEC_ELT (vec, i) = error_mark_node;
+	  continue;
+	}
+      if (is_tmpl_parm)
+	{
+	  if (requires_tmpl_type)
+	    {
+	      cp_error ("nested template template parameter not implemented");
+	      lost++;
+	      TREE_VEC_ELT (vec, i) = error_mark_node;
+	    }
+	  continue;
+	}
+        
       if (is_type)
 	{
-	  val = groktypename (arg);
-	  if (! processing_template_decl)
+	  if (requires_tmpl_type)
+	    {
+	      if (!CLASSTYPE_TEMPLATE_INFO (parm))
+		{
+		  tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm);
+		  tree argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg);
+
+		  /* The parameter and argument roles have to be switched 
+		     here in order to handle default arguments properly.  
+		     For example, 
+		       template<template <class> class TT> void f(TT<int>) 
+		     should be able to accept vector<int> which comes from 
+		       template <class T, class Allcator = allocator> 
+		       class vector.  */
+
+		  val = coerce_template_parms (argparm, parmparm, in_decl);
+		  if (val != error_mark_node)
+		    val = arg;
+		    
+		  /* TEMPLATE_TEMPLATE_PARM node is preferred over 
+		     TEMPLATE_DECL.  */
+		  if (DECL_TEMPLATE_TEMPLATE_PARM_P (val))
+		    val = TREE_TYPE (val);
+		}
+	      else
+		/* The parameter has been substituted with arguments.  
+		   We have already checked this */
+		val = arg;
+	    }
+	  else
 	    {
-	      tree t = target_type (val);
-	      if (TREE_CODE (t) != TYPENAME_TYPE 
-		  && IS_AGGR_TYPE (t)
-		  && decl_function_context (TYPE_MAIN_DECL (t)))
+	      val = groktypename (arg);
+	      if (! processing_template_decl)
 		{
-		  cp_error ("type `%T' composed from a local class is not a valid template-argument", val);
-		  return error_mark_node;
+		  tree t = target_type (val);
+		  if (TREE_CODE (t) != TYPENAME_TYPE 
+		      && IS_AGGR_TYPE (t)
+		      && decl_function_context (TYPE_MAIN_DECL (t)))
+		    {
+		      cp_error ("type `%T' composed from a local class is not a valid template-argument",
+				val);
+		      return error_mark_node;
+		    }
 		}
 	    }
 	}
@@ -1166,6 +1286,14 @@ comp_template_args (oldargs, newargs)
       tree nt = TREE_VEC_ELT (newargs, i);
       tree ot = TREE_VEC_ELT (oldargs, i);
 
+      /* It's messy because we introduce template template parameters
+	 as TEMPLATE_DECL nodes in the class scope but store them in
+	 TEMPLATE_INFO as a TEMPLATE_TEMPLATE_PARM nodes */
+      if (DECL_TEMPLATE_TEMPLATE_PARM_P (nt))
+	nt = TREE_TYPE (nt);
+      if (DECL_TEMPLATE_TEMPLATE_PARM_P (ot))
+	ot = TREE_TYPE (ot);
+
       if (nt == ot)
 	continue;
       if (TREE_CODE (nt) != TREE_CODE (ot))
@@ -1236,6 +1364,17 @@ mangle_class_name_for_template (name, pa
 	  cat (type_as_string (arg, 0));
 	  continue;
 	}
+      else if (TREE_CODE (parm) == TEMPLATE_DECL)
+	{
+	  if (TREE_CODE (arg) == TEMPLATE_DECL)
+	    /* Already substituted with real template.  Just output 
+	       the template name here */
+	    cat (IDENTIFIER_POINTER (DECL_NAME (arg)));
+	  else
+	    /* Output the parameter declaration */
+	    cat (type_as_string (arg, 0));
+	  continue;
+	}
       else
 	my_friendly_assert (TREE_CODE (parm) == PARM_DECL, 269);
 
@@ -1359,9 +1498,15 @@ lookup_template_class (d1, arglist, in_d
 
   if (TREE_CODE (d1) == IDENTIFIER_NODE)
     {
-      template = IDENTIFIER_GLOBAL_VALUE (d1); /* XXX */
-      if (! template)
-	template = IDENTIFIER_CLASS_VALUE (d1);
+      if (IDENTIFIER_LOCAL_VALUE (d1) 
+	  && DECL_TEMPLATE_TEMPLATE_PARM_P (IDENTIFIER_LOCAL_VALUE (d1)))
+	template = IDENTIFIER_LOCAL_VALUE (d1);
+      else
+	{
+	  template = IDENTIFIER_GLOBAL_VALUE (d1); /* XXX */
+	  if (! template)
+	    template = IDENTIFIER_CLASS_VALUE (d1);
+	}
     }
   else if (TREE_CODE (d1) == TYPE_DECL && IS_AGGR_TYPE (TREE_TYPE (d1)))
     {
@@ -1390,7 +1535,29 @@ lookup_template_class (d1, arglist, in_d
       return error_mark_node;
     }
 
-  if (PRIMARY_TEMPLATE_P (template))
+  if (DECL_TEMPLATE_TEMPLATE_PARM_P (template))
+    {
+      /* Create a new TEMPLATE_DECL and TEMPLATE_TEMPLATE_PARM node to store
+         template arguments */
+
+      tree parm = copy_template_template_parm (TREE_TYPE (template));
+      tree template2 = TYPE_STUB_DECL (parm);
+      tree arglist2;
+
+      CLASSTYPE_GOT_SEMICOLON (parm) = 1;
+      parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
+
+      arglist2 = coerce_template_parms (parmlist, arglist, template);
+      if (arglist2 == error_mark_node)
+	return error_mark_node;
+
+      arglist2 = copy_to_permanent (arglist2);
+      CLASSTYPE_TEMPLATE_INFO (parm)
+	= perm_tree_cons (template2, arglist2, NULL_TREE);
+      TYPE_SIZE (parm) = 0;
+      return parm;
+    }
+  else if (PRIMARY_TEMPLATE_P (template))
     {
       parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
 
@@ -1556,6 +1723,15 @@ uses_template_parms (t)
     case TYPE_DECL:
       return uses_template_parms (TREE_TYPE (t));
 
+    case TEMPLATE_DECL:
+      /* A template template parameter is encountered */
+      if (DECL_TEMPLATE_TEMPLATE_PARM_P (t))
+        /* We are parsing a template declaration */
+        return 1;
+      /* We are instantiating templates with template template
+         parameter */
+      return 0;
+      
     case FUNCTION_DECL:
     case VAR_DECL:
       /* ??? What about FIELD_DECLs?  */
@@ -1578,6 +1754,7 @@ uses_template_parms (t)
 
       /* template parm nodes */
     case TEMPLATE_TYPE_PARM:
+    case TEMPLATE_TEMPLATE_PARM:
     case TEMPLATE_CONST_PARM:
       return 1;
 
@@ -2168,12 +2345,14 @@ tsubst (t, args, nargs, in_decl)
       }
 
     case TEMPLATE_TYPE_PARM:
+    case TEMPLATE_TEMPLATE_PARM:
     case TEMPLATE_CONST_PARM:
       {
 	int idx;
 	int level;
 
-	if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
+	if (TREE_CODE (t) == TEMPLATE_TYPE_PARM
+	    || TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM)
 	  {
 	    idx = TEMPLATE_TYPE_IDX (t);
 	    level = TEMPLATE_TYPE_LEVEL (t);
@@ -2203,6 +2382,29 @@ tsubst (t, args, nargs, in_decl)
 		  return cp_build_type_variant
 		    (arg, TYPE_READONLY (arg) || TYPE_READONLY (t),
 		     TYPE_VOLATILE (arg) || TYPE_VOLATILE (t));
+		else if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM)
+		  {
+		    if (CLASSTYPE_TEMPLATE_INFO (t))
+		      {
+			/* We are processing a data member constructed 
+			   from template template parameter */
+			tree argvec = tsubst (
+					TREE_VALUE (CLASSTYPE_TEMPLATE_INFO (t)), 
+					args, nargs, in_decl);
+			tree r;
+
+			/* ARG is the real template to be instantiated.  */
+			if (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
+			  arg = TYPE_NAME (arg);
+			r = lookup_template_class (DECL_NAME (arg), 
+						   argvec, in_decl);
+			return cp_build_type_variant (r, TYPE_READONLY (t),
+						      TYPE_VOLATILE (t));
+		      }
+		    else
+		      /* We are processing a template argument list.  */ 
+		      return arg;
+		  }
 		else
 		  return arg;
 	      }
@@ -2213,6 +2415,8 @@ tsubst (t, args, nargs, in_decl)
 	my_friendly_assert((TREE_CODE (t) == TEMPLATE_CONST_PARM 
 			    && TEMPLATE_CONST_LEVEL (t) > 1) 
 			   || (TREE_CODE (t) == TEMPLATE_TYPE_PARM
+			       && TEMPLATE_TYPE_LEVEL (t) > 1)
+			   || (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM
 			       && TEMPLATE_TYPE_LEVEL (t) > 1),
 			   0);
 	return t;
@@ -3125,6 +3329,7 @@ tsubst_copy (t, args, nargs, in_decl)
     case ENUMERAL_TYPE:
     case INTEGER_TYPE:
     case TEMPLATE_TYPE_PARM:
+    case TEMPLATE_TEMPLATE_PARM:
     case TEMPLATE_CONST_PARM:
     case POINTER_TYPE:
     case REFERENCE_TYPE:
@@ -3850,6 +4055,79 @@ unify (tparms, targs, ntparms, parm, arg
 	return 1;
       targs[idx] = arg;
       return 0;
+
+    case TEMPLATE_TEMPLATE_PARM:
+      (*nsubsts)++;
+      idx = TEMPLATE_TYPE_IDX (parm);
+      /* Check for mixed types and values.  */
+      if (TREE_CODE (TREE_VALUE (TREE_VEC_ELT (tparms, idx))) != TEMPLATE_DECL)
+	return 1;
+
+      if (!strict && targs[idx] != NULL_TREE && 
+	  TREE_CODE (targs[idx]) == NOP_EXPR)
+	/* An explicit template argument.  Don't even try to match
+	   here; the overload resolution code will manage check to
+	   see whether the call is legal.  */ 
+	return 0;
+
+      if (CLASSTYPE_TEMPLATE_INFO (parm))
+	{
+	  /* We arrive here when PARM does not involve template 
+	     specialization.  */
+
+	  /* ARG must be constructed from a template class.  */
+	  if (TREE_CODE (arg) != RECORD_TYPE || !CLASSTYPE_TEMPLATE_INFO (arg))
+	    return 1;
+
+	  {
+	    tree parmtmpl = CLASSTYPE_TI_TEMPLATE (parm);
+	    tree parmvec = CLASSTYPE_TI_ARGS (parm);
+	    tree argvec = CLASSTYPE_TI_ARGS (arg);
+	    tree argtmplvec
+	      = DECL_INNERMOST_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (arg));
+	    int i, j;
+
+	    /* The parameter and argument roles have to be switched here 
+	       in order to handle default arguments properly.  For example, 
+		 template<template <class> class TT> void f(TT<int>) 
+	       should be able to accept vector<int> which comes from 
+		 template <class T, class Allcator = allocator> 
+		   class vector.  */
+
+	    if (coerce_template_parms (argtmplvec, parmvec, parmtmpl)
+		== error_mark_node)
+	      return 1;
+	  
+	    /* Deduce arguments T, i from TT<T> or TT<i>.  */
+	    for (i = 0; i < TREE_VEC_LENGTH (parmvec); ++i)
+	      {
+		tree t = TREE_VEC_ELT (parmvec, i);
+		if (TREE_CODE (t) != TEMPLATE_TYPE_PARM
+		    && TREE_CODE (t) != TEMPLATE_TEMPLATE_PARM
+		    && TREE_CODE (t) != TEMPLATE_CONST_PARM)
+		  continue;
+
+		/* This argument can be deduced.  */
+
+		if (unify (tparms, targs, ntparms, t, 
+			   TREE_VEC_ELT (argvec, i), nsubsts, strict))
+		  return 1;
+	      }
+	  }
+	  arg = CLASSTYPE_TI_TEMPLATE (arg);
+	}
+
+      /* Simple cases: Value already set, does match or doesn't.  */
+      if (targs[idx] == arg 
+	  || (targs[idx] 
+	      && TREE_CODE (targs[idx]) == NOP_EXPR 
+	      && TREE_OPERAND (targs[idx], 0) == arg))
+	return 0;
+      else if (targs[idx])
+	return 1;
+      targs[idx] = arg;
+      return 0;
+
     case TEMPLATE_CONST_PARM:
       (*nsubsts)++;
       idx = TEMPLATE_CONST_IDX (parm);
diff -rNpu3 gcc-old/cp/search.c gcc/cp/search.c
--- gcc-old/cp/search.c	Sat Jan 10 02:27:53 1998
+++ gcc/cp/search.c	Sat Jan 10 02:27:34 1998
@@ -2471,7 +2471,8 @@ dfs_walk (binfo, fn, qfn)
 
       if (qfn == 0 || (*qfn)(base_binfo))
 	{
-	  if (TREE_CODE (BINFO_TYPE (base_binfo)) == TEMPLATE_TYPE_PARM)
+	  if (TREE_CODE (BINFO_TYPE (base_binfo)) == TEMPLATE_TYPE_PARM
+	      || TREE_CODE (BINFO_TYPE (base_binfo)) == TEMPLATE_TEMPLATE_PARM)
 	    /* Pass */;
 	  else if (fn == dfs_init_vbase_pointers)
 	    {
@@ -3134,7 +3135,8 @@ dfs_record_inheritance (binfo)
       tree baseclass = BINFO_TYPE (base_binfo);
       mi_boolean *base_row = BINFO_DERIVES_FROM_STAR (base_binfo);
 
-      if (TREE_CODE (baseclass) == TEMPLATE_TYPE_PARM)
+      if (TREE_CODE (baseclass) == TEMPLATE_TYPE_PARM
+          || TREE_CODE (baseclass) == TEMPLATE_TEMPLATE_PARM)
 	continue;
       my_friendly_assert (CLASSTYPE_CID (baseclass) != 0, 2365);
 
diff -rNpu3 gcc-old/cp/tree.c gcc/cp/tree.c
--- gcc-old/cp/tree.c	Sat Jan 10 02:27:53 1998
+++ gcc/cp/tree.c	Sat Jan 10 02:27:34 1998
@@ -1438,6 +1438,27 @@ build_exception_variant (type, raises)
   return v;
 }
 
+/* Given a TEMPLATE_TEMPLATE_PARM node T, create a new one together with its 
+   lang_specific field and its corresponding TEMPLATE_DECL node */
+
+tree
+copy_template_template_parm (t)
+     tree t;
+{
+  tree template = TYPE_NAME (t);
+  tree t2 = make_lang_type (TEMPLATE_TEMPLATE_PARM);
+  template = copy_node (template);
+  copy_lang_decl (template);
+  TREE_TYPE (template) = t2;
+  TYPE_NAME (t2) = template;
+  TYPE_STUB_DECL (t2) = template;
+
+  /* No need to copy these */
+  TYPE_FIELDS (t2) = TYPE_FIELDS (t);
+  CLASSTYPE_TEMPLATE_INFO (t2) = CLASSTYPE_TEMPLATE_INFO (t);
+  return t2;
+}
+
 /* Subroutine of copy_to_permanent
 
    Assuming T is a node build bottom-up, make it all exist on
@@ -1624,6 +1645,9 @@ mapcar (t, func)
       t = copy_node (t);
       CONSTRUCTOR_ELTS (t) = mapcar (CONSTRUCTOR_ELTS (t), func);
       return t;
+
+    case TEMPLATE_TEMPLATE_PARM:
+      return copy_template_template_parm (t);
 
     case RECORD_TYPE:
       if (TYPE_PTRMEMFUNC_P (t))
diff -rNpu3 gcc-old/cp/typeck.c gcc/cp/typeck.c
--- gcc-old/cp/typeck.c	Sat Jan 10 02:27:54 1998
+++ gcc/cp/typeck.c	Tue Jan 13 17:10:31 1998
@@ -836,6 +836,37 @@ comptypes (type1, type2, strict)
       val = comp_array_types (comptypes, t1, t2, strict);
       break;
 
+    case TEMPLATE_TEMPLATE_PARM:
+      if (TEMPLATE_TYPE_IDX (t1) != TEMPLATE_TYPE_IDX (t2)
+	  || TEMPLATE_TYPE_LEVEL (t1) != TEMPLATE_TYPE_LEVEL (t2))
+	return 0;
+
+      if (CLASSTYPE_TEMPLATE_INFO (t1) && CLASSTYPE_TEMPLATE_INFO (t2))
+	{
+	  int i = TREE_VEC_LENGTH (CLASSTYPE_TI_ARGS (t1));
+	  tree *p1 = &TREE_VEC_ELT (CLASSTYPE_TI_ARGS (t1), 0);
+	  tree *p2 = &TREE_VEC_ELT (CLASSTYPE_TI_ARGS (t2), 0);
+	
+	  while (i--)
+	    {
+	      if (TREE_CODE_CLASS (TREE_CODE (p1[i])) == 't')
+		{
+		  if (! comptypes (p1[i], p2[i], 1))
+		    return 0;
+		}
+	      else
+		{
+		  if (simple_cst_equal (p1[i], p2[i]) <= 0)
+		    return 0;
+		}
+	    }
+	  return 1;
+	}
+      else if (CLASSTYPE_TEMPLATE_INFO (t1) || CLASSTYPE_TEMPLATE_INFO (t2))
+	return 0;
+      else
+	return 1;
+
     case TEMPLATE_TYPE_PARM:
       return TEMPLATE_TYPE_IDX (t1) == TEMPLATE_TYPE_IDX (t2)
 	&& TEMPLATE_TYPE_LEVEL (t1) == TEMPLATE_TYPE_LEVEL (t2);
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp1.C gcc/testsuite/g++.old-deja/g++.pt/ttp1.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp1.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp1.C	Sat Jan 10 02:29:46 1998
@@ -0,0 +1,14 @@
+// Build don't link:
+
+template<class E> class D
+{
+};
+
+template<template<class> class D,class E> class C
+{
+};
+
+int main()
+{
+	C<int,D> c;		// ERROR - args not match
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp10.C gcc/testsuite/g++.old-deja/g++.pt/ttp10.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp10.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp10.C	Sat Jan 10 02:29:46 1998
@@ -0,0 +1,30 @@
+// Build don't link:
+
+template<class T> class D
+{
+	public:
+		int f();
+};
+
+template<class T> int D<T>::f()
+{
+	return sizeof(T);
+}
+
+template<template<class> class D,class E> class C
+{
+		D d;			// ERROR - D is a template
+	public:
+		int f();
+};
+
+template<template<class> class D,class E> int C<D,E>::f()
+{
+	return d.f();			// ERROR - d not properly declared
+}
+
+int main()
+{
+	C<D,int> c;
+	c.f();
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp11.C gcc/testsuite/g++.old-deja/g++.pt/ttp11.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp11.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp11.C	Sat Jan 10 02:29:46 1998
@@ -0,0 +1,25 @@
+template<class T> class D
+{
+	public:
+		int f();
+};
+
+template<class T> int D<T>::f()
+{
+	return sizeof(T);
+}
+
+template<template<class> class D,class E> class C
+{
+		D<E> d;
+	public:
+		int f() { return d.f(); }
+};
+
+int main()
+{
+	C<D,int> c;
+	C<D,char> d;
+	c.f();
+	d.f();
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp12.C gcc/testsuite/g++.old-deja/g++.pt/ttp12.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp12.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp12.C	Sat Jan 10 02:29:46 1998
@@ -0,0 +1,28 @@
+template<class T> class D
+{
+	public:
+		int f();
+};
+
+template<class T> int D<T>::f()
+{
+	return sizeof(T);
+}
+
+template<template<class> class E,class D> class C
+{
+		E<D> d;
+	public:
+		int f();
+};
+
+template<template<class> class E,class D> int C<E,D>::f()
+{
+	return d.f();
+}
+
+int main()
+{
+	C<D,int> c;
+	c.f();
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp13.C gcc/testsuite/g++.old-deja/g++.pt/ttp13.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp13.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp13.C	Sat Jan 10 02:29:46 1998
@@ -0,0 +1,28 @@
+template<class T> class D
+{
+	public:
+		int f();
+};
+
+template<class T> int D<T>::f()
+{
+	return sizeof(T);
+}
+
+template<template<class> class D,class E> class C
+{
+		D<E> d;
+	public:
+		int f();
+};
+
+template<template<class> class D,class E> int C<D,E>::f()
+{
+	return d.f();
+}
+
+int main()
+{
+	C<D,int> c;
+	c.f();
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp14.C gcc/testsuite/g++.old-deja/g++.pt/ttp14.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp14.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp14.C	Sat Jan 10 02:29:46 1998
@@ -0,0 +1,30 @@
+template<class T> class D
+{
+	T	a;
+	public:
+		int f();
+};
+
+template<class T> int D<T>::f()
+{
+	return sizeof(T);
+}
+
+template<class E,template<class> class DD = D> class C
+{
+		DD<E> d;
+	public:
+		int f();
+};
+
+template<class E,template<class> class DD = D> int C<E,DD>::f()
+{
+	DD<E> d2;
+	return d2.f();
+}
+
+int main()
+{
+	C<int> c;
+	c.f();
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp15.C gcc/testsuite/g++.old-deja/g++.pt/ttp15.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp15.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp15.C	Sat Jan 10 02:29:46 1998
@@ -0,0 +1,29 @@
+template<class T> class D
+{
+	public:
+		int f();
+};
+
+template<class T> int D<T>::f()
+{
+	return sizeof(T);
+}
+
+template<template<class> class D,class E> class C
+{
+		D<E> d;
+	public:
+		int f();
+};
+
+template<template<class> class D,class E> int C<D,E>::f()
+{
+	D<E> d2;
+	return d2.f();
+}
+
+int main()
+{
+	C<D,int> c;
+	c.f();
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp16.C gcc/testsuite/g++.old-deja/g++.pt/ttp16.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp16.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp16.C	Sat Jan 10 02:29:46 1998
@@ -0,0 +1,30 @@
+template<class T> class D
+{
+	T	a;
+	public:
+		int f();
+};
+
+template<class T> int D<T>::f()
+{
+	return sizeof(T);
+}
+
+template<template<class> class D,class E> class C
+{
+		D<E> d;
+	public:
+		int f();
+};
+
+template<template<class> class D,class E> int C<D,E>::f()
+{
+	D<E> d2;
+	return d2.f();
+}
+
+int main()
+{
+	C<D,int> c;
+	c.f();
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp17.C gcc/testsuite/g++.old-deja/g++.pt/ttp17.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp17.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp17.C	Sat Jan 10 02:29:46 1998
@@ -0,0 +1,30 @@
+template<class T> class D
+{
+	public:
+		int f();
+};
+
+template<class T> int D<T>::f()
+{
+	return sizeof(T);
+}
+
+template<template<class> class D,class E> class C
+{
+		D<E> d;
+	public:
+		int f();
+		int g() { return 0; }
+};
+
+template<template<class> class D,class E> int C<D,E>::f()
+{
+	C<D,E> d2;
+	return d2.g();
+}
+
+int main()
+{
+	C<D,int> c;
+	c.f();
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp18.C gcc/testsuite/g++.old-deja/g++.pt/ttp18.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp18.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp18.C	Sat Jan 10 02:29:46 1998
@@ -0,0 +1,30 @@
+template<class T> class D
+{
+	public:
+		int f();
+};
+
+template<class T> int D<T>::f()
+{
+	return sizeof(T);
+}
+
+template<template<class> class D,class E> class C
+{
+		D<E> d;
+	public:
+		int f();
+		int g() { return 0; }
+};
+
+template<template<class> class D,class E> int C<D,E>::f()
+{
+	C<D,char> d2;
+	return d2.g();
+}
+
+int main()
+{
+	C<D,int> c;
+	c.f();
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp19.C gcc/testsuite/g++.old-deja/g++.pt/ttp19.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp19.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp19.C	Sat Jan 10 02:29:46 1998
@@ -0,0 +1,24 @@
+#include <vector>
+
+template<template<class> class D,class E> class C
+{
+		D<E> d;
+	public:
+		int size() { return d.size(); }
+};
+
+template<template<class> class D,class E> int size(D<E> &d1)
+{
+	d1.size();
+	C<D,E> d2;
+	d2.size();
+	return 0;
+}
+
+int main()
+{
+	std::vector<int> c1;
+	std::vector<char> c2;
+	size(c1);
+	size(c2);
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp2.C gcc/testsuite/g++.old-deja/g++.pt/ttp2.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp2.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp2.C	Sat Jan 10 02:29:46 1998
@@ -0,0 +1,14 @@
+// Build don't link:
+
+template<class E> class D
+{
+};
+
+template<template<class> class D,int> class C
+{
+};
+
+int main()
+{
+	C<1,D> c;		// ERROR - args not match
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp20.C gcc/testsuite/g++.old-deja/g++.pt/ttp20.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp20.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp20.C	Sat Jan 10 02:29:46 1998
@@ -0,0 +1,27 @@
+template<class T> class D
+{
+	public:
+		int f();
+};
+
+template<class T> int D<T>::f()
+{
+	return sizeof(T);
+}
+
+template<template<class> class D,class E> class C : D<E>
+{
+	public:
+		int g();
+};
+
+template<template<class> class D,class E> int C<D,E>::g()
+{
+	return f();
+}
+
+int main()
+{
+	C<D,int> c;
+	c.g();
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp21.C gcc/testsuite/g++.old-deja/g++.pt/ttp21.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp21.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp21.C	Sat Jan 10 02:29:46 1998
@@ -0,0 +1,33 @@
+template<class T> class D
+{
+	public:
+		int f();
+};
+
+template<class T> int D<T>::f()
+{
+	return sizeof(T);
+}
+
+template<template<class> class D,class E> class C : D<E>
+{
+	public:
+		int g();
+};
+
+template<template<class> class D,class E> int C<D,E>::g()
+{
+	return f();
+}
+
+class E : C<D,int>
+{
+	public:
+		int h() { return g(); }
+};
+
+int main()
+{
+	E c;
+	c.h();
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp22.C gcc/testsuite/g++.old-deja/g++.pt/ttp22.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp22.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp22.C	Sat Jan 10 02:29:46 1998
@@ -0,0 +1,33 @@
+template<class T> class D
+{
+	public:
+		int f();
+};
+
+template<class T> int D<T>::f()
+{
+	return sizeof(T);
+}
+
+template<template<class> class DD,class EE> class C : DD<EE>
+{
+	public:
+		int f();
+};
+
+template<template<class> class DD,class EE> int C<DD,EE>::f()
+{
+	return DD<EE>::f();
+}
+
+class E : C<D,int>
+{
+	public:
+		int f() { return C<D,int>::f(); }
+};
+
+int main()
+{
+	E c;
+	c.f();
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp23.C gcc/testsuite/g++.old-deja/g++.pt/ttp23.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp23.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp23.C	Tue Jan 13 17:13:16 1998
@@ -0,0 +1,33 @@
+template<class T> class D
+{
+	public:
+		int f();
+};
+
+template<class T> int D<T>::f()
+{
+	return sizeof(T);
+}
+
+template<template<class> class E,class D> class C : E<D>
+{
+	public:
+		int f();
+};
+
+template<template<class> class E,class D> int C<E,D>::f()
+{
+	return E<D>::f();
+}
+
+class E : C<D,int>
+{
+	public:
+		int f() { return C<D,int>::f(); }
+};
+
+int main()
+{
+	E c;
+	c.f();
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp24.C gcc/testsuite/g++.old-deja/g++.pt/ttp24.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp24.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp24.C	Sat Jan 10 02:29:46 1998
@@ -0,0 +1,22 @@
+template<class T> class D
+{
+	public:
+		int f();
+};
+
+template<class T> int D<T>::f()
+{
+	return sizeof(T);
+}
+
+template<template<class> class D,class E> int f()
+{
+	D<E> d;
+	return d.f();
+};
+
+int main()
+{
+	f<D,int>();
+	f<D,char>();
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp25.C gcc/testsuite/g++.old-deja/g++.pt/ttp25.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp25.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp25.C	Sat Jan 10 02:29:46 1998
@@ -0,0 +1,33 @@
+template<class T> class D
+{
+	public:
+		int f();
+};
+
+template<class T> int D<T>::f()
+{
+	return sizeof(T);
+}
+
+template<template<class> class D,class E> class C
+{
+		D<E> d;
+	public:
+		int f() { return d.f(); }
+};
+
+template<template<class> class D,class E> int f(D<E> &d1)
+{
+	d1.f();
+	C<D,E> d2;
+	d2.f();
+	return 0;
+}
+
+int main()
+{
+	D<int> c1;
+	D<char> c2;
+	f(c1);
+	f(c2);
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp26.C gcc/testsuite/g++.old-deja/g++.pt/ttp26.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp26.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp26.C	Sat Jan 10 02:29:46 1998
@@ -0,0 +1,33 @@
+template<class T, class U = int> class D
+{
+	public:
+		int f();
+};
+
+template<class T, class U> int D<T,U>::f()
+{
+	return sizeof(T)+sizeof(U);
+}
+
+template<template<class> class D,class E> class C
+{
+		D<E> d;
+	public:
+		int f() { return d.f(); }
+};
+
+template<template<class> class D,class E> int f(D<E> &d1)
+{
+	d1.f();
+	C<D,E> d2;
+	d2.f();
+	return 0;
+}
+
+int main()
+{
+	D<int> c1;
+	D<char> c2;
+	f(c1);
+	f(c2);
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp27.C gcc/testsuite/g++.old-deja/g++.pt/ttp27.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp27.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp27.C	Sat Jan 10 02:29:47 1998
@@ -0,0 +1,35 @@
+template<class T> class D
+{
+	public:
+		int f() const;
+};
+
+template<class T> int D<T>::f() const
+{
+	return sizeof(T);
+}
+
+template<template<class> class D,class E> class C
+{
+		D<E> d;
+	public:
+		int f() const { return d.f(); }
+};
+
+template<template<class> class D,class E> int f(const D<E> &d1)
+{
+	d1.f();
+	C<D,E> d2;
+	d2.f();
+	return 0;
+}
+
+int main()
+{
+	D<const int> c1;
+	D<char> c2;
+	const D<char> c3(c2);
+	f(c1);
+	f(c2);
+	f(c3);
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp28.C gcc/testsuite/g++.old-deja/g++.pt/ttp28.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp28.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp28.C	Sat Jan 10 02:29:47 1998
@@ -0,0 +1,39 @@
+template<class T> class D
+{
+	public:
+		int f();
+};
+
+template<class T> int D<T>::f()
+{
+	return sizeof(T);
+}
+
+template<template<class> class D,class E> class C
+{
+		D<E> d;
+	public:
+		int f() { return d.f(); }
+};
+
+template<template<class> class D,class E> int f(D<E> &d1)
+{
+	d1.f();
+	C<D,E> d2;
+	d2.f();
+	return 0;
+}
+
+template<> int f<>(D<char> &d1)
+{
+	d1.f();
+	return 0;
+}
+
+int main()
+{
+	D<int> c1;
+	D<char> c2;
+	f(c1);
+	f(c2);
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp29.C gcc/testsuite/g++.old-deja/g++.pt/ttp29.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp29.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp29.C	Sat Jan 10 02:29:47 1998
@@ -0,0 +1,32 @@
+template<class T> class D
+{
+	public:
+		int f();
+};
+
+template<class T> int D<T>::f()
+{
+	return sizeof(T);
+}
+
+extern "C" void abort();
+
+template<template<class> class D,class E> class C
+{
+		D<E> d;
+	public:
+		int f() { abort(); return 0; }
+};
+
+template<class E> class C<D,E>
+{
+		D<E> d;
+	public:
+		int f() { return d.f(); }
+};
+
+int main()
+{
+	C<D,int> c;
+	c.f();
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp3.C gcc/testsuite/g++.old-deja/g++.pt/ttp3.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp3.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp3.C	Sat Jan 10 02:29:47 1998
@@ -0,0 +1,14 @@
+// Build don't link:
+
+template<class E,class F> class D
+{
+};
+
+template<template<class> class D,class E> class C
+{				// ERROR - ref below
+};
+
+int main()
+{
+	C<D,int> c;		// ERROR - param list not match
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp30.C gcc/testsuite/g++.old-deja/g++.pt/ttp30.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp30.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp30.C	Sat Jan 10 02:29:47 1998
@@ -0,0 +1,37 @@
+template<class T> class D
+{
+	public:
+		int f();
+};
+
+template<class T> int D<T>::f()
+{
+	return sizeof(T);
+}
+
+extern "C" void abort();
+
+template<template<class> class D,class E> class C
+{
+		D<E> d;
+	public:
+		int f() { abort(); return 0; }
+};
+
+template<class E> class C<D,E>
+{
+		D<E> d;
+	public:
+		int f();
+};
+
+template<class E> int C<D,E>::f()
+{
+	return d.f();
+}
+
+int main()
+{
+	C<D,int> c;
+	c.f();
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp31.C gcc/testsuite/g++.old-deja/g++.pt/ttp31.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp31.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp31.C	Sat Jan 10 02:29:47 1998
@@ -0,0 +1,32 @@
+template<class T> class D
+{
+	public:
+		int f();
+};
+
+template<class T> int D<T>::f()
+{
+	return sizeof(T);
+}
+
+extern "C" void abort();
+
+template<template<class> class D,class E> class C
+{
+		D<E> d;
+	public:
+		int f() { abort(); return 0; }
+};
+
+template<template <class> class F> class C<F,int>
+{
+		F<int> d;
+	public:
+		int f() { return d.f(); }
+};
+
+int main()
+{
+	C<D,int> c;
+	c.f();
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp32.C gcc/testsuite/g++.old-deja/g++.pt/ttp32.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp32.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp32.C	Sat Jan 10 02:29:47 1998
@@ -0,0 +1,37 @@
+template<class T> class D
+{
+	public:
+		int f();
+};
+
+template<class T> int D<T>::f()
+{
+	return sizeof(T);
+}
+
+extern "C" void abort();
+
+template<template<class> class D,class E> class C
+{
+		D<E> d;
+	public:
+		int f() { abort(); return 0; }
+};
+
+template<template <class> class F> class C<F,int>
+{
+		F<int> d;
+	public:
+		int f();
+};
+
+template<template<class>class F> int C<F,int>::f()
+{
+	return d.f();
+}
+
+int main()
+{
+	C<D,int> c;
+	c.f();
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp33.C gcc/testsuite/g++.old-deja/g++.pt/ttp33.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp33.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp33.C	Sat Jan 10 03:40:49 1998
@@ -0,0 +1,31 @@
+template<class T> class D
+{
+	public:
+		int f();
+};
+
+template<class T> int D<T>::f()
+{
+	return sizeof(T);
+}
+
+template<template<class> class D,class E> class C
+{
+		D<E> d;
+	public:
+		template<template<class> class F> int f(F<int>);
+};
+
+template<template<class> class D,class E> 
+template<template<class> class F> int C<D,E>::f(F<int>)
+{
+	F<E> d2;
+	return d2.f();
+}
+
+int main()
+{
+	C<D,int> c;
+	D<int> d;
+	c.f(d);
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp34.C gcc/testsuite/g++.old-deja/g++.pt/ttp34.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp34.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp34.C	Sat Jan 10 04:01:11 1998
@@ -0,0 +1,31 @@
+template<class T> class D
+{
+	public:
+		int f();
+};
+
+template<class T> int D<T>::f()
+{
+	return sizeof(T);
+}
+
+template<template<class> class D,class E> class C
+{
+		D<E> d;
+	public:
+		int f();
+};
+
+template<template<class> class D,class E> int C<D,E>::f()
+{
+	D<E> d2;
+	return d2.f();
+}
+
+template class C<D,int>;
+
+int main()
+{
+	C<D,int> c;
+	c.f();
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp35.C gcc/testsuite/g++.old-deja/g++.pt/ttp35.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp35.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp35.C	Tue Jan 13 17:02:26 1998
@@ -0,0 +1,35 @@
+template<int T, class U = int> class D
+{
+	public:
+		int f();
+};
+
+template<int T, class U> int D<T,U>::f()
+{
+	return T+sizeof(U);
+}
+
+template<template<int> class D,class E> class C
+{
+		D<1> d;
+	public:
+		int f() { return d.f(); }
+};
+
+template<template<int> class D> int f(D<2> &d1)
+{
+	d1.f();
+	return 0;
+}
+
+template<template<int> class D> int f(D<1> &d1)
+{
+	d1.f();
+	return 0;
+}
+
+int main()
+{
+	D<1> c1;
+	f(c1);
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp36.C gcc/testsuite/g++.old-deja/g++.pt/ttp36.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp36.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp36.C	Tue Jan 13 17:02:20 1998
@@ -0,0 +1,29 @@
+template<int T, class U = int> class D
+{
+	public:
+		int f();
+};
+
+template<int T, class U> int D<T,U>::f()
+{
+	return T+sizeof(U);
+}
+
+template<template<int> class D,class E> class C
+{
+		D<1> d;
+	public:
+		int f() { return d.f(); }
+};
+
+template<template<int> class D> int f(D<1> &d1)
+{
+	d1.f();
+	return 0;
+}
+
+int main()
+{
+	D<1> c1;
+	f(c1);
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp37.C gcc/testsuite/g++.old-deja/g++.pt/ttp37.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp37.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp37.C	Tue Jan 13 17:02:10 1998
@@ -0,0 +1,29 @@
+template<int T, class U = int> class D
+{
+	public:
+		int f();
+};
+
+template<int T, class U> int D<T,U>::f()
+{
+	return T+sizeof(U);
+}
+
+template<template<int> class D,class E> class C
+{
+		D<1> d;
+	public:
+		int f() { return d.f(); }
+};
+
+template<template<int> class D, int T> int f(D<T> &d1)
+{
+	d1.f();
+	return T;
+}
+
+int main()
+{
+	D<1> c1;
+	f(c1);
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp38.C gcc/testsuite/g++.old-deja/g++.pt/ttp38.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp38.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp38.C	Tue Jan 13 17:02:04 1998
@@ -0,0 +1,29 @@
+template<class T, class U = int> class D
+{
+	public:
+		int f();
+};
+
+template<class T, class U> int D<T,U>::f()
+{
+	return sizeof(T)+sizeof(U);
+}
+
+template<template<class> class D,class E> class C
+{
+		D<E> d;
+	public:
+		int f() { return d.f(); }
+};
+
+template<template<class> class D> int f(D<int> &d1)
+{
+	d1.f();
+	return 0;
+}
+
+int main()
+{
+	D<int> c1;
+	f(c1);
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp4.C gcc/testsuite/g++.old-deja/g++.pt/ttp4.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp4.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp4.C	Sat Jan 10 02:29:47 1998
@@ -0,0 +1,15 @@
+// Build don't link:
+
+template<class E> class D
+{
+};
+
+template<template<class> class D,class E> class C
+{
+	D<1> d;			// ERROR - arg not match
+};
+
+int main()
+{
+	C<D,int> c;
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp5.C gcc/testsuite/g++.old-deja/g++.pt/ttp5.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp5.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp5.C	Sat Jan 10 02:29:47 1998
@@ -0,0 +1,15 @@
+// Build don't link:
+
+template<int> class D
+{
+};
+
+template<template<int> class D,class E> class C
+{
+	D<int> d;			// ERROR - arg not match
+};
+
+int main()
+{
+	C<D,int> c;
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp6.C gcc/testsuite/g++.old-deja/g++.pt/ttp6.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp6.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp6.C	Sat Jan 10 02:29:47 1998
@@ -0,0 +1,13 @@
+template<int> class F
+{
+};
+
+template<template<int> class D,class E> class C
+{
+	D<1> d;
+};
+
+int main()
+{
+	C<F,int> c;
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp7.C gcc/testsuite/g++.old-deja/g++.pt/ttp7.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp7.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp7.C	Sat Jan 10 02:29:47 1998
@@ -0,0 +1,15 @@
+// Build don't link:
+
+template<class E> class D
+{
+};
+
+template<template<class> class D,class E> class C	// ERROR - ref below
+{
+	D<int,int> d;				// ERROR - arg not match
+};
+
+int main()
+{
+	C<D,int> c;
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp8.C gcc/testsuite/g++.old-deja/g++.pt/ttp8.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp8.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp8.C	Sat Jan 10 02:29:47 1998
@@ -0,0 +1,17 @@
+template<class E> class DD
+{
+};
+
+template<int> class D
+{
+};
+
+template<template<class> class D,class E> class C
+{
+	D<E>	d;
+};
+
+int main()
+{
+	C<DD,int> c;
+}
diff -rNpu3 gcc-old/testsuite/g++.old-deja/g++.pt/ttp9.C gcc/testsuite/g++.old-deja/g++.pt/ttp9.C
--- gcc-old/testsuite/g++.old-deja/g++.pt/ttp9.C	Wed Dec 31 16:00:00 1969
+++ gcc/testsuite/g++.old-deja/g++.pt/ttp9.C	Sat Jan 10 02:29:47 1998
@@ -0,0 +1,13 @@
+template<class E,class F=int> class D
+{
+};
+
+template<template<class> class D,class E> class C
+{
+	D<E>	d;
+};
+
+int main()
+{
+	C<D,int> c;
+}




More information about the Gcc mailing list