cplus-dem.c (optable): Add sizeof.
authorMark Mitchell <mmitchell@usa.net>
Tue, 24 Mar 1998 10:25:44 +0000 (10:25 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Tue, 24 Mar 1998 10:25:44 +0000 (10:25 +0000)
* cplus-dem.c (optable): Add sizeof.
(demangle_template_value_parm): New function containing code
previously found in demangle_template.
(demangle_integral_value): New function which handles complicated
integral expressions.
(demangle_template): Use them.
* error.c (dump_expr): Remove unused variable `l'.
* pt.c (for_each_template_parm): New function, created by
converting uses_template_parms.
(tree_fn_t): New typedef.
(uses_template_parms): Use it.
(mark_template_parm): New function.
(push_template_decl): Check that the argument list of a partial
specialization uses all the template parameters.
* Make-lang.in (c++filt): Don't delete cxxmain.c after we're done
with it; we might want it for debugging.
* cp-tree.h (type_unification): Change interface.
* class.c (finish_struct_1): Skip nested template types, just like
ordinary nested types.
(instantiate_type): Use new interface to type_unification.
* lex.c (init_lex): Add __sz as opname for sizeof.
* method.c (build_overload_scope_ref): New function.
(build_overload_int): Handle complex expressions.  Set
numeric_output_need_bar if necessary.
(build_overload_value): Handle non-PARM_DECL nodes; this
routine is now used by build_overload_int.  Remove some
assignments to numeric_output_need_bar.  Use
build_overload_scope_ref.
(build_qualified_name): Note that some template mangled names end
with digits, and set numeric_output_need_bar appropriately.  Use
build_underscore_int.
* pt.c (unify): Change interface.
(type_unification_real): Likewise.
(determine_specialization): Use new interfaces.
(tsubst): Deal gracefully with situations in which the argument
vector is not fully filled.
(fn_type_unification): Use new interfaces.
(type_unification): Likewise.  Remove NOP_EXPR hack.
(type_unification_real): Likewise.
(unify): Likewise.  Deal with unification of complex expresions.

From-SVN: r18795

14 files changed:
gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/Make-lang.in
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/error.c
gcc/cp/method.c
gcc/cp/pt.c
gcc/cplus-dem.c
gcc/testsuite/g++.old-deja/g++.pt/crash4.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/expr1.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/expr2.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/expr3.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/expr4.C [new file with mode: 0644]

index fae898a9089e7653847202836cdb014ebc05a828..78a37f2f076ef22b6fac2ce1a22e391cf1bc5eae 100644 (file)
@@ -1,3 +1,12 @@
+1998-03-24  Mark Mitchell  <mmitchell@usa.net>
+
+       * cplus-dem.c (optable): Add sizeof.
+       (demangle_template_value_parm): New function containing code
+       previously found in demangle_template.
+       (demangle_integral_value): New function which handles complicated 
+       integral expressions.
+       (demangle_template): Use them.
+
 Tue Mar 24 12:13:18 1998  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
 
         * Makefile.in (genconfig.o, genflags.o, gencodes.o, genemit.o,
index 3ebc7f522cc061deb74fdfc594f9b3a7923b7814..320bcf6fc60ee7540072b07be098088f3e92f15f 100644 (file)
@@ -1,3 +1,42 @@
+Tue Mar 24 10:23:47 1998  Mark Mitchell  <mmitchell@usa.net>
+
+       * error.c (dump_expr): Remove unused variable `l'.
+
+       * pt.c (for_each_template_parm): New function, created by
+       converting uses_template_parms.
+       (tree_fn_t): New typedef.
+       (uses_template_parms): Use it.
+       (mark_template_parm): New function.
+       (push_template_decl): Check that the argument list of a partial
+       specialization uses all the template parameters.
+
+       * Make-lang.in (c++filt): Don't delete cxxmain.c after we're done
+       with it; we might want it for debugging.
+       * cp-tree.h (type_unification): Change interface.
+       * class.c (finish_struct_1): Skip nested template types, just like
+       ordinary nested types.
+       (instantiate_type): Use new interface to type_unification.
+       * lex.c (init_lex): Add __sz as opname for sizeof.
+       * method.c (build_overload_scope_ref): New function.
+       (build_overload_int): Handle complex expressions.  Set
+       numeric_output_need_bar if necessary.
+       (build_overload_value): Handle non-PARM_DECL nodes; this
+       routine is now used by build_overload_int.  Remove some
+       assignments to numeric_output_need_bar.  Use
+       build_overload_scope_ref.
+       (build_qualified_name): Note that some template mangled names end
+       with digits, and set numeric_output_need_bar appropriately.  Use
+       build_underscore_int.
+       * pt.c (unify): Change interface.
+       (type_unification_real): Likewise.
+       (determine_specialization): Use new interfaces.
+       (tsubst): Deal gracefully with situations in which the argument
+       vector is not fully filled.
+       (fn_type_unification): Use new interfaces.
+       (type_unification): Likewise.  Remove NOP_EXPR hack.
+       (type_unification_real): Likewise.
+       (unify): Likewise.  Deal with unification of complex expresions.
+
 Mon Mar 23 12:24:37 1998  Jason Merrill  <jason@yorick.cygnus.com>
 
        * pt.c (complete_template_args): Initialize skip properly.
index 6490c7e1d666f290209713fc5ce959337d7332ae..215bc950a524ff107431febe72a190066715968a 100644 (file)
@@ -107,7 +107,6 @@ cxxmain.o: cplus-dem.c demangle.h
        $(LN_S) $(srcdir)/cplus-dem.c cxxmain.c
        $(CC) -c -DMAIN $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
          -DVERSION=\"$(version)\" cxxmain.c
-       rm -f cxxmain.c
 
 $(DEMANGLER_PROG): cxxmain.o underscore.o getopt.o getopt1.o $(LIBDEPS)
        $(CC) $(ALL_CFLAGS) $(LDFLAGS) $(LIBS) -o $@ \
index 3cbf9ea3e689cc410d5d3454c97a7994f2fae17f..37f8086db445f5b38393994e8ce1cc5c52ff0165 100644 (file)
@@ -3322,7 +3322,8 @@ finish_struct_1 (t, warn_anon)
 
       last_x = x;
 
-      if (TREE_CODE (x) == TYPE_DECL)
+      if (TREE_CODE (x) == TYPE_DECL
+         || TREE_CODE (x) == TEMPLATE_DECL)
        continue;
 
       /* If we've gotten this far, it's a data member, possibly static,
@@ -5174,8 +5175,8 @@ instantiate_type (lhstype, rhs, complain)
                    tree t = make_scratch_vec (n);
                    int i;
                    i = type_unification
-                     (DECL_INNERMOST_TEMPLATE_PARMS (elem), 
-                      &TREE_VEC_ELT (t, 0), TYPE_ARG_TYPES (TREE_TYPE (elem)),
+                     (DECL_INNERMOST_TEMPLATE_PARMS (elem), t,
+                      TYPE_ARG_TYPES (TREE_TYPE (elem)),
                       TYPE_ARG_TYPES (lhstype), explicit_targs, 1, 1);
                    if (i == 0)
                      {
index 0c4cfcd78f8ded51caa1287530dc2a2cd508cd92..1d2d24764952940e2f402bdf45b84362571b6a86 100644 (file)
@@ -2463,7 +2463,7 @@ extern tree instantiate_class_template            PROTO((tree));
 extern tree instantiate_template               PROTO((tree, tree));
 extern void overload_template_name             PROTO((tree));
 extern int fn_type_unification                  PROTO((tree, tree, tree, tree, tree, int, tree));
-extern int type_unification                    PROTO((tree, tree *, tree, tree, tree, int, int));
+extern int type_unification                    PROTO((tree, tree, tree, tree, tree, int, int));
 struct tinst_level *tinst_for_decl             PROTO((void));
 extern void mark_decl_instantiated             PROTO((tree, int));
 extern int more_specialized                    PROTO((tree, tree, tree));
index 31a38bb52d33eed34b5c5a553e0bdf0fe4189d75..d97ed3804aa91da598d1617dba38f834c7ac32b9 100644 (file)
@@ -1533,12 +1533,7 @@ dump_expr (t, nop)
       }
 
     case TEMPLATE_PARM_INDEX:
-      {
-       int l = current_template_parms ? 
-         list_length (current_template_parms) : 0;
-
-       dump_decl (TEMPLATE_PARM_DECL (t), -1);
-      }
+      dump_decl (TEMPLATE_PARM_DECL (t), -1);
       break;
 
     case IDENTIFIER_NODE:
index 7efaf655c4828aa612235ec37f22405102590f5d..2b5059814c50d9f7fe736cf41e4114b23d3264a7 100644 (file)
@@ -471,6 +471,16 @@ build_underscore_int (i)
     OB_PUTC ('_');
 }
 
+static void
+build_overload_scope_ref (value)
+     tree value;
+{
+  OB_PUTC2 ('Q', '2');
+  numeric_output_need_bar = 0;
+  build_mangled_name (TREE_OPERAND (value, 0), 0, 0);
+  build_overload_identifier (TREE_OPERAND (value, 1));
+}
+
 /* Encoding for an INTEGER_CST value.  */
 
 static void
@@ -479,13 +489,70 @@ build_overload_int (value, in_template)
      int in_template;
 {
   if (in_template && TREE_CODE (value) != INTEGER_CST)
-    /* We don't ever want this output, but it's inconvenient not to
-       be able to build the string.  This should cause assembler
-       errors we'll notice.  */
     {
-      static int n;
-      sprintf (digit_buffer, " *%d", n++);
-      OB_PUTCP (digit_buffer);
+      if (TREE_CODE (value) == SCOPE_REF)
+       {
+         build_overload_scope_ref (value);
+         return;
+       }
+
+      OB_PUTC ('E');
+      numeric_output_need_bar = 0;
+
+      if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (value))))
+       {
+         int i;
+         int operands = tree_code_length[(int) TREE_CODE (value)];
+         tree id;
+         char* name;
+
+         id = ansi_opname [(int) TREE_CODE (value)];
+         my_friendly_assert (id != NULL_TREE, 0);
+         name = IDENTIFIER_POINTER (id);
+         my_friendly_assert (name[0] == '_' && name[1] == '_', 0);
+
+         for (i = 0; i < operands; ++i)
+           {
+             tree operand;
+             enum tree_code tc;
+
+             /* We just outputted either the `E' or the name of the
+                operator.  */
+             numeric_output_need_bar = 0;
+
+             if (i != 0)
+               /* Skip the leading underscores.  */
+               OB_PUTCP (name + 2);
+
+             operand = TREE_OPERAND (value, i);
+             tc = TREE_CODE (operand);
+
+             if (TREE_CODE_CLASS (tc) == 't')
+               /* We can get here with sizeof, e.g.:
+                    
+                  template <class T> void f(A<sizeof(T)>);  */
+               process_overload_item (operand, 0);
+             else if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (tc)))
+               build_overload_int (operand, in_template);
+             else
+               build_overload_value (TREE_TYPE (operand),
+                                     operand,
+                                     in_template);
+           }
+       }
+      else
+       {
+         /* We don't ever want this output, but it's
+            inconvenient not to be able to build the string.
+            This should cause assembler errors we'll notice.  */
+           
+         static int n;
+         sprintf (digit_buffer, " *%d", n++);
+         OB_PUTCP (digit_buffer);
+       }
+
+      OB_PUTC ('W');
+      numeric_output_need_bar = 0;
       return;
     }
 
@@ -497,12 +564,14 @@ build_overload_int (value, in_template)
        {
          /* need to print a DImode value in decimal */
          dicat (TREE_INT_CST_LOW (value), TREE_INT_CST_HIGH (value));
+         numeric_output_need_bar = 1;
          return;
        }
       /* else fall through to print in smaller mode */
     }
   /* Wordsize or smaller */
   icat (TREE_INT_CST_LOW (value));
+  numeric_output_need_bar = 1;
 }
 
 
@@ -531,8 +600,11 @@ build_overload_value (type, value, in_template)
   while (TREE_CODE (value) == NON_LVALUE_EXPR
         || TREE_CODE (value) == NOP_EXPR)
     value = TREE_OPERAND (value, 0);
-  my_friendly_assert (TREE_CODE (type) == PARM_DECL, 242);
-  type = TREE_TYPE (type);
+
+  if (TREE_CODE (type) == PARM_DECL)
+    type = TREE_TYPE (type);
+
+  my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (type)) == 't', 0);
 
   if (numeric_output_need_bar)
     {
@@ -569,7 +641,6 @@ build_overload_value (type, value, in_template)
     case BOOLEAN_TYPE:
       {
        build_overload_int (value, in_template);
-       numeric_output_need_bar = 1;
        return;
       }
     case REAL_TYPE:
@@ -672,7 +743,6 @@ build_overload_value (type, value, in_template)
                    {
                      OB_PUTC ('i');
                      build_overload_int (a3, in_template);
-                     numeric_output_need_bar = 1;
                      return;
                    }
                }
@@ -683,7 +753,6 @@ build_overload_value (type, value, in_template)
       if (TREE_CODE (value) == INTEGER_CST)
        {
          build_overload_int (value, in_template);
-         numeric_output_need_bar = 1;
          return;
        }
       else if (TREE_CODE (value) == TEMPLATE_PARM_INDEX)
@@ -707,13 +776,7 @@ build_overload_value (type, value, in_template)
          return;
        }
       else if (TREE_CODE (value) == SCOPE_REF)
-       {
-         OB_PUTC2 ('Q', '1');
-         numeric_output_need_bar = 0;
-         build_mangled_name (TREE_OPERAND (value, 0), 0, 0);
-         build_overload_identifier (TREE_OPERAND (value, 1));
-         return;
-       }
+       build_overload_scope_ref (value);
       else
        my_friendly_abort (71);
       break; /* not really needed */
@@ -865,7 +928,10 @@ build_qualified_name (decl)
   if (TREE_CODE (decl) == TYPE_DECL
       && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl) && !flag_do_squangling)
     {
-      OB_PUTID (DECL_ASSEMBLER_NAME (decl));
+      tree id = DECL_ASSEMBLER_NAME (decl);
+      OB_PUTID (id);
+      if (isdigit (IDENTIFIER_POINTER (id) [IDENTIFIER_LENGTH (id) - 1]))
+       numeric_output_need_bar = 1;
       return;
     }
 
@@ -907,11 +973,7 @@ build_qualified_name (decl)
   if (i > 1)
     {
       OB_PUTC ('Q');
-      if (i > 9)
-       OB_PUTC ('_');
-      icat (i);
-      if (i > 9)
-       OB_PUTC ('_');
+      build_underscore_int (i);
       numeric_output_need_bar = 0;
     }
   build_overload_nested_name (decl);
index 6ea32092644c0b5e533c12ffc05a46047575453a..2e44007b3c508abf295b2d70f14f791a93379263 100644 (file)
@@ -43,6 +43,10 @@ Boston, MA 02111-1307, USA.  */
 #include <stdlib.h>
 #endif
 
+/* The type of functions taking a tree, and some additional data, and
+   returning an int.  */
+typedef int (*tree_fn_t) PROTO((tree, void*));
+
 extern struct obstack permanent_obstack;
 
 extern int lineno;
@@ -69,7 +73,7 @@ static tree saved_trees;
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 
-static int unify PROTO((tree, tree *, int, tree, tree, int));
+static int unify PROTO((tree, tree, int, tree, tree, int, int*));
 static void add_pending_template PROTO((tree));
 static int push_tinst_level PROTO((tree));
 static tree classtype_mangled_name PROTO((tree));
@@ -81,13 +85,14 @@ static tree get_class_bindings PROTO((tree, tree, tree, tree));
 static tree coerce_template_parms PROTO((tree, tree, tree, int, int, int));
 static tree tsubst_enum        PROTO((tree, tree, tree *));
 static tree add_to_template_args PROTO((tree, tree));
+static int  type_unification_real PROTO((tree, tree, tree, tree,
+                                        int, int, int, int*));
 static tree complete_template_args PROTO((tree, tree, int));
-static int  type_unification_real PROTO((tree, tree *, tree, tree,
-                                        int, int, int));
 static void note_template_header PROTO((int));
 static tree maybe_fold_nontype_arg PROTO((tree));
 static tree convert_nontype_argument PROTO((tree, tree));
 static tree get_bindings_overload PROTO((tree, tree, tree));
+static int for_each_template_parm PROTO((tree, tree_fn_t, void*));
 
 /* Do any processing required when DECL (a member template declaration
    using TEMPLATE_PARAMETERS as its innermost parameter list) is
@@ -719,7 +724,7 @@ determine_specialization (template_id, decl, targs_out,
          /* We allow incomplete unification here, because we are going to
             check all the functions. */
          i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (tmpl),
-                               &TREE_VEC_ELT (targs, 0),
+                               targs,
                                NULL_TREE,
                                NULL_TREE,  
                                targs_in,
@@ -1464,7 +1469,46 @@ build_template_decl (decl, parms)
   return tmpl;
 }
 
-  
+struct template_parm_data
+{
+  int level;
+  int* parms;
+};
+
+/* Subroutine of push_template_decl used to see if each template
+   parameter in a partial specialization is used in the explicit
+   argument list.  If T is of the LEVEL given in DATA (which is
+   treated as a template_parm_data*), then DATA->PARMS is marked
+   appropriately.  */
+
+static int
+mark_template_parm (t, data)
+     tree t;
+     void* data;
+{
+  int level;
+  int idx;
+  struct template_parm_data* tpd = (struct template_parm_data*) data;
+
+  if (TREE_CODE (t) == TEMPLATE_PARM_INDEX)
+    {
+      level = TEMPLATE_PARM_LEVEL (t);
+      idx = TEMPLATE_PARM_IDX (t);
+    }
+  else
+    {
+      level = TEMPLATE_TYPE_LEVEL (t);
+      idx = TEMPLATE_TYPE_IDX (t);
+    }
+
+  if (level == tpd->level)
+    tpd->parms[idx] = 1;
+
+  /* Return zero so that for_each_template_parm will continue the
+     traversal of the tree; we want to mark *every* template parm.  */
+  return 0;
+}
+
 /* Creates a TEMPLATE_DECL for the indicated DECL using the template
    parameters given by current_template_args, or reuses a
    previously existing one, if appropriate.  Returns the DECL, or an
@@ -1529,6 +1573,66 @@ push_template_decl (decl)
       tree mainargs = CLASSTYPE_TI_ARGS (type);
       tree spec = DECL_TEMPLATE_SPECIALIZATIONS (maintmpl);
 
+      /* We check that each of the template parameters given in the
+        partial specialization is used in the argument list to the
+        specialization.  For example:
+        
+          template <class T> struct S;
+          template <class T> struct S<T*>;
+
+        The second declaration is OK because `T*' uses the template
+        parameter T, whereas
+       
+           template <class T> struct S<int>;
+
+        is no good.  Even trickier is:
+
+          template <class T>
+          struct S1
+          {
+             template <class U>
+             struct S2;
+             template <class U>
+             struct S2<T>;
+          };
+          
+        The S2<T> declaration is actually illegal; it is a
+        full-specialization.  Of course, 
+
+              template <class U>
+              struct S2<T (*)(U)>;
+
+         or some such would have been OK.  */
+      int  i;
+      struct template_parm_data tpd;
+      int ntparms = TREE_VEC_LENGTH (TREE_VALUE (current_template_parms));
+      int did_error_intro = 0;
+
+      tpd.level = TREE_INT_CST_HIGH (TREE_PURPOSE (current_template_parms));
+      tpd.parms = alloca (sizeof (int) * ntparms);
+      for (i = 0; i < ntparms; ++i)
+       tpd.parms[i] = 0;
+      for (i = 0; i < TREE_VEC_LENGTH (mainargs); ++i)
+       for_each_template_parm (TREE_VEC_ELT (mainargs, i),
+                               &mark_template_parm,
+                               &tpd);
+      for (i = 0; i < ntparms; ++i)
+       if (tpd.parms[i] == 0)
+         {
+           /* One of the template parms was not used in the
+              specialization.  */
+           if (!did_error_intro)
+             {
+               cp_error ("template parameters not used in partial specialization:");
+               did_error_intro = 1;
+             }
+
+           cp_error ("        `%D'", 
+                     TREE_VALUE (TREE_VEC_ELT 
+                                 (TREE_VALUE (current_template_parms),
+                                  i)));
+         }
+
       for (; spec; spec = TREE_CHAIN (spec))
        {
          /* purpose: args to main template
@@ -2505,6 +2609,8 @@ tree
 lookup_template_function (fns, arglist)
      tree fns, arglist;
 {
+  tree t;
+
   if (fns == NULL_TREE)
     {
       cp_error ("non-template used as template");
@@ -2737,9 +2843,19 @@ lookup_template_class (d1, arglist, in_decl, context)
 /* Should be defined in parse.h.  */
 extern int yychar;
 
+/* For each TEMPLATE_TYPE_PARM, TEMPLATE_TEMPLATE_PARM, or
+   TEMPLATE_PARM_INDEX in T, call FN with the parameter and the DATA.
+   If FN returns non-zero, the iteration is terminated, and
+   for_each_template_parm returns 1.  Otherwise, the iteration
+   continues.  If FN never returns a non-zero value, the value
+   returned by for_each_template_parm is 0.  If FN is NULL, it is
+   considered to be the function which always returns 1.  */
+
 int
-uses_template_parms (t)
+for_each_template_parm (t, fn, data)
      tree t;
+     tree_fn_t fn;
+     void* data;
 {
   if (!t)
     return 0;
@@ -2750,7 +2866,7 @@ uses_template_parms (t)
       /* We assume that the object must be instantiated in order to build
         the COMPONENT_REF, so we test only whether the type of the
         COMPONENT_REF uses template parms.  */
-      return uses_template_parms (TREE_TYPE (t));
+      return for_each_template_parm (TREE_TYPE (t), fn, data);
 
     case IDENTIFIER_NODE:
       if (!IDENTIFIER_TEMPLATE (t))
@@ -2762,49 +2878,52 @@ uses_template_parms (t)
       {
        int i = TREE_VEC_LENGTH (t);
        while (i--)
-         if (uses_template_parms (TREE_VEC_ELT (t, i)))
+         if (for_each_template_parm (TREE_VEC_ELT (t, i), fn, data))
            return 1;
        return 0;
       }
     case TREE_LIST:
-      if (uses_template_parms (TREE_PURPOSE (t))
-         || uses_template_parms (TREE_VALUE (t)))
+      if (for_each_template_parm (TREE_PURPOSE (t), fn, data)
+         || for_each_template_parm (TREE_VALUE (t), fn, data))
        return 1;
-      return uses_template_parms (TREE_CHAIN (t));
+      return for_each_template_parm (TREE_CHAIN (t), fn, data);
 
       /* constructed type nodes */
     case POINTER_TYPE:
     case REFERENCE_TYPE:
-      return uses_template_parms (TREE_TYPE (t));
+      return for_each_template_parm (TREE_TYPE (t), fn, data);
     case RECORD_TYPE:
       if (TYPE_PTRMEMFUNC_FLAG (t))
-       return uses_template_parms (TYPE_PTRMEMFUNC_FN_TYPE (t));
+       return for_each_template_parm (TYPE_PTRMEMFUNC_FN_TYPE (t),
+                                      fn, data);
     case UNION_TYPE:
       if (! CLASSTYPE_TEMPLATE_INFO (t))
        return 0;
-      return uses_template_parms (TREE_VALUE (CLASSTYPE_TEMPLATE_INFO (t)));
+      return for_each_template_parm (TREE_VALUE
+                                    (CLASSTYPE_TEMPLATE_INFO (t)),
+                                    fn, data);
     case FUNCTION_TYPE:
-      if (uses_template_parms (TYPE_ARG_TYPES (t)))
+      if (for_each_template_parm (TYPE_ARG_TYPES (t), fn, data))
        return 1;
-      return uses_template_parms (TREE_TYPE (t));
+      return for_each_template_parm (TREE_TYPE (t), fn, data);
     case ARRAY_TYPE:
-      if (uses_template_parms (TYPE_DOMAIN (t)))
+      if (for_each_template_parm (TYPE_DOMAIN (t), fn, data))
        return 1;
-      return uses_template_parms (TREE_TYPE (t));
+      return for_each_template_parm (TREE_TYPE (t), fn, data);
     case OFFSET_TYPE:
-      if (uses_template_parms (TYPE_OFFSET_BASETYPE (t)))
+      if (for_each_template_parm (TYPE_OFFSET_BASETYPE (t), fn, data))
        return 1;
-      return uses_template_parms (TREE_TYPE (t));
+      return for_each_template_parm (TREE_TYPE (t), fn, data);
     case METHOD_TYPE:
-      if (uses_template_parms (TYPE_METHOD_BASETYPE (t)))
+      if (for_each_template_parm (TYPE_METHOD_BASETYPE (t), fn, data))
        return 1;
-      if (uses_template_parms (TYPE_ARG_TYPES (t)))
+      if (for_each_template_parm (TYPE_ARG_TYPES (t), fn, data))
        return 1;
-      return uses_template_parms (TREE_TYPE (t));
+      return for_each_template_parm (TREE_TYPE (t), fn, data);
 
       /* decl nodes */
     case TYPE_DECL:
-      return uses_template_parms (TREE_TYPE (t));
+      return for_each_template_parm (TREE_TYPE (t), fn, data);
 
     case TEMPLATE_DECL:
       /* A template template parameter is encountered */
@@ -2816,7 +2935,7 @@ uses_template_parms (t)
       return 0;
       
     case CONST_DECL:
-      if (uses_template_parms (DECL_INITIAL (t)))
+      if (for_each_template_parm (DECL_INITIAL (t), fn, data))
        return 1;
       goto check_type_and_context;
 
@@ -2824,33 +2943,37 @@ uses_template_parms (t)
     case VAR_DECL:
       /* ??? What about FIELD_DECLs?  */
       if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t)
-         && uses_template_parms (DECL_TI_ARGS (t)))
+         && for_each_template_parm (DECL_TI_ARGS (t), fn, data))
        return 1;
       /* fall through */
     case PARM_DECL:
     check_type_and_context:
-      if (uses_template_parms (TREE_TYPE (t)))
+      if (for_each_template_parm (TREE_TYPE (t), fn, data))
        return 1;
-      if (DECL_CONTEXT (t) && uses_template_parms (DECL_CONTEXT (t)))
+      if (DECL_CONTEXT (t) 
+         && for_each_template_parm (DECL_CONTEXT (t), fn, data))
        return 1;
       return 0;
 
     case CALL_EXPR:
-      return uses_template_parms (TREE_TYPE (t));
+      return for_each_template_parm (TREE_TYPE (t), fn, data);
     case ADDR_EXPR:
-      return uses_template_parms (TREE_OPERAND (t, 0));
+      return for_each_template_parm (TREE_OPERAND (t, 0), fn, data);
 
       /* template parm nodes */
     case TEMPLATE_TYPE_PARM:
     case TEMPLATE_TEMPLATE_PARM:
     case TEMPLATE_PARM_INDEX:
-      return 1;
+      if (fn)
+       return (*fn)(t, data);
+      else
+       return 1;
 
       /* simple type nodes */
     case INTEGER_TYPE:
-      if (uses_template_parms (TYPE_MIN_VALUE (t)))
+      if (for_each_template_parm (TYPE_MIN_VALUE (t), fn, data))
        return 1;
-      return uses_template_parms (TYPE_MAX_VALUE (t));
+      return for_each_template_parm (TYPE_MAX_VALUE (t), fn, data);
 
     case REAL_TYPE:
     case COMPLEX_TYPE:
@@ -2863,7 +2986,7 @@ uses_template_parms (t)
        tree v;
 
        for (v = TYPE_VALUES (t); v != NULL_TREE; v = TREE_CHAIN (v))
-         if (uses_template_parms (TREE_VALUE (v)))
+         if (for_each_template_parm (TREE_VALUE (v), fn, data))
            return 1;
       }
       return 0;
@@ -2885,12 +3008,13 @@ uses_template_parms (t)
       return 1;
 
     case SCOPE_REF:
-      return uses_template_parms (TREE_OPERAND (t, 0));
+      return for_each_template_parm (TREE_OPERAND (t, 0), fn, data);
 
     case CONSTRUCTOR:
       if (TREE_TYPE (t) && TYPE_PTRMEMFUNC_P (TREE_TYPE (t)))
-       return uses_template_parms (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (t)));
-      return uses_template_parms (TREE_OPERAND (t, 1));
+       return for_each_template_parm (TYPE_PTRMEMFUNC_FN_TYPE
+                                      (TREE_TYPE (t)), fn, data);
+      return for_each_template_parm (TREE_OPERAND (t, 1), fn, data);
 
     case MODOP_EXPR:
     case CAST_EXPR:
@@ -2905,7 +3029,7 @@ uses_template_parms (t)
 
     case SIZEOF_EXPR:
     case ALIGNOF_EXPR:
-      return uses_template_parms (TREE_OPERAND (t, 0));
+      return for_each_template_parm (TREE_OPERAND (t, 0), fn, data);
 
     default:
       switch (TREE_CODE_CLASS (TREE_CODE (t)))
@@ -2917,7 +3041,7 @@ uses_template_parms (t)
          {
            int i;
            for (i = tree_code_length[(int) TREE_CODE (t)]; --i >= 0;)
-             if (uses_template_parms (TREE_OPERAND (t, i)))
+             if (for_each_template_parm (TREE_OPERAND (t, i), fn, data))
                return 1;
            return 0;
          }
@@ -2932,6 +3056,13 @@ uses_template_parms (t)
     }
 }
 
+int
+uses_template_parms (t)
+     tree t;
+{
+  return for_each_template_parm (t, 0, 0);
+}
+
 static struct tinst_level *current_tinst_level = 0;
 static struct tinst_level *free_tinst_level = 0;
 static int tinst_depth = 0;
@@ -3549,7 +3680,7 @@ tsubst (t, args, in_decl)
          r = lookup_template_class (t, argvec, in_decl, context);
 
          return cp_build_type_variant (r, TYPE_READONLY (t),
-                                       TYPE_VOLATILE (t));
+                               TYPE_VOLATILE (t));
        }
 
       /* else fall through */
@@ -3625,7 +3756,8 @@ tsubst (t, args, in_decl)
          {
            tree arg = NULL_TREE;
 
-           if (TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
+           if (TREE_VEC_ELT (args, 0) != NULL_TREE
+               && TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
              {
                levels = TREE_VEC_LENGTH (args);
                if (level <= levels)
@@ -3678,12 +3810,15 @@ tsubst (t, args, in_decl)
              }
          }
 
+       if (level == 1)
+         /* This can happen during the attempted tsubst'ing in
+            unify.  This means that we don't yet have any information
+            about the template parameter in question.  */
+         return t;
+
        /* If we get here, we must have been looking at a parm for a
-          more deeply nested template.  */
-       my_friendly_assert(level > 1, 0);
-       
-       /* Make a new version of this template parameter, but with a
-          lower level.  */
+          more deeply nested template.  Make a new version of this
+          template parameter, but with a lower level.  */
        switch (TREE_CODE (t))
          {
          case TEMPLATE_TYPE_PARM:
@@ -5111,7 +5246,7 @@ fn_type_unification (fn, explicit_targs, targs, args, return_type,
                                      fn_arg_types); 
 
   i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (fn), 
-                       &TREE_VEC_ELT (targs, 0), 
+                       targs,
                        fn_arg_types,
                        decl_arg_types,
                        explicit_targs,
@@ -5147,15 +5282,17 @@ fn_type_unification (fn, explicit_targs, targs, args, return_type,
 int
 type_unification (tparms, targs, parms, args, targs_in,
                  strict, allow_incomplete)
-     tree tparms, *targs, parms, args, targs_in;
+     tree tparms, targs, parms, args, targs_in;
      int strict, allow_incomplete;
 {
   int ntparms = TREE_VEC_LENGTH (tparms);
   tree arg;
+  int* explicit_mask;
   int i;
   int r;
 
-  bzero ((char *) targs, sizeof (tree) * ntparms);
+  for (i = 0; i < ntparms; i++)
+    TREE_VEC_ELT (targs, i) = NULL_TREE;
 
   if (targs_in != NULL_TREE)
     {
@@ -5166,34 +5303,38 @@ type_unification (tparms, targs, parms, args, targs_in,
       if (arg_vec == error_mark_node)
        return 1;
 
+      explicit_mask = alloca (sizeof (int) * TREE_VEC_LENGTH (targs));
+      bzero (explicit_mask, sizeof(int) * TREE_VEC_LENGTH (targs));
+
       for (i = 0; 
           i < TREE_VEC_LENGTH (arg_vec) 
-            && TREE_VEC_ELT (arg_vec, i) != NULL_TREE; 
+            && TREE_VEC_ELT (arg_vec, i) != NULL_TREE;  
           ++i)
-       /* Insert the template argument.  It is encoded as the operands
-          of NOP_EXPRs so that unify can tell that it is an explicit
-          arguments.  */
-       targs[i] = build1 (NOP_EXPR, NULL_TREE, TREE_VEC_ELT (arg_vec, i));
+       {
+         TREE_VEC_ELT (targs, i) = TREE_VEC_ELT (arg_vec, i);
+         /* Let unify know that this argument was explicit.  */
+         explicit_mask [i] = 1;
+       }
     }
-  
-  r = type_unification_real (tparms, targs, parms, args, 0,
-                            strict, allow_incomplete); 
+  else
+    explicit_mask = 0;
 
-  for (i = 0, arg = targs_in; 
-       arg != NULL_TREE; 
-       arg = TREE_CHAIN (arg), ++i)
-    if (TREE_CODE (targs[i]) == NOP_EXPR)
-      targs[i] = TREE_OPERAND (targs[i], 0);
+  r = type_unification_real (tparms, targs, parms, args, 0,
+                            strict, allow_incomplete, explicit_mask); 
 
   return r;
 }
 
+/* Like type_unfication.  EXPLICIT_MASK, if non-NULL, is an array of
+   integers, with ones in positions corresponding to arguments in
+   targs that were provided explicitly, and zeros elsewhere.  */
 
 static int
 type_unification_real (tparms, targs, parms, args, subr,
-                      strict, allow_incomplete)
-     tree tparms, *targs, parms, args;
+                      strict, allow_incomplete, explicit_mask)
+     tree tparms, targs, parms, args;
      int subr, strict, allow_incomplete;
+     int* explicit_mask;
 {
   tree parm, arg;
   int i;
@@ -5267,12 +5408,12 @@ type_unification_real (tparms, targs, parms, args, subr,
              && TREE_CODE (TREE_VALUE (arg)) == TEMPLATE_DECL)
            {
              int ntparms;
-             tree *targs;
+             tree targs;
 
              /* Have to back unify here */
              arg = TREE_VALUE (arg);
              ntparms = DECL_NTPARMS (arg);
-             targs = (tree *) alloca (sizeof (tree) * ntparms);
+             targs = make_scratch_vec (ntparms);
              parm = expr_tree_cons (NULL_TREE, parm, NULL_TREE);
              return 
                type_unification (DECL_INNERMOST_TEMPLATE_PARMS (arg), 
@@ -5304,7 +5445,8 @@ type_unification_real (tparms, targs, parms, args, subr,
            arg = TYPE_MAIN_VARIANT (arg);
        }
 
-      switch (unify (tparms, targs, ntparms, parm, arg, strict))
+      switch (unify (tparms, targs, ntparms, parm, arg, strict,
+                    explicit_mask)) 
        {
        case 0:
          break;
@@ -5323,7 +5465,7 @@ type_unification_real (tparms, targs, parms, args, subr,
     return 1;
   if (!subr)
     for (i = 0; i < ntparms; i++)
-      if (!targs[i])
+      if (TREE_VEC_ELT (targs, i) == NULL_TREE)
        {
          if (!allow_incomplete)
            error ("incomplete type unification");
@@ -5335,11 +5477,13 @@ type_unification_real (tparms, targs, parms, args, subr,
 /* Tail recursion is your friend.  */
 
 static int
-unify (tparms, targs, ntparms, parm, arg, strict)
-     tree tparms, *targs, parm, arg;
+unify (tparms, targs, ntparms, parm, arg, strict, explicit_mask)
+     tree tparms, targs, parm, arg;
      int ntparms, strict;
+     int* explicit_mask;
 {
   int idx;
+  tree targ;
 
   /* I don't think this will do the right thing with respect to types.
      But the only case I've seen it in so far has been array bounds, where
@@ -5372,12 +5516,13 @@ unify (tparms, targs, ntparms, parm, arg, strict)
 
     case TEMPLATE_TYPE_PARM:
       idx = TEMPLATE_TYPE_IDX (parm);
+      targ = TREE_VEC_ELT (targs, idx);
       /* Check for mixed types and values.  */
       if (TREE_CODE (TREE_VALUE (TREE_VEC_ELT (tparms, idx))) != TYPE_DECL)
        return 1;
 
-      if (!strict && targs[idx] != NULL_TREE && 
-         TREE_CODE (targs[idx]) == NOP_EXPR)
+      if (!strict && targ != NULL_TREE 
+         && explicit_mask && explicit_mask[idx])
        /* 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.  */ 
@@ -5402,24 +5547,23 @@ unify (tparms, targs, ntparms, parm, arg, strict)
       }
 #endif
       /* 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))
+      if (targ == arg || (targ && explicit_mask && explicit_mask[idx]))
        return 0;
-      else if (targs[idx])
+      else if (targ)
        return 1;
-      targs[idx] = arg;
+      TREE_VEC_ELT (targs, idx) = arg;
       return 0;
 
     case TEMPLATE_TEMPLATE_PARM:
       idx = TEMPLATE_TYPE_IDX (parm);
+      targ = TREE_VEC_ELT (targs, idx);
+
       /* 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)
+      if (!strict && targ != NULL_TREE 
+         && explicit_mask && explicit_mask[idx])
        /* 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.  */ 
@@ -5465,7 +5609,7 @@ unify (tparms, targs, ntparms, parm, arg, strict)
                /* This argument can be deduced.  */
 
                if (unify (tparms, targs, ntparms, t, 
-                          TREE_VEC_ELT (argvec, i), strict))
+                          TREE_VEC_ELT (argvec, i), strict, explicit_mask))
                  return 1;
              }
          }
@@ -5473,21 +5617,19 @@ unify (tparms, targs, ntparms, parm, arg, strict)
        }
 
       /* 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))
+      if (targ == arg || (targ && explicit_mask && explicit_mask[idx]))
        return 0;
-      else if (targs[idx])
+      else if (targ)
        return 1;
-      targs[idx] = arg;
+      TREE_VEC_ELT (targs, idx) = arg;
       return 0;
 
     case TEMPLATE_PARM_INDEX:
       idx = TEMPLATE_PARM_IDX (parm);
-      if (targs[idx])
+      targ = TREE_VEC_ELT (targs, idx);
+      if (targ)
        {
-         int i = cp_tree_equal (targs[idx], arg);
+         int i = cp_tree_equal (targ, arg);
          if (i == 1)
            return 0;
          else if (i == 0)
@@ -5496,24 +5638,24 @@ unify (tparms, targs, ntparms, parm, arg, strict)
            my_friendly_abort (42);
        }
 
-      targs[idx] = copy_to_permanent (arg);
+      TREE_VEC_ELT (targs, idx) = copy_to_permanent (arg);
       return 0;
 
     case POINTER_TYPE:
       if (TREE_CODE (arg) == RECORD_TYPE && TYPE_PTRMEMFUNC_FLAG (arg))
        return unify (tparms, targs, ntparms, parm,
-                     TYPE_PTRMEMFUNC_FN_TYPE (arg), strict);
+                     TYPE_PTRMEMFUNC_FN_TYPE (arg), strict, explicit_mask);
 
       if (TREE_CODE (arg) != POINTER_TYPE)
        return 1;
       return unify (tparms, targs, ntparms, TREE_TYPE (parm), TREE_TYPE (arg),
-                   strict);
+                   strict, explicit_mask);
 
     case REFERENCE_TYPE:
       if (TREE_CODE (arg) == REFERENCE_TYPE)
        arg = TREE_TYPE (arg);
       return unify (tparms, targs, ntparms, TREE_TYPE (parm), arg,
-                   strict);
+                   strict, explicit_mask);
 
     case ARRAY_TYPE:
       if (TREE_CODE (arg) != ARRAY_TYPE)
@@ -5523,10 +5665,10 @@ unify (tparms, targs, ntparms, parm, arg, strict)
        return 1;
       if (TYPE_DOMAIN (parm) != NULL_TREE
          && unify (tparms, targs, ntparms, TYPE_DOMAIN (parm),
-                   TYPE_DOMAIN (arg), strict) != 0)
+                   TYPE_DOMAIN (arg), strict, explicit_mask) != 0)
        return 1;
       return unify (tparms, targs, ntparms, TREE_TYPE (parm), TREE_TYPE (arg),
-                   strict);
+                   strict, explicit_mask);
 
     case REAL_TYPE:
     case COMPLEX_TYPE:
@@ -5540,11 +5682,11 @@ unify (tparms, targs, ntparms, parm, arg, strict)
        {
          if (TYPE_MIN_VALUE (parm) && TYPE_MIN_VALUE (arg)
              && unify (tparms, targs, ntparms, TYPE_MIN_VALUE (parm),
-                       TYPE_MIN_VALUE (arg), strict))
+                       TYPE_MIN_VALUE (arg), strict, explicit_mask))
            return 1;
          if (TYPE_MAX_VALUE (parm) && TYPE_MAX_VALUE (arg)
              && unify (tparms, targs, ntparms, TYPE_MAX_VALUE (parm),
-                       TYPE_MAX_VALUE (arg), strict))
+                       TYPE_MAX_VALUE (arg), strict, explicit_mask))
            return 1;
        }
       else if (TREE_CODE (parm) == REAL_TYPE
@@ -5565,16 +5707,6 @@ unify (tparms, targs, ntparms, parm, arg, strict)
        return 1;
       return !tree_int_cst_equal (parm, arg);
 
-    case MINUS_EXPR:
-      {
-       tree t1, t2;
-       t1 = TREE_OPERAND (parm, 0);
-       t2 = TREE_OPERAND (parm, 1);
-       return unify (tparms, targs, ntparms, t1,
-                     fold (build (PLUS_EXPR, integer_type_node, arg, t2)),
-                     strict);
-      }
-
     case TREE_VEC:
       {
        int i;
@@ -5585,7 +5717,7 @@ unify (tparms, targs, ntparms, parm, arg, strict)
        for (i = TREE_VEC_LENGTH (parm) - 1; i >= 0; i--)
          if (unify (tparms, targs, ntparms,
                     TREE_VEC_ELT (parm, i), TREE_VEC_ELT (arg, i),
-                    strict))
+                    strict, explicit_mask))
            return 1;
        return 0;
       }
@@ -5593,7 +5725,7 @@ unify (tparms, targs, ntparms, parm, arg, strict)
     case RECORD_TYPE:
       if (TYPE_PTRMEMFUNC_FLAG (parm))
        return unify (tparms, targs, ntparms, TYPE_PTRMEMFUNC_FN_TYPE (parm),
-                     arg, strict);
+                     arg, strict, explicit_mask);
 
       /* Allow trivial conversions.  */
       if (TREE_CODE (arg) != RECORD_TYPE
@@ -5614,7 +5746,7 @@ unify (tparms, targs, ntparms, parm, arg, strict)
            return 1;
 
          return unify (tparms, targs, ntparms, CLASSTYPE_TI_ARGS (parm),
-                       CLASSTYPE_TI_ARGS (t), strict);
+                       CLASSTYPE_TI_ARGS (t), strict, explicit_mask);
        }
       else if (TYPE_MAIN_VARIANT (parm) != TYPE_MAIN_VARIANT (arg))
        return 1;
@@ -5630,20 +5762,20 @@ unify (tparms, targs, ntparms, parm, arg, strict)
        return 1;
      check_args:
       if (unify (tparms, targs, ntparms, TREE_TYPE (parm),
-                TREE_TYPE (arg), strict))
+                TREE_TYPE (arg), strict, explicit_mask))
        return 1;
       return type_unification_real (tparms, targs, TYPE_ARG_TYPES (parm),
                                    TYPE_ARG_TYPES (arg), 1, 
-                                   strict, 0);
+                                   strict, 0, explicit_mask);
 
     case OFFSET_TYPE:
       if (TREE_CODE (arg) != OFFSET_TYPE)
        return 1;
       if (unify (tparms, targs, ntparms, TYPE_OFFSET_BASETYPE (parm),
-                TYPE_OFFSET_BASETYPE (arg), strict))
+                TYPE_OFFSET_BASETYPE (arg), strict, explicit_mask))
        return 1;
       return unify (tparms, targs, ntparms, TREE_TYPE (parm),
-                   TREE_TYPE (arg), strict);
+                   TREE_TYPE (arg), strict, explicit_mask);
 
     case CONST_DECL:
       if (arg != decl_constant_value (parm))
@@ -5655,8 +5787,65 @@ unify (tparms, targs, ntparms, parm, arg, strict)
       return 1;
 
     default:
-      sorry ("use of `%s' in template type unification",
-            tree_code_name [(int) TREE_CODE (parm)]);
+      if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (parm))))
+       {
+         /* We're looking at an expression.  This can happen with
+            something like:
+
+              template <int I>
+              void foo(S<I>, S<I + 2>);
+
+             If the call looked like:
+
+               foo(S<2>(), S<4>());
+
+            we would have already matched `I' with `2'.  Now, we'd
+            like to know if `4' matches `I + 2'.  So, we substitute
+            into that expression, and fold constants, in the hope of
+            figuring it out.  */
+         tree t = 
+           maybe_fold_nontype_arg (tsubst_expr (parm, targs, NULL_TREE)); 
+         enum tree_code tc = TREE_CODE (t);
+
+         if (tc == MINUS_EXPR 
+             && TREE_CODE (TREE_OPERAND (t, 0)) == TEMPLATE_PARM_INDEX
+             && TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST)
+           {
+             /* We handle this case specially, since it comes up with
+                arrays.  In particular, something like:
+
+                template <int N> void f(int (&x)[N]);
+
+                Here, we are trying to unify the range type, which
+                looks like [0 ... (N - 1)].  */
+             tree t1, t2;
+             t1 = TREE_OPERAND (parm, 0);
+             t2 = TREE_OPERAND (parm, 1);
+
+             t = maybe_fold_nontype_arg (build (PLUS_EXPR,
+                                                integer_type_node,
+                                                arg, t2));
+
+             return unify (tparms, targs, ntparms, t1, t,
+                           strict, explicit_mask);
+           }
+
+         if (!IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (tc)))
+           /* Good, we mangaged to simplify the exression.  */
+           return unify (tparms, targs, ntparms, t, arg, strict,
+                         explicit_mask);
+         else
+           /* Bad, we couldn't simplify this.  Assume it doesn't
+              unify.  */
+           return 1;
+       }
+      else
+       {
+         sorry ("use of `%s' in template type unification",
+                tree_code_name [(int) TREE_CODE (parm)]);
+         break;
+       }
+
       return 1;
     }
 }
@@ -5837,8 +6026,9 @@ get_class_bindings (tparms, parms, args, outer_args)
 
   for (i = 0; i < TREE_VEC_LENGTH (parms); ++i)
     {
-      switch (unify (tparms, &TREE_VEC_ELT (vec, 0), ntparms,
-                    TREE_VEC_ELT (parms, i), TREE_VEC_ELT (args, i), 1))
+      switch (unify (tparms, vec, ntparms,
+                    TREE_VEC_ELT (parms, i), TREE_VEC_ELT (args, i),
+                    1, 0))
        {
        case 0:
          break;
index af9244909f7081240a197959513f2861ed3e3f9f..898ab4bd500c490534a6042e8fde1990e3fa7ef5 100644 (file)
@@ -197,7 +197,8 @@ static const struct optable
   {"min",        "<?",         0},             /* old */
   {"mn",         "<?",         DMGL_ANSI},     /* pseudo-ansi */
   {"nop",        "",           0},             /* old (for operator=) */
-  {"rm",         "->*",        DMGL_ANSI}      /* ansi */
+  {"rm",         "->*",        DMGL_ANSI},     /* ansi */
+  {"sz",          "sizeof ",    DMGL_ANSI}      /* pseudo-ansi */
 };
 
 
@@ -330,6 +331,10 @@ forget_types PARAMS ((struct work_stuff *));
 static void
 string_prepends PARAMS ((string *, string *));
 
+static int 
+demangle_template_value_parm PARAMS ((struct work_stuff*, 
+                                     const char**, string*)); 
+
 /*  Translate count to integer, consuming tokens in the process.
     Conversion terminates on the first non-digit character.
     Trying to consume something that isn't a count results in
@@ -995,6 +1000,270 @@ demangle_template_template_parm (work, mangled, tname)
   return (success);
 }
 
+static int
+demangle_integral_value (work, mangled, s)
+     struct work_stuff *work;
+     const char** mangled;
+     string* s;
+{
+  int success;
+
+  if (**mangled == 'E')
+    {
+      int need_operator = 0;
+      
+      success = 1;
+      string_appendn (s, "(", 1);
+      (*mangled)++;
+      while (success && **mangled != 'W' && **mangled != '\0')
+       {
+         if (need_operator)
+           {
+             size_t i;
+             size_t len;
+
+             success = 0;
+
+             len = strlen (*mangled);
+
+             for (i = 0; 
+                  i < sizeof (optable) / sizeof (optable [0]);
+                  ++i)
+               {
+                 size_t l = strlen (optable[i].in);
+
+                 if (l <= len
+                     && memcmp (optable[i].in, *mangled, l) == 0)
+                   {
+                     string_appendn (s, " ", 1);
+                     string_append (s, optable[i].out);
+                     string_appendn (s, " ", 1);
+                     success = 1;
+                     (*mangled) += l;
+                     break;
+                   }
+               }
+
+             if (!success)
+               break;
+           }
+         else
+           need_operator = 1;
+
+         success = demangle_template_value_parm (work, mangled, s);
+       }
+
+      if (**mangled != 'W')
+         success = 0;
+      else 
+       {
+         string_appendn (s, ")", 1);
+         (*mangled)++;
+       }
+    }
+  else if (**mangled == 'Q')
+    success = demangle_qualified (work, mangled, s, 0, 1);
+  else
+    {
+      success = 0;
+
+      if (**mangled == 'm')
+       {
+         string_appendn (s, "-", 1);
+         (*mangled)++;
+       }
+      while (isdigit (**mangled))      
+       {
+         string_appendn (s, *mangled, 1);
+         (*mangled)++;
+         success = 1;
+       }
+    }
+  
+  return success;
+}
+
+static int 
+demangle_template_value_parm (work, mangled, s)
+     struct work_stuff *work;
+     const char **mangled;
+     string* s;
+{
+  const char *old_p = *mangled;
+  int is_pointer = 0;
+  int is_real = 0;
+  int is_integral = 0;
+  int is_char = 0;
+  int is_bool = 0;
+  int done = 0;
+  int success = 1;
+
+  while (*old_p && !done)
+    {  
+      switch (*old_p)
+       {
+       case 'P':
+       case 'p':
+       case 'R':
+         done = is_pointer = 1;
+         break;
+       case 'C':       /* const */
+       case 'S':       /* explicitly signed [char] */
+       case 'U':       /* unsigned */
+       case 'V':       /* volatile */
+       case 'F':       /* function */
+       case 'M':       /* member function */
+       case 'O':       /* ??? */
+       case 'J':       /* complex */
+         old_p++;
+         continue;
+       case 'E':       /* expression */
+       case 'Q':       /* qualified name */
+         done = is_integral = 1;
+         break;
+       case 'T':       /* remembered type */
+         abort ();
+         break;
+       case 'v':       /* void */
+         abort ();
+         break;
+       case 'x':       /* long long */
+       case 'l':       /* long */
+       case 'i':       /* int */
+       case 's':       /* short */
+       case 'w':       /* wchar_t */
+         done = is_integral = 1;
+         break;
+       case 'b':       /* bool */
+         done = is_bool = 1;
+         break;
+       case 'c':       /* char */
+         done = is_char = 1;
+         break;
+       case 'r':       /* long double */
+       case 'd':       /* double */
+       case 'f':       /* float */
+         done = is_real = 1;
+         break;
+       default:
+         /* it's probably user defined type, let's assume
+            it's integral, it seems hard to figure out
+            what it really is */
+         done = is_integral = 1;
+       }
+    }
+  if (**mangled == 'Y')
+    {
+      /* The next argument is a template parameter. */
+      int idx;
+
+      (*mangled)++;
+      idx = consume_count_with_underscores (mangled);
+      if (idx == -1 
+         || (work->tmpl_argvec && idx >= work->ntmpl_args)
+         || consume_count_with_underscores (mangled) == -1)
+       return -1;
+      if (work->tmpl_argvec)
+       string_append (s, work->tmpl_argvec[idx]);
+      else
+       {
+         char buf[10];
+         sprintf(buf, "T%d", idx);
+         string_append (s, buf);
+       }
+    }
+  else if (is_integral)
+    success = demangle_integral_value (work, mangled, s);
+  else if (is_char)
+    {
+      char tmp[2];
+      int val;
+      if (**mangled == 'm')
+       {
+         string_appendn (s, "-", 1);
+         (*mangled)++;
+       }
+      string_appendn (s, "'", 1);
+      val = consume_count(mangled);
+      if (val == 0)
+       return -1;
+      tmp[0] = (char)val;
+      tmp[1] = '\0';
+      string_appendn (s, &tmp[0], 1);
+      string_appendn (s, "'", 1);
+    }
+  else if (is_bool)
+    {
+      int val = consume_count (mangled);
+      if (val == 0)
+       string_appendn (s, "false", 5);
+      else if (val == 1)
+       string_appendn (s, "true", 4);
+      else
+       success = 0;
+    }
+  else if (is_real)
+    {
+      if (**mangled == 'm')
+       {
+         string_appendn (s, "-", 1);
+         (*mangled)++;
+       }
+      while (isdigit (**mangled))      
+       {
+         string_appendn (s, *mangled, 1);
+         (*mangled)++;
+       }
+      if (**mangled == '.') /* fraction */
+       {
+         string_appendn (s, ".", 1);
+         (*mangled)++;
+         while (isdigit (**mangled))   
+           {
+             string_appendn (s, *mangled, 1);
+             (*mangled)++;
+           }
+       }
+      if (**mangled == 'e') /* exponent */
+       {
+         string_appendn (s, "e", 1);
+         (*mangled)++;
+         while (isdigit (**mangled))   
+           {
+             string_appendn (s, *mangled, 1);
+             (*mangled)++;
+           }
+       }
+    }
+  else if (is_pointer)
+    {
+      int symbol_len = consume_count (mangled);
+      if (symbol_len == 0)
+       return -1;
+      if (symbol_len == 0)
+       string_appendn (s, "0", 1);
+      else
+       {
+         char *p = xmalloc (symbol_len + 1), *q;
+         strncpy (p, *mangled, symbol_len);
+         p [symbol_len] = '\0';
+         q = cplus_demangle (p, work->options);
+         string_appendn (s, "&", 1);
+         if (q)
+           {
+             string_append (s, q);
+             free (q);
+           }
+         else
+           string_append (s, p);
+         free (p);
+       }
+      *mangled += symbol_len;
+    }
+
+  return success;
+}
+
 static int
 demangle_template (work, mangled, tname, trawname, is_type)
      struct work_stuff *work;
@@ -1004,18 +1273,10 @@ demangle_template (work, mangled, tname, trawname, is_type)
      int is_type;
 {
   int i;
-  int is_pointer;
-  int is_real;
-  int is_integral;
-  int is_char;
-  int is_bool;
   int r;
   int need_comma = 0;
   int success = 0;
-  int done;
-  const char *old_p;
   const char *start;
-  int symbol_len;
   int is_java_array = 0;
   string temp;
 
@@ -1148,13 +1409,7 @@ demangle_template (work, mangled, tname, trawname, is_type)
          string* s;
 
          /* otherwise, value parameter */
-         old_p  = *mangled;
-         is_pointer = 0;
-         is_real = 0;
-         is_integral = 0;
-          is_char = 0;
-         is_bool = 0;
-         done = 0;
+
          /* temp is initialized in do_type */
          success = do_type (work, mangled, &temp);
          /*
@@ -1180,193 +1435,16 @@ demangle_template (work, mangled, tname, trawname, is_type)
          else
            s = tname;
 
-         while (*old_p && !done)
-           {   
-             switch (*old_p)
-               {
-               case 'P':
-               case 'p':
-               case 'R':
-                 done = is_pointer = 1;
-                 break;
-               case 'C':       /* const */
-               case 'S':       /* explicitly signed [char] */
-               case 'U':       /* unsigned */
-               case 'V':       /* volatile */
-               case 'F':       /* function */
-               case 'M':       /* member function */
-               case 'O':       /* ??? */
-               case 'J':       /* complex */
-                 old_p++;
-                 continue;
-               case 'Q':       /* qualified name */
-                 done = is_integral = 1;
-                 break;
-               case 'T':       /* remembered type */
-                 abort ();
-                 break;
-               case 'v':       /* void */
-                 abort ();
-                 break;
-               case 'x':       /* long long */
-               case 'l':       /* long */
-               case 'i':       /* int */
-               case 's':       /* short */
-               case 'w':       /* wchar_t */
-                 done = is_integral = 1;
-                 break;
-               case 'b':       /* bool */
-                 done = is_bool = 1;
-                 break;
-               case 'c':       /* char */
-                 done = is_char = 1;
-                 break;
-               case 'r':       /* long double */
-               case 'd':       /* double */
-               case 'f':       /* float */
-                 done = is_real = 1;
-                 break;
-               default:
-                 /* it's probably user defined type, let's assume
-                    it's integral, it seems hard to figure out
-                    what it really is */
-                 done = is_integral = 1;
-               }
-           }
-         if (**mangled == 'Y')
-           {
-             /* The next argument is a template parameter. */
-             int idx;
+         success = demangle_template_value_parm (work, mangled, s);
 
-             (*mangled)++;
-             idx = consume_count_with_underscores (mangled);
-             if (idx == -1 
-                 || (work->tmpl_argvec && idx >= work->ntmpl_args)
-                 || consume_count_with_underscores (mangled) == -1)
-               {
-                 success = 0;
-                 if (!is_type)
-                   string_delete (s);
-                 break;
-               }
-             if (work->tmpl_argvec)
-               string_append (s, work->tmpl_argvec[idx]);
-             else
-               {
-                 char buf[10];
-                 sprintf(buf, "T%d", idx);
-                 string_append (s, buf);
-               }
-           }
-         else if (is_integral)
-           {
-             if (**mangled == 'm')
-               {
-                 string_appendn (s, "-", 1);
-                 (*mangled)++;
-               }
-             while (isdigit (**mangled))       
-               {
-                 string_appendn (s, *mangled, 1);
-                 (*mangled)++;
-               }
-           }
-         else if (is_char)
-           {
-             char tmp[2];
-             int val;
-              if (**mangled == 'm')
-                {
-                  string_appendn (s, "-", 1);
-                  (*mangled)++;
-                }
-             string_appendn (s, "'", 1);
-              val = consume_count(mangled);
-             if (val == 0)
-               {
-                 success = 0;
-                 if (!is_type)
-                   string_delete (s);
-                 break;
-                }
-              tmp[0] = (char)val;
-              tmp[1] = '\0';
-              string_appendn (s, &tmp[0], 1);
-             string_appendn (s, "'", 1);
-           }
-         else if (is_bool)
-           {
-             int val = consume_count (mangled);
-             if (val == 0)
-               string_appendn (s, "false", 5);
-             else if (val == 1)
-               string_appendn (s, "true", 4);
-             else
-               success = 0;
-           }
-         else if (is_real)
-           {
-             if (**mangled == 'm')
-               {
-                 string_appendn (s, "-", 1);
-                 (*mangled)++;
-               }
-             while (isdigit (**mangled))       
-               {
-                 string_appendn (s, *mangled, 1);
-                 (*mangled)++;
-               }
-             if (**mangled == '.') /* fraction */
-               {
-                 string_appendn (s, ".", 1);
-                 (*mangled)++;
-                 while (isdigit (**mangled))   
-                   {
-                     string_appendn (s, *mangled, 1);
-                     (*mangled)++;
-                   }
-               }
-             if (**mangled == 'e') /* exponent */
-               {
-                 string_appendn (s, "e", 1);
-                 (*mangled)++;
-                 while (isdigit (**mangled))   
-                   {
-                     string_appendn (s, *mangled, 1);
-                     (*mangled)++;
-                   }
-               }
-           }
-         else if (is_pointer)
+         if (!success)
            {
-             symbol_len = consume_count (mangled);
-             if (symbol_len == 0)
-               {
-                 success = 0;
-                 if (!is_type)
-                   string_delete (s);
-                 break;
-               }
-             if (symbol_len == 0)
-               string_appendn (s, "0", 1);
-             else
-               {
-                 char *p = xmalloc (symbol_len + 1), *q;
-                 strncpy (p, *mangled, symbol_len);
-                 p [symbol_len] = '\0';
-                 q = cplus_demangle (p, work->options);
-                 string_appendn (s, "&", 1);
-                 if (q)
-                   {
-                     string_append (s, q);
-                     free (q);
-                   }
-                 else
-                   string_append (s, p);
-                 free (p);
-               }
-             *mangled += symbol_len;
+             if (!is_type)
+               string_delete (s);
+             success = 0;
+             break;
            }
+
          if (!is_type)
            {
              int len = s->p - s->b;
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash4.C b/gcc/testsuite/g++.old-deja/g++.pt/crash4.C
new file mode 100644 (file)
index 0000000..510d4cd
--- /dev/null
@@ -0,0 +1,11 @@
+// Build don't link:
+
+template <unsigned rank>
+class Tensor
+{
+};
+
+template <unsigned rank>
+class Tensor<2> : Tensor<rank> { // ERROR - template parameters not used
+};
+
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/expr1.C b/gcc/testsuite/g++.old-deja/g++.pt/expr1.C
new file mode 100644 (file)
index 0000000..cdb8687
--- /dev/null
@@ -0,0 +1,33 @@
+template <int n> class vec {
+    double x[n];
+
+    public:
+    vec() {
+ for (int i=0; i<n-1; ++i) x[i]=0;
+    }
+
+    vec(const vec<n>& v) {
+ for (int i=0; i<n; ++i) x[i]=v(i);
+    }
+
+    vec(const vec<n-1>& v, const double& y) {
+ for (int i=0; i<n-1; ++i) x[i]=v(i);
+ x[n-1]=y;
+    }
+
+    inline double operator()(const int i) const {
+ return x[i];
+    }
+};
+
+
+template <int n> vec<n + 1>& operator,(const vec<n>& v, const double& y) {
+    return *(new vec<n + 1>(v, y));
+}
+
+
+int main() {
+    vec<4> v;
+    vec<5> w;
+    w=(v,3.);
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/expr2.C b/gcc/testsuite/g++.old-deja/g++.pt/expr2.C
new file mode 100644 (file)
index 0000000..d6e5593
--- /dev/null
@@ -0,0 +1,12 @@
+// Build don't link:
+
+template <int I>
+struct S {};
+
+template <int J>
+void foo(S<J + 2>);
+
+void bar()
+{
+  foo(S<3>()); // ERROR - no way to deduce J from this.
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/expr3.C b/gcc/testsuite/g++.old-deja/g++.pt/expr3.C
new file mode 100644 (file)
index 0000000..4d77370
--- /dev/null
@@ -0,0 +1,20 @@
+// Build don't link:
+
+template <int I>
+struct S {};
+
+template <int J>
+void foo(S<J - 1>);
+
+template <class T>
+void baz(S<sizeof(T)>);
+
+template <int J>
+void fun(S<J>, S<J * 2>);
+
+void bar()
+{
+  foo<5>(S<4>()); // OK - 4 is 5 - 1.
+  baz<int>(S<sizeof(int)>()); // OK
+  fun(S<4>(), S<8>()); // OK - deduce J from first argument.
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/expr4.C b/gcc/testsuite/g++.old-deja/g++.pt/expr4.C
new file mode 100644 (file)
index 0000000..13298fe
--- /dev/null
@@ -0,0 +1,373 @@
+template<class View, class W>
+class TinyContainer {
+public:
+
+  typedef W T_Wrapped;
+
+  TinyContainer() { }
+  TinyContainer(View data) : m_data(data) { }
+
+  T_Wrapped &unwrap() 
+  { 
+    return *static_cast<T_Wrapped *>(this);
+  }
+  const T_Wrapped &unwrap() const 
+  { 
+    return *static_cast<const T_Wrapped *>(this);
+  }
+
+protected:
+
+  mutable View m_data;
+};
+
+template<class Op, class Left, class Right>
+class TinyBinaryExpr :
+  public TinyContainer< Op, TinyBinaryExpr<Op, Left, Right> > {
+public:
+
+  typedef typename Left::T_Return T_Return;
+  typedef TinyBinaryExpr<Op, Left, Right> T_Expr;
+  
+  T_Expr makeExpr() const { return *this; }
+
+  TinyBinaryExpr(const Op &op, const Left &left, const Right &right)
+  : TinyContainer< Op, TinyBinaryExpr<Op, Left, Right> >(op),
+    m_left(left), m_right(right)
+  { }
+
+  TinyBinaryExpr(const Left &left, const Right &right)
+  : m_left(left), m_right(right)
+  { }
+  
+  Op op() const { return m_data; }
+  Left left() const { return m_left; }
+  Right right() const { return m_right; }
+
+private:
+
+  Left m_left;
+  Right m_right;
+};
+
+struct OpAdd {
+
+  template<class T1, class T2>
+  static T1 apply(const T1 &l, const T2 &r)
+  {
+    return l + r;
+  }
+
+};
+
+template<class V1, class T1, class V2, class T2>
+inline TinyBinaryExpr<OpAdd, typename T1::T_Expr, typename T2::T_Expr>
+operator+(const TinyContainer<V1,T1>& l, const TinyContainer<V2,T2>& r)
+{
+  typedef TinyBinaryExpr<OpAdd, typename T1::T_Expr, typename T2::T_Expr> ret;
+  return ret(l.unwrap().makeExpr(), r.unwrap().makeExpr());
+}
+
+
+template<class Op, class T1, class T2, class Functor>
+inline
+typename T1::T_Return
+for_each(const TinyBinaryExpr<Op,T1,T2>& node, Functor f)
+{
+  return Op::apply(for_each(node.left(),f), for_each(node.right(),f));
+}
+
+template<class T, unsigned Nrows, unsigned Ncols, unsigned S1, unsigned S2>
+class DenseDataView
+  : public TinyContainer< T*, DenseDataView<T, Nrows, Ncols, S1, S2> > {
+public:
+
+  typedef T T_Return;
+  typedef DenseDataView<T, Nrows, Ncols, S1, S2> T_Expr;
+
+  T_Expr makeExpr() const { return *this; }
+
+  T *beginLoc(unsigned i, unsigned j) const 
+  { return m_data + S1 * i + S2 * j; }
+
+  DenseDataView(T *pData) 
+  : TinyContainer< T*, DenseDataView<T, Nrows, Ncols, S1, S2> >(pData) { }
+
+  T &offset(unsigned i, unsigned j)
+  {
+    return m_data[S1 * i + S2 * j];
+  }
+
+  T offset(unsigned i, unsigned j) const
+  {
+    return m_data[S1 * i + S2 * j];
+  }
+
+  template<unsigned I, unsigned J>
+  struct Offset {
+
+    static T &apply(DenseDataView<T, Nrows, Ncols, S1, S2> &d)
+    {
+      return d.m_data[S1 * I + S2 * J];
+    }
+
+    static T constApply(const DenseDataView<T, Nrows, Ncols, S1, S2> &d)
+    {
+      return d.m_data[S1 * I + S2 * J];
+    }
+
+  };
+
+};
+
+template<unsigned I, unsigned J>
+struct Eval2 { };
+
+template<class T, unsigned Nrows, unsigned Ncols, unsigned S1, unsigned S2,
+  unsigned I, unsigned J>
+inline T
+for_each(const DenseDataView<T, Nrows, Ncols, S1, S2> &d, 
+  const Eval2<I,J> &e)
+{
+  return d.offset(I, J);
+}
+
+template<class T, unsigned Nrows, unsigned Ncols>
+class DenseData
+  : public TinyContainer< T[Nrows * Ncols], DenseData<T, Nrows, Ncols> > {
+public:
+
+  typedef T T_Return;
+  typedef DenseDataView<T, Nrows, Ncols, 1, Nrows> T_Expr;
+
+  T_Expr makeExpr() const { return T_Expr(m_data); }
+
+  T *beginLoc(unsigned i, unsigned j) const 
+  { return &m_data[i + Nrows * j]; }
+
+  T &operator[](unsigned i)
+  {
+    return m_data[i];
+  }
+
+  T operator[](unsigned i) const
+  {
+    return m_data[i];
+  }
+
+  T &offset(unsigned i, unsigned j)
+  {
+    return m_data[i + Nrows * j];
+  }
+
+  T offset(unsigned i, unsigned j) const
+  {
+    return m_data[i + Nrows * j];
+  }
+
+  template<unsigned I, unsigned J>
+  struct Offset {
+
+    static T &apply(DenseData<T, Nrows, Ncols> &d)
+    {
+      return d.m_data[I + Nrows * J];
+    }
+
+    static T constApply(const DenseData<T, Nrows, Ncols> &d)
+    {
+      return d.m_data[I + Nrows * J];
+    }
+
+  };
+
+};
+
+template<class T, unsigned Nrc>
+class DiagonalData {
+public:
+
+  T &offset(unsigned i, unsigned j)
+  {
+    assert(i == j);
+    return m_data[i];
+  }
+
+  T offset(unsigned i, unsigned j) const
+  {
+    return (i == j) ? m_data[i] : T(0);
+  }
+
+  template<unsigned I, unsigned J>
+  struct Offset {
+
+    static T &apply(DiagonalData<T,Nrc> &d)
+    {
+      assert(I == J);
+      return d.m_data[I];
+    }
+
+    static T constApply(const DiagonalData<T,Nrc> &d)
+    {
+      return (I == J) ? d.m_data[I] : T(0);
+    }
+
+  };
+
+private:
+  
+  T m_data[Nrc];
+};
+
+template<unsigned I, unsigned J, unsigned C1>
+struct InnerLoop {
+
+  template<class LHS, class RHS>
+  static inline void eval(LHS &l, const RHS &r)
+  {
+    l.offset(I,J) = for_each(r, Eval2<I,J>());
+    InnerLoop<I + 1, J, C1 - 1>::eval(l, r);
+  }
+
+};
+
+template<unsigned I, unsigned J>
+struct InnerLoop<I, J, 0> {
+
+  template<class LHS, class RHS>
+  static inline void eval(LHS &, const RHS &) { }
+
+};
+
+template<unsigned I, unsigned J, unsigned C1, unsigned C2>
+struct Loop2 {
+
+  template<class LHS, class RHS>
+  static inline void eval(LHS &l, const RHS &r)
+  {
+    InnerLoop<I, J, C1>::eval(l, r);
+    Loop2<I, J + 1, C1, C2 - 1>::eval(l, r);
+  }
+};
+
+template<unsigned I, unsigned J, unsigned C1>
+struct Loop2<I, J, C1, 0> {
+
+  template<class LHS, class RHS>
+  static inline void eval(LHS &l, const RHS &r) { }
+
+};
+
+
+template<unsigned Begin, unsigned End, unsigned Stride = 1>
+class TinyRange {
+public:
+
+  static const unsigned b = Begin;
+  static const unsigned e = End;
+  static const unsigned s = Stride;
+  static const unsigned n = (End - Begin) / Stride + 1;
+
+  static unsigned index(unsigned i)
+    {
+      return b + s * i;
+    }
+};
+
+template<class Range1, class Range2, class Data>
+struct Merge { };
+
+template<class Range1, class Range2, class T, unsigned Nrows, unsigned Ncols>
+struct Merge<Range1, Range2, DenseData<T, Nrows, Ncols> >
+{
+  static const unsigned s2 = Nrows * Range2::s;
+  typedef 
+    DenseDataView<T, Range1::n, Range2::n, Range1::s, s2> type;
+};
+
+template<class Range1, class Range2, class T, unsigned Nrows, unsigned Ncols,
+  unsigned S1, unsigned S2>
+struct Merge<Range1, Range2, DenseDataView<T, Nrows, Ncols, S1, S2> >
+{
+  static const unsigned s1 = S1 * Range1::s;
+  static const unsigned s2 = S2 * Range2::s;
+
+  typedef
+    DenseDataView<T, Range1::n, Range2::n, s1, s2> type;
+};
+
+template<class T, unsigned Nrows, unsigned Ncols, 
+  class Data = DenseData<T, Nrows, Ncols> >
+class TinyMatrix :
+  public TinyContainer< Data, TinyMatrix<T, Nrows, Ncols, Data> > {
+public:
+
+  typedef T T_Return;
+  typedef typename Data::T_Expr T_Expr;
+  typedef TinyContainer< Data, TinyMatrix<T, Nrows, Ncols, Data> > T_Base;
+  
+  T_Expr makeExpr() const { return m_data.makeExpr(); }
+
+  TinyMatrix() { }
+
+  TinyMatrix(const T &a0, const T &a1, const T &a2, 
+            const T &a3, const T &a4, const T &a5)
+  {
+    m_data[0] = a0; m_data[1] = a1; m_data[2] = a2;
+    m_data[3] = a3; m_data[4] = a4; m_data[5] = a5;
+  }
+
+  TinyMatrix(const T &a0, const T &a1)
+  {
+    m_data[0] = a0; m_data[1] = a1;
+  }
+
+  TinyMatrix(const Data &d) : T_Base(d) { }
+
+  T operator()(unsigned i, unsigned j) const
+  {
+    return m_data.offset(i, j);
+  }
+
+  template<unsigned B1, unsigned E1, unsigned S1,
+    unsigned B2, unsigned E2, unsigned S2>
+  TinyMatrix<T, TinyRange<B1, E1, S1>::n,
+      TinyRange<B2, E2, S2>::n, 
+      typename 
+      Merge< TinyRange<B1, E1, S1>, TinyRange<B2, E2, S2>, Data>::type>  
+  operator()(const TinyRange<B1, E1, S1> &r1, const TinyRange<B2, E2, S2> &r2)
+  {
+    typedef typename 
+      Merge< TinyRange<B1, E1, S1>, TinyRange<B2, E2, S2>, Data>::type
+      T_DataType;
+    typedef TinyMatrix<T, TinyRange<B1, E1, S1>::n,
+      TinyRange<B2, E2, S2>::n, T_DataType> T_RetType;
+
+    return T_RetType(T_DataType(m_data.beginLoc(B1, B2)));
+  }
+
+  template<class V1, class T1>
+  void operator=(const TinyContainer<V1, T1> &rhs)
+  {
+    Loop2<0, 0, Nrows, Ncols>::eval(m_data, rhs.unwrap().makeExpr());
+  }
+
+};
+
+    
+int main()
+{
+  TinyMatrix<double, 2, 3> a, b(1.0, 2.0, 3.0, 4.0, 5.0, 6.0),
+    c(0.1, 0.2, 0.3, 0.4, 0.5, 0.6), d(0.01, 0.02, 0.03, 0.04, 0.05, 0.06);
+  TinyMatrix<double, 1, 2> e, f(17.0, 48.3);
+
+  a = b + c + d;
+
+  a(TinyRange<0,1>(), TinyRange<0,2,2>());
+  
+  a(TinyRange<0,1>(), TinyRange<0,2,2>())
+    (TinyRange<0,0>(), TinyRange<0,1>());
+  
+  e = f + a(TinyRange<0,1>(), TinyRange<0,2,2>())
+    (TinyRange<0,0>(), TinyRange<0,1>());
+}
+