PATCH for complex expressions in templates

Mark Mitchell mmitchell@usa.net
Thu Mar 19 13:09:00 GMT 1998


Jason --

  Here's a patch that fixes the following problems:

  o Incorrect mangling of template functions like:

    template <int I>
    void f(vec<N - 1>);

  o Failure to unify with some examples of such templates, such
    as

    template <int I>
    void f(vec<N>, vec<N+1>);

  o A mishandling of member template classes in finish_struct_1.

  All regression tests are OK, plus the quite nasty code in the test
cases at the bottom of the patch now works.

  Is this OK?

-- 
Mark Mitchell <mmitchell@usa.net>
http://home.earthlink.net/~mbmitchell
Consulting Services Available

1998-03-19  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.
	
Thu Mar 19 11:10:47 1998  Mark Mitchell  <mmitchell@usa.net>

	* 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.
	* 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.

Index: cplus-dem.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cplus-dem.c,v
retrieving revision 1.12
diff -c -p -r1.12 cplus-dem.c
*** cplus-dem.c	1998/03/19 00:09:47	1.12
--- cplus-dem.c	1998/03/19 19:02:38
*************** static const struct optable
*** 197,203 ****
    {"min",	  "<?",		0},		/* old */
    {"mn",	  "<?",		DMGL_ANSI},	/* pseudo-ansi */
    {"nop",	  "",		0},		/* old (for operator=) */
!   {"rm",	  "->*",	DMGL_ANSI}	/* ansi */
  };
  
  
--- 197,204 ----
    {"min",	  "<?",		0},		/* old */
    {"mn",	  "<?",		DMGL_ANSI},	/* pseudo-ansi */
    {"nop",	  "",		0},		/* old (for operator=) */
!   {"rm",	  "->*",	DMGL_ANSI},	/* ansi */
!   {"sz",          "sizeof ",    DMGL_ANSI}      /* pseudo-ansi */
  };
  
  
*************** forget_types PARAMS ((struct work_stuff 
*** 330,335 ****
--- 331,340 ----
  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
*************** demangle_template_template_parm (work, m
*** 996,1001 ****
--- 1001,1270 ----
  }
  
  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;
       const char **mangled;
*************** demangle_template (work, mangled, tname,
*** 1004,1021 ****
       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;
  
--- 1273,1282 ----
*************** demangle_template (work, mangled, tname,
*** 1148,1160 ****
  	  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);
  	  /*
--- 1409,1415 ----
  	  string* s;
  
  	  /* otherwise, value parameter */
! 
  	  /* temp is initialized in do_type */
  	  success = do_type (work, mangled, &temp);
  	  /*
*************** demangle_template (work, mangled, tname,
*** 1180,1372 ****
  	  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;
  
! 	      (*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)
  	    {
! 	      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)
  	    {
  	      int len = s->p - s->b;
--- 1435,1450 ----
  	  else
  	    s = tname;
  
! 	  success = demangle_template_value_parm (work, mangled, s);
  
! 	  if (!success)
  	    {
! 	      if (!is_type)
! 		string_delete (s);
! 	      success = 0;
! 	      break;
  	    }
+ 
  	  if (!is_type)
  	    {
  	      int len = s->p - s->b;
Index: cp/Make-lang.in
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/Make-lang.in,v
retrieving revision 1.11
diff -c -p -r1.11 Make-lang.in
*** Make-lang.in	1998/03/18 10:52:00	1.11
--- Make-lang.in	1998/03/19 19:02:43
*************** cxxmain.o: cplus-dem.c demangle.h
*** 107,113 ****
  	$(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 $@ \
--- 107,112 ----
Index: cp/class.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/class.c,v
retrieving revision 1.28
diff -c -p -r1.28 class.c
*** class.c	1998/03/17 00:03:35	1.28
--- class.c	1998/03/19 19:02:59
*************** finish_struct_1 (t, warn_anon)
*** 3322,3328 ****
  
        last_x = x;
  
!       if (TREE_CODE (x) == TYPE_DECL)
  	continue;
  
        /* If we've gotten this far, it's a data member, possibly static,
--- 3322,3329 ----
  
        last_x = x;
  
!       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,
*************** instantiate_type (lhstype, rhs, complain
*** 5174,5181 ****
  		    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)),
  		       TYPE_ARG_TYPES (lhstype), explicit_targs, 1, 1);
  		    if (i == 0)
  		      {
--- 5175,5182 ----
  		    tree t = make_scratch_vec (n);
  		    int i;
  		    i = type_unification
! 		      (DECL_INNERMOST_TEMPLATE_PARMS (elem), t,
! 		       TYPE_ARG_TYPES (TREE_TYPE (elem)),
  		       TYPE_ARG_TYPES (lhstype), explicit_targs, 1, 1);
  		    if (i == 0)
  		      {
Index: cp/cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.43
diff -c -p -r1.43 cp-tree.h
*** cp-tree.h	1998/03/18 10:51:54	1.43
--- cp-tree.h	1998/03/19 19:03:10
*************** extern tree instantiate_class_template		
*** 2463,2469 ****
  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));
  struct tinst_level *tinst_for_decl		PROTO((void));
  extern void mark_decl_instantiated		PROTO((tree, int));
  extern int more_specialized			PROTO((tree, tree, tree));
--- 2463,2469 ----
  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));
  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: cp/gxxint.texi
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/gxxint.texi,v
retrieving revision 1.7
diff -c -p -r1.7 gxxint.texi
*** gxxint.texi	1998/03/04 12:12:59	1.7
--- gxxint.texi	1998/03/19 19:03:17
*************** Indicates a C++ array type.
*** 1746,1751 ****
--- 1746,1754 ----
  Encodes the C++ @code{bool} type,
  and the Java @code{boolean} type.
  
+ @item B
+ Used for squangling.
+ 
  @item c
  Encodes the C++ @code{char} type, and the Java @code{byte} type.
  
*************** Encodes the C++ and Java @code{double} t
*** 1760,1765 ****
--- 1763,1771 ----
  @item e
  Indicates extra unknown arguments @code{...}.
  
+ @item E
+ Indicates the opening parenthesis of an expression.
+ 
  @item f
  Encodes the C++ and Java @code{float} types.
  
*************** Encodes the C++ and Java @code{int} type
*** 1775,1780 ****
--- 1781,1789 ----
  @item J
  Indicates a complex type.
  
+ @item K
+ Used for squangling.
+ 
  @item l
  Encodes the C++ @code{long} type.
  
*************** A modified for a @code{const} type or me
*** 1820,1825 ****
--- 1829,1837 ----
  
  @item w
  Encodes the C++ @code{wchar_t} type, and the Java @code{char} types.
+ 
+ @item W
+ Indicates the closing parenthesis of an expression.
  
  @item x
  Encodes the GNU C++ @code{long long} type, and the Java @code{long} type.
Index: cp/method.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/method.c,v
retrieving revision 1.35
diff -c -p -r1.35 method.c
*** method.c	1998/03/06 22:24:29	1.35
--- method.c	1998/03/19 19:03:33
*************** build_underscore_int (i)
*** 471,476 ****
--- 471,486 ----
      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
*************** build_overload_int (value, in_template)
*** 479,491 ****
       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);
        return;
      }
  
--- 489,571 ----
       int in_template;
  {
    if (in_template && TREE_CODE (value) != INTEGER_CST)
!     {
!       if (TREE_CODE (value) == SCOPE_REF)
! 	{
! 	  build_overload_scope_ref (value);
! 	  return;
! 	}
! 
!       OB_PUTC ('E');
!       numeric_output_need_bar = 0;
! 
!       switch (TREE_CODE_CLASS (TREE_CODE (value)))
! 	{
! 	case '1':
! 	case '2':
! 	case 'e':
! 	  {
! 	    int i;
! 	    int operands;
! 	    tree id;
! 	    char* name;
! 	    
! 	    if (TREE_CODE_CLASS (TREE_CODE (value)) == 1)
! 	      operands = 1;
! 	    else if (TREE_CODE_CLASS (TREE_CODE (value)) == 2)
! 	      operands = 2;
! 	    else
! 	      operands = tree_code_length[(int) TREE_CODE (value)];
! 
! 	    if (TREE_CODE (value) == SIZEOF_EXPR)
! 	      name = "__sz";
! 	    else
! 	      {
! 		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;
! 
! 		if (i != 0)
! 		  /* Skip the leading underscores.  */
! 		  OB_PUTCP (name + 2);
! 
! 		operand = TREE_OPERAND (value, i);
! 		
! 		if (TREE_CODE_CLASS (TREE_CODE (operand)) == 't')
! 		  /* We can get here with sizeof, e.g.:
! 		     
! 		     template <class T> void f(A<sizeof(T)>);  */
! 		  process_overload_item (operand, 0);
! 		else
! 		  build_overload_value (TREE_TYPE (operand),
! 					operand,
! 					in_template);
! 	      }
! 	  }
! 	  break;
! 
! 	default:
! 	  {
! 	    /* 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);
! 	  }
! 	  break;
! 	}
! 
!       OB_PUTC ('W');
!       numeric_output_need_bar = 0;
        return;
      }
  
*************** build_overload_int (value, in_template)
*** 497,508 ****
--- 577,590 ----
  	{
  	  /* 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;
  }
  
  
*************** build_overload_value (type, value, in_te
*** 531,538 ****
    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 (numeric_output_need_bar)
      {
--- 613,623 ----
    while (TREE_CODE (value) == NON_LVALUE_EXPR
  	 || TREE_CODE (value) == NOP_EXPR)
      value = TREE_OPERAND (value, 0);
! 
!   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)
      {
*************** build_overload_value (type, value, in_te
*** 569,575 ****
      case BOOLEAN_TYPE:
        {
  	build_overload_int (value, in_template);
- 	numeric_output_need_bar = 1;
  	return;
        }
      case REAL_TYPE:
--- 654,659 ----
*************** build_overload_value (type, value, in_te
*** 672,678 ****
  		    {
  		      OB_PUTC ('i');
  		      build_overload_int (a3, in_template);
- 		      numeric_output_need_bar = 1;
  		      return;
  		    }
  		}
--- 756,761 ----
*************** build_overload_value (type, value, in_te
*** 683,689 ****
        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)
--- 766,771 ----
*************** build_overload_value (type, value, in_te
*** 707,719 ****
  	  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;
! 	}
        else
  	my_friendly_abort (71);
        break; /* not really needed */
--- 789,795 ----
  	  return;
  	}
        else if (TREE_CODE (value) == SCOPE_REF)
! 	build_overload_scope_ref (value);
        else
  	my_friendly_abort (71);
        break; /* not really needed */
*************** build_qualified_name (decl)
*** 865,871 ****
    if (TREE_CODE (decl) == TYPE_DECL
        && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl) && !flag_do_squangling)
      {
!       OB_PUTID (DECL_ASSEMBLER_NAME (decl));
        return;
      }
  
--- 941,950 ----
    if (TREE_CODE (decl) == TYPE_DECL
        && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl) && !flag_do_squangling)
      {
!       tree id = DECL_ASSEMBLER_NAME (decl);
!       OB_PUTID (id);
!       if (isdigit (IDENTIFIER_POINTER (id) [IDENTIFIER_LENGTH (id) - 1]))
! 	numeric_output_need_bar = 1;
        return;
      }
  
*************** build_qualified_name (decl)
*** 907,917 ****
    if (i > 1)
      {
        OB_PUTC ('Q');
!       if (i > 9)
! 	OB_PUTC ('_');
!       icat (i);
!       if (i > 9)
! 	OB_PUTC ('_');
        numeric_output_need_bar = 0;
      }
    build_overload_nested_name (decl);
--- 986,992 ----
    if (i > 1)
      {
        OB_PUTC ('Q');
!       build_underscore_int (i);
        numeric_output_need_bar = 0;
      }
    build_overload_nested_name (decl);
Index: cp/pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.98
diff -c -p -r1.98 pt.c
*** pt.c	1998/03/19 09:08:52	1.98
--- pt.c	1998/03/19 19:03:50
*************** static tree saved_trees;
*** 69,75 ****
  #define obstack_chunk_alloc xmalloc
  #define obstack_chunk_free free
  
! static int unify PROTO((tree, tree *, int, tree, tree, int));
  static void add_pending_template PROTO((tree));
  static int push_tinst_level PROTO((tree));
  static tree classtype_mangled_name PROTO((tree));
--- 69,75 ----
  #define obstack_chunk_alloc xmalloc
  #define obstack_chunk_free free
  
! 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));
*************** static tree get_class_bindings PROTO((tr
*** 81,88 ****
  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));
  static void note_template_header PROTO((int));
  static tree maybe_fold_nontype_arg PROTO((tree));
  static tree convert_nontype_argument PROTO((tree, tree));
--- 81,88 ----
  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 void note_template_header PROTO((int));
  static tree maybe_fold_nontype_arg PROTO((tree));
  static tree convert_nontype_argument PROTO((tree, tree));
*************** determine_specialization (template_id, d
*** 621,627 ****
  	  /* 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),
  				NULL_TREE,
  				NULL_TREE,  
  				targs_in,
--- 621,627 ----
  	  /* We allow incomplete unification here, because we are going to
  	     check all the functions. */
  	  i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (tmpl),
! 				targs,
  				NULL_TREE,
  				NULL_TREE,  
  				targs_in,
*************** tsubst (t, args, in_decl)
*** 3527,3533 ****
  	  {
  	    tree arg = NULL_TREE;
  
! 	    if (TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
  	      {
  		levels = TREE_VEC_LENGTH (args);
  		if (level <= levels)
--- 3531,3538 ----
  	  {
  	    tree arg = NULL_TREE;
  
! 	    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)
*************** tsubst (t, args, in_decl)
*** 3580,3585 ****
--- 3585,3596 ----
  	      }
  	  }
  
+ 	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);
*************** fn_type_unification (fn, explicit_targs,
*** 5017,5023 ****
  				      fn_arg_types); 
  
    i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (fn), 
! 			&TREE_VEC_ELT (targs, 0), 
  			fn_arg_types,
  			decl_arg_types,
  			explicit_targs,
--- 5028,5034 ----
  				      fn_arg_types); 
  
    i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (fn), 
! 			targs,
  			fn_arg_types,
  			decl_arg_types,
  			explicit_targs,
*************** fn_type_unification (fn, explicit_targs,
*** 5053,5067 ****
  int
  type_unification (tparms, targs, parms, args, targs_in,
  		  strict, allow_incomplete)
!      tree tparms, *targs, parms, args, targs_in;
       int strict, allow_incomplete;
  {
    int ntparms = TREE_VEC_LENGTH (tparms);
    tree arg;
    int i;
    int r;
  
!   bzero ((char *) targs, sizeof (tree) * ntparms);
  
    if (targs_in != NULL_TREE)
      {
--- 5064,5080 ----
  int
  type_unification (tparms, targs, parms, args, targs_in,
  		  strict, allow_incomplete)
!      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;
  
!   for (i = 0; i < ntparms; i++)
!     TREE_VEC_ELT (targs, i) = NULL_TREE;
  
    if (targs_in != NULL_TREE)
      {
*************** type_unification (tparms, targs, parms, 
*** 5072,5105 ****
        if (arg_vec == error_mark_node)
  	return 1;
  
        for (i = 0; 
  	   i < TREE_VEC_LENGTH (arg_vec) 
! 	     && 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));
      }
!   
!   r = type_unification_real (tparms, targs, parms, args, 0,
! 			     strict, allow_incomplete); 
  
!   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);
  
    return r;
  }
  
  
  static int
  type_unification_real (tparms, targs, parms, args, subr,
! 		       strict, allow_incomplete)
!      tree tparms, *targs, parms, args;
       int subr, strict, allow_incomplete;
  {
    tree parm, arg;
    int i;
--- 5085,5122 ----
        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;  
  	   ++i)
! 	{
! 	  TREE_VEC_ELT (targs, i) = TREE_VEC_ELT (arg_vec, i);
! 	  /* Let unify know that this argument was explicit.  */
! 	  explicit_mask [i] = 1;
! 	}
      }
!   else
!     explicit_mask = 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, explicit_mask)
!      tree tparms, targs, parms, args;
       int subr, strict, allow_incomplete;
+      int* explicit_mask;
  {
    tree parm, arg;
    int i;
*************** type_unification_real (tparms, targs, pa
*** 5173,5184 ****
  	      && TREE_CODE (TREE_VALUE (arg)) == TEMPLATE_DECL)
  	    {
  	      int ntparms;
! 	      tree *targs;
  
  	      /* Have to back unify here */
  	      arg = TREE_VALUE (arg);
  	      ntparms = DECL_NTPARMS (arg);
! 	      targs = (tree *) alloca (sizeof (tree) * ntparms);
  	      parm = expr_tree_cons (NULL_TREE, parm, NULL_TREE);
  	      return 
  		type_unification (DECL_INNERMOST_TEMPLATE_PARMS (arg), 
--- 5190,5201 ----
  	      && TREE_CODE (TREE_VALUE (arg)) == TEMPLATE_DECL)
  	    {
  	      int ntparms;
! 	      tree targs;
  
  	      /* Have to back unify here */
  	      arg = TREE_VALUE (arg);
  	      ntparms = DECL_NTPARMS (arg);
! 	      targs = make_scratch_vec (ntparms);
  	      parm = expr_tree_cons (NULL_TREE, parm, NULL_TREE);
  	      return 
  		type_unification (DECL_INNERMOST_TEMPLATE_PARMS (arg), 
*************** type_unification_real (tparms, targs, pa
*** 5210,5216 ****
  	    arg = TYPE_MAIN_VARIANT (arg);
  	}
  
!       switch (unify (tparms, targs, ntparms, parm, arg, strict))
  	{
  	case 0:
  	  break;
--- 5227,5234 ----
  	    arg = TYPE_MAIN_VARIANT (arg);
  	}
  
!       switch (unify (tparms, targs, ntparms, parm, arg, strict,
! 		     explicit_mask)) 
  	{
  	case 0:
  	  break;
*************** type_unification_real (tparms, targs, pa
*** 5229,5235 ****
      return 1;
    if (!subr)
      for (i = 0; i < ntparms; i++)
!       if (!targs[i])
  	{
  	  if (!allow_incomplete)
  	    error ("incomplete type unification");
--- 5247,5253 ----
      return 1;
    if (!subr)
      for (i = 0; i < ntparms; i++)
!       if (TREE_VEC_ELT (targs, i) == NULL_TREE)
  	{
  	  if (!allow_incomplete)
  	    error ("incomplete type unification");
*************** type_unification_real (tparms, targs, pa
*** 5241,5251 ****
  /* Tail recursion is your friend.  */
  
  static int
! unify (tparms, targs, ntparms, parm, arg, strict)
!      tree tparms, *targs, parm, arg;
       int ntparms, strict;
  {
    int idx;
  
    /* 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
--- 5259,5271 ----
  /* Tail recursion is your friend.  */
  
  static int
! 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
*************** unify (tparms, targs, ntparms, parm, arg
*** 5278,5289 ****
  
      case TEMPLATE_TYPE_PARM:
        idx = TEMPLATE_TYPE_IDX (parm);
        /* 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)
  	/* 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.  */ 
--- 5298,5310 ----
  
      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 && 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.  */ 
*************** unify (tparms, targs, ntparms, parm, arg
*** 5308,5331 ****
        }
  #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))
  	return 0;
!       else if (targs[idx])
  	return 1;
!       targs[idx] = arg;
        return 0;
  
      case TEMPLATE_TEMPLATE_PARM:
        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.  */ 
--- 5329,5351 ----
        }
  #endif
        /* Simple cases: Value already set, does match or doesn't.  */
!       if (targ == arg || (targ && explicit_mask && explicit_mask[idx]))
  	return 0;
!       else if (targ)
  	return 1;
!       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 && 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.  */ 
*************** unify (tparms, targs, ntparms, parm, arg
*** 5371,5377 ****
  		/* This argument can be deduced.  */
  
  		if (unify (tparms, targs, ntparms, t, 
! 			   TREE_VEC_ELT (argvec, i), strict))
  		  return 1;
  	      }
  	  }
--- 5391,5397 ----
  		/* This argument can be deduced.  */
  
  		if (unify (tparms, targs, ntparms, t, 
! 			   TREE_VEC_ELT (argvec, i), strict, explicit_mask))
  		  return 1;
  	      }
  	  }
*************** unify (tparms, targs, ntparms, parm, arg
*** 5379,5399 ****
  	}
  
        /* 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_PARM_INDEX:
        idx = TEMPLATE_PARM_IDX (parm);
!       if (targs[idx])
  	{
! 	  int i = cp_tree_equal (targs[idx], arg);
  	  if (i == 1)
  	    return 0;
  	  else if (i == 0)
--- 5399,5417 ----
  	}
  
        /* Simple cases: Value already set, does match or doesn't.  */
!       if (targ == arg || (targ && explicit_mask && explicit_mask[idx]))
  	return 0;
!       else if (targ)
  	return 1;
!       TREE_VEC_ELT (targs, idx) = arg;
        return 0;
  
      case TEMPLATE_PARM_INDEX:
        idx = TEMPLATE_PARM_IDX (parm);
!       targ = TREE_VEC_ELT (targs, idx);
!       if (targ)
  	{
! 	  int i = cp_tree_equal (targ, arg);
  	  if (i == 1)
  	    return 0;
  	  else if (i == 0)
*************** unify (tparms, targs, ntparms, parm, arg
*** 5402,5425 ****
  	    my_friendly_abort (42);
  	}
  
!       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);
  
        if (TREE_CODE (arg) != POINTER_TYPE)
  	return 1;
        return unify (tparms, targs, ntparms, TREE_TYPE (parm), TREE_TYPE (arg),
! 		    strict);
  
      case REFERENCE_TYPE:
        if (TREE_CODE (arg) == REFERENCE_TYPE)
  	arg = TREE_TYPE (arg);
        return unify (tparms, targs, ntparms, TREE_TYPE (parm), arg,
! 		    strict);
  
      case ARRAY_TYPE:
        if (TREE_CODE (arg) != ARRAY_TYPE)
--- 5420,5443 ----
  	    my_friendly_abort (42);
  	}
  
!       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, explicit_mask);
  
        if (TREE_CODE (arg) != POINTER_TYPE)
  	return 1;
        return unify (tparms, targs, ntparms, TREE_TYPE (parm), TREE_TYPE (arg),
! 		    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, explicit_mask);
  
      case ARRAY_TYPE:
        if (TREE_CODE (arg) != ARRAY_TYPE)
*************** unify (tparms, targs, ntparms, parm, arg
*** 5429,5438 ****
  	return 1;
        if (TYPE_DOMAIN (parm) != NULL_TREE
  	  && unify (tparms, targs, ntparms, TYPE_DOMAIN (parm),
! 		    TYPE_DOMAIN (arg), strict) != 0)
  	return 1;
        return unify (tparms, targs, ntparms, TREE_TYPE (parm), TREE_TYPE (arg),
! 		    strict);
  
      case REAL_TYPE:
      case COMPLEX_TYPE:
--- 5447,5456 ----
  	return 1;
        if (TYPE_DOMAIN (parm) != NULL_TREE
  	  && unify (tparms, targs, ntparms, TYPE_DOMAIN (parm),
! 		    TYPE_DOMAIN (arg), strict, explicit_mask) != 0)
  	return 1;
        return unify (tparms, targs, ntparms, TREE_TYPE (parm), TREE_TYPE (arg),
! 		    strict, explicit_mask);
  
      case REAL_TYPE:
      case COMPLEX_TYPE:
*************** unify (tparms, targs, ntparms, parm, arg
*** 5446,5456 ****
  	{
  	  if (TYPE_MIN_VALUE (parm) && TYPE_MIN_VALUE (arg)
  	      && unify (tparms, targs, ntparms, TYPE_MIN_VALUE (parm),
! 			TYPE_MIN_VALUE (arg), strict))
  	    return 1;
  	  if (TYPE_MAX_VALUE (parm) && TYPE_MAX_VALUE (arg)
  	      && unify (tparms, targs, ntparms, TYPE_MAX_VALUE (parm),
! 			TYPE_MAX_VALUE (arg), strict))
  	    return 1;
  	}
        else if (TREE_CODE (parm) == REAL_TYPE
--- 5464,5474 ----
  	{
  	  if (TYPE_MIN_VALUE (parm) && TYPE_MIN_VALUE (arg)
  	      && unify (tparms, targs, ntparms, TYPE_MIN_VALUE (parm),
! 			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, explicit_mask))
  	    return 1;
  	}
        else if (TREE_CODE (parm) == REAL_TYPE
*************** unify (tparms, targs, ntparms, parm, arg
*** 5471,5486 ****
  	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;
--- 5489,5494 ----
*************** unify (tparms, targs, ntparms, parm, arg
*** 5491,5497 ****
  	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))
  	    return 1;
  	return 0;
        }
--- 5499,5505 ----
  	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, explicit_mask))
  	    return 1;
  	return 0;
        }
*************** unify (tparms, targs, ntparms, parm, arg
*** 5499,5505 ****
      case RECORD_TYPE:
        if (TYPE_PTRMEMFUNC_FLAG (parm))
  	return unify (tparms, targs, ntparms, TYPE_PTRMEMFUNC_FN_TYPE (parm),
! 		      arg, strict);
  
        /* Allow trivial conversions.  */
        if (TREE_CODE (arg) != RECORD_TYPE
--- 5507,5513 ----
      case RECORD_TYPE:
        if (TYPE_PTRMEMFUNC_FLAG (parm))
  	return unify (tparms, targs, ntparms, TYPE_PTRMEMFUNC_FN_TYPE (parm),
! 		      arg, strict, explicit_mask);
  
        /* Allow trivial conversions.  */
        if (TREE_CODE (arg) != RECORD_TYPE
*************** unify (tparms, targs, ntparms, parm, arg
*** 5520,5526 ****
  	    return 1;
  
  	  return unify (tparms, targs, ntparms, CLASSTYPE_TI_ARGS (parm),
! 			CLASSTYPE_TI_ARGS (t), strict);
  	}
        else if (TYPE_MAIN_VARIANT (parm) != TYPE_MAIN_VARIANT (arg))
  	return 1;
--- 5528,5534 ----
  	    return 1;
  
  	  return unify (tparms, targs, ntparms, CLASSTYPE_TI_ARGS (parm),
! 			CLASSTYPE_TI_ARGS (t), strict, explicit_mask);
  	}
        else if (TYPE_MAIN_VARIANT (parm) != TYPE_MAIN_VARIANT (arg))
  	return 1;
*************** unify (tparms, targs, ntparms, parm, arg
*** 5536,5555 ****
  	return 1;
       check_args:
        if (unify (tparms, targs, ntparms, TREE_TYPE (parm),
! 		 TREE_TYPE (arg), strict))
  	return 1;
        return type_unification_real (tparms, targs, TYPE_ARG_TYPES (parm),
  				    TYPE_ARG_TYPES (arg), 1, 
! 				    strict, 0);
  
      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))
  	return 1;
        return unify (tparms, targs, ntparms, TREE_TYPE (parm),
! 		    TREE_TYPE (arg), strict);
  
      case CONST_DECL:
        if (arg != decl_constant_value (parm))
--- 5544,5563 ----
  	return 1;
       check_args:
        if (unify (tparms, targs, ntparms, TREE_TYPE (parm),
! 		 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, 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, explicit_mask))
  	return 1;
        return unify (tparms, targs, ntparms, TREE_TYPE (parm),
! 		    TREE_TYPE (arg), strict, explicit_mask);
  
      case CONST_DECL:
        if (arg != decl_constant_value (parm))
*************** unify (tparms, targs, ntparms, parm, arg
*** 5561,5568 ****
        return 1;
  
      default:
!       sorry ("use of `%s' in template type unification",
! 	     tree_code_name [(int) TREE_CODE (parm)]);
        return 1;
      }
  }
--- 5569,5624 ----
        return 1;
  
      default:
!       if (TREE_CODE_CLASS (TREE_CODE (parm)) == 'e'
! 	  || TREE_CODE_CLASS (TREE_CODE (parm)) == '1'
! 	  || TREE_CODE_CLASS (TREE_CODE (parm)) == '2')
! 	{
! 	  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 (TREE_CODE_CLASS (tc) != 'e'
! 	      && TREE_CODE_CLASS (tc) != '1'
! 	      && TREE_CODE_CLASS (tc) != '2')
! 	    /* 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;
      }
  }
*************** get_class_bindings (tparms, parms, args,
*** 5720,5727 ****
  
    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))
  	{
  	case 0:
  	  break;
--- 5776,5784 ----
  
    for (i = 0; i < TREE_VEC_LENGTH (parms); ++i)
      {
!       switch (unify (tparms, vec, ntparms,
! 		     TREE_VEC_ELT (parms, i), TREE_VEC_ELT (args, i),
! 		     1, 0))
  	{
  	case 0:
  	  break;
Index: testsuite/g++.old-deja/g++.pt/expr1.C
===================================================================
RCS file: expr1.C
diff -N expr1.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- expr1.C	Thu Mar 19 11:04:11 1998
***************
*** 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.);
+ }
Index: testsuite/g++.old-deja/g++.pt/expr2.C
===================================================================
RCS file: expr2.C
diff -N expr2.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- expr2.C	Thu Mar 19 11:04:11 1998
***************
*** 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.
+ }
Index: testsuite/g++.old-deja/g++.pt/expr3.C
===================================================================
RCS file: expr3.C
diff -N expr3.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- expr3.C	Thu Mar 19 11:04:11 1998
***************
*** 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.
+ }
Index: testsuite/g++.old-deja/g++.pt/expr4.C
===================================================================
RCS file: expr4.C
diff -N expr4.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- expr4.C	Thu Mar 19 11:04:11 1998
***************
*** 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>());
+ }
+ 
cvs server: Diffing testsuite/g++.old-deja/g++.rfg
cvs server: Diffing testsuite/g++.old-deja/g++.robertl
cvs server: Diffing testsuite/g77.f-torture
cvs server: Diffing testsuite/g77.f-torture/compile
cvs server: Diffing testsuite/g77.f-torture/execute
cvs server: Diffing testsuite/gcc.c-torture
cvs server: Diffing testsuite/gcc.c-torture/code_quality
cvs server: Diffing testsuite/gcc.c-torture/compat
cvs server: Diffing testsuite/gcc.c-torture/compile
cvs server: Diffing testsuite/gcc.c-torture/execute
cvs server: Diffing testsuite/gcc.c-torture/execute/ieee
cvs server: Diffing testsuite/gcc.c-torture/noncompile
cvs server: Diffing testsuite/gcc.c-torture/special
cvs server: Diffing testsuite/gcc.c-torture/unsorted
cvs server: Diffing testsuite/gcc.dg
cvs server: Diffing testsuite/gcc.failure
cvs server: Diffing testsuite/gcc.misc-tests
cvs server: Diffing testsuite/lib



More information about the Gcc-bugs mailing list