Commit 050367a3 by Mark Mitchell Committed by Mark Mitchell

cplus-dem.c (optable): Add sizeof.

	* 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
parent 0b93b64e
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> Tue Mar 24 12:13:18 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* Makefile.in (genconfig.o, genflags.o, gencodes.o, genemit.o, * Makefile.in (genconfig.o, genflags.o, gencodes.o, genemit.o,
......
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> Mon Mar 23 12:24:37 1998 Jason Merrill <jason@yorick.cygnus.com>
* pt.c (complete_template_args): Initialize skip properly. * pt.c (complete_template_args): Initialize skip properly.
......
...@@ -107,7 +107,6 @@ cxxmain.o: cplus-dem.c demangle.h ...@@ -107,7 +107,6 @@ cxxmain.o: cplus-dem.c demangle.h
$(LN_S) $(srcdir)/cplus-dem.c cxxmain.c $(LN_S) $(srcdir)/cplus-dem.c cxxmain.c
$(CC) -c -DMAIN $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(CC) -c -DMAIN $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
-DVERSION=\"$(version)\" cxxmain.c -DVERSION=\"$(version)\" cxxmain.c
rm -f cxxmain.c
$(DEMANGLER_PROG): cxxmain.o underscore.o getopt.o getopt1.o $(LIBDEPS) $(DEMANGLER_PROG): cxxmain.o underscore.o getopt.o getopt1.o $(LIBDEPS)
$(CC) $(ALL_CFLAGS) $(LDFLAGS) $(LIBS) -o $@ \ $(CC) $(ALL_CFLAGS) $(LDFLAGS) $(LIBS) -o $@ \
......
...@@ -3322,7 +3322,8 @@ finish_struct_1 (t, warn_anon) ...@@ -3322,7 +3322,8 @@ finish_struct_1 (t, warn_anon)
last_x = x; last_x = x;
if (TREE_CODE (x) == TYPE_DECL) if (TREE_CODE (x) == TYPE_DECL
|| TREE_CODE (x) == TEMPLATE_DECL)
continue; continue;
/* If we've gotten this far, it's a data member, possibly static, /* If we've gotten this far, it's a data member, possibly static,
...@@ -5174,8 +5175,8 @@ instantiate_type (lhstype, rhs, complain) ...@@ -5174,8 +5175,8 @@ instantiate_type (lhstype, rhs, complain)
tree t = make_scratch_vec (n); tree t = make_scratch_vec (n);
int i; int i;
i = type_unification i = type_unification
(DECL_INNERMOST_TEMPLATE_PARMS (elem), (DECL_INNERMOST_TEMPLATE_PARMS (elem), t,
&TREE_VEC_ELT (t, 0), TYPE_ARG_TYPES (TREE_TYPE (elem)), TYPE_ARG_TYPES (TREE_TYPE (elem)),
TYPE_ARG_TYPES (lhstype), explicit_targs, 1, 1); TYPE_ARG_TYPES (lhstype), explicit_targs, 1, 1);
if (i == 0) if (i == 0)
{ {
......
...@@ -2463,7 +2463,7 @@ extern tree instantiate_class_template PROTO((tree)); ...@@ -2463,7 +2463,7 @@ extern tree instantiate_class_template PROTO((tree));
extern tree instantiate_template PROTO((tree, tree)); extern tree instantiate_template PROTO((tree, tree));
extern void overload_template_name PROTO((tree)); extern void overload_template_name PROTO((tree));
extern int fn_type_unification PROTO((tree, tree, tree, tree, tree, int, 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)); struct tinst_level *tinst_for_decl PROTO((void));
extern void mark_decl_instantiated PROTO((tree, int)); extern void mark_decl_instantiated PROTO((tree, int));
extern int more_specialized PROTO((tree, tree, tree)); extern int more_specialized PROTO((tree, tree, tree));
......
...@@ -1533,12 +1533,7 @@ dump_expr (t, nop) ...@@ -1533,12 +1533,7 @@ dump_expr (t, nop)
} }
case TEMPLATE_PARM_INDEX: case TEMPLATE_PARM_INDEX:
{ dump_decl (TEMPLATE_PARM_DECL (t), -1);
int l = current_template_parms ?
list_length (current_template_parms) : 0;
dump_decl (TEMPLATE_PARM_DECL (t), -1);
}
break; break;
case IDENTIFIER_NODE: case IDENTIFIER_NODE:
......
...@@ -471,6 +471,16 @@ build_underscore_int (i) ...@@ -471,6 +471,16 @@ build_underscore_int (i)
OB_PUTC ('_'); 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. */ /* Encoding for an INTEGER_CST value. */
static void static void
...@@ -479,13 +489,70 @@ build_overload_int (value, in_template) ...@@ -479,13 +489,70 @@ build_overload_int (value, in_template)
int in_template; int in_template;
{ {
if (in_template && TREE_CODE (value) != INTEGER_CST) 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; if (TREE_CODE (value) == SCOPE_REF)
sprintf (digit_buffer, " *%d", n++); {
OB_PUTCP (digit_buffer); 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; return;
} }
...@@ -497,12 +564,14 @@ build_overload_int (value, in_template) ...@@ -497,12 +564,14 @@ build_overload_int (value, in_template)
{ {
/* need to print a DImode value in decimal */ /* need to print a DImode value in decimal */
dicat (TREE_INT_CST_LOW (value), TREE_INT_CST_HIGH (value)); dicat (TREE_INT_CST_LOW (value), TREE_INT_CST_HIGH (value));
numeric_output_need_bar = 1;
return; return;
} }
/* else fall through to print in smaller mode */ /* else fall through to print in smaller mode */
} }
/* Wordsize or smaller */ /* Wordsize or smaller */
icat (TREE_INT_CST_LOW (value)); icat (TREE_INT_CST_LOW (value));
numeric_output_need_bar = 1;
} }
...@@ -531,8 +600,11 @@ build_overload_value (type, value, in_template) ...@@ -531,8 +600,11 @@ build_overload_value (type, value, in_template)
while (TREE_CODE (value) == NON_LVALUE_EXPR while (TREE_CODE (value) == NON_LVALUE_EXPR
|| TREE_CODE (value) == NOP_EXPR) || TREE_CODE (value) == NOP_EXPR)
value = TREE_OPERAND (value, 0); 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) if (numeric_output_need_bar)
{ {
...@@ -569,7 +641,6 @@ build_overload_value (type, value, in_template) ...@@ -569,7 +641,6 @@ build_overload_value (type, value, in_template)
case BOOLEAN_TYPE: case BOOLEAN_TYPE:
{ {
build_overload_int (value, in_template); build_overload_int (value, in_template);
numeric_output_need_bar = 1;
return; return;
} }
case REAL_TYPE: case REAL_TYPE:
...@@ -672,7 +743,6 @@ build_overload_value (type, value, in_template) ...@@ -672,7 +743,6 @@ build_overload_value (type, value, in_template)
{ {
OB_PUTC ('i'); OB_PUTC ('i');
build_overload_int (a3, in_template); build_overload_int (a3, in_template);
numeric_output_need_bar = 1;
return; return;
} }
} }
...@@ -683,7 +753,6 @@ build_overload_value (type, value, in_template) ...@@ -683,7 +753,6 @@ build_overload_value (type, value, in_template)
if (TREE_CODE (value) == INTEGER_CST) if (TREE_CODE (value) == INTEGER_CST)
{ {
build_overload_int (value, in_template); build_overload_int (value, in_template);
numeric_output_need_bar = 1;
return; return;
} }
else if (TREE_CODE (value) == TEMPLATE_PARM_INDEX) else if (TREE_CODE (value) == TEMPLATE_PARM_INDEX)
...@@ -707,13 +776,7 @@ build_overload_value (type, value, in_template) ...@@ -707,13 +776,7 @@ build_overload_value (type, value, in_template)
return; return;
} }
else if (TREE_CODE (value) == SCOPE_REF) else if (TREE_CODE (value) == SCOPE_REF)
{ build_overload_scope_ref (value);
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 else
my_friendly_abort (71); my_friendly_abort (71);
break; /* not really needed */ break; /* not really needed */
...@@ -865,7 +928,10 @@ build_qualified_name (decl) ...@@ -865,7 +928,10 @@ build_qualified_name (decl)
if (TREE_CODE (decl) == TYPE_DECL if (TREE_CODE (decl) == TYPE_DECL
&& DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl) && !flag_do_squangling) && 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; return;
} }
...@@ -907,11 +973,7 @@ build_qualified_name (decl) ...@@ -907,11 +973,7 @@ build_qualified_name (decl)
if (i > 1) if (i > 1)
{ {
OB_PUTC ('Q'); OB_PUTC ('Q');
if (i > 9) build_underscore_int (i);
OB_PUTC ('_');
icat (i);
if (i > 9)
OB_PUTC ('_');
numeric_output_need_bar = 0; numeric_output_need_bar = 0;
} }
build_overload_nested_name (decl); build_overload_nested_name (decl);
......
...@@ -43,6 +43,10 @@ Boston, MA 02111-1307, USA. */ ...@@ -43,6 +43,10 @@ Boston, MA 02111-1307, USA. */
#include <stdlib.h> #include <stdlib.h>
#endif #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 struct obstack permanent_obstack;
extern int lineno; extern int lineno;
...@@ -69,7 +73,7 @@ static tree saved_trees; ...@@ -69,7 +73,7 @@ static tree saved_trees;
#define obstack_chunk_alloc xmalloc #define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free #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 void add_pending_template PROTO((tree));
static int push_tinst_level PROTO((tree)); static int push_tinst_level PROTO((tree));
static tree classtype_mangled_name PROTO((tree)); static tree classtype_mangled_name PROTO((tree));
...@@ -81,13 +85,14 @@ static tree get_class_bindings PROTO((tree, tree, tree, 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 coerce_template_parms PROTO((tree, tree, tree, int, int, int));
static tree tsubst_enum PROTO((tree, tree, tree *)); static tree tsubst_enum PROTO((tree, tree, tree *));
static tree add_to_template_args PROTO((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 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 void note_template_header PROTO((int));
static tree maybe_fold_nontype_arg PROTO((tree)); static tree maybe_fold_nontype_arg PROTO((tree));
static tree convert_nontype_argument PROTO((tree, tree)); static tree convert_nontype_argument PROTO((tree, tree));
static tree get_bindings_overload PROTO((tree, 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 /* Do any processing required when DECL (a member template declaration
using TEMPLATE_PARAMETERS as its innermost parameter list) is using TEMPLATE_PARAMETERS as its innermost parameter list) is
...@@ -719,7 +724,7 @@ determine_specialization (template_id, decl, targs_out, ...@@ -719,7 +724,7 @@ determine_specialization (template_id, decl, targs_out,
/* We allow incomplete unification here, because we are going to /* We allow incomplete unification here, because we are going to
check all the functions. */ check all the functions. */
i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (tmpl), i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (tmpl),
&TREE_VEC_ELT (targs, 0), targs,
NULL_TREE, NULL_TREE,
NULL_TREE, NULL_TREE,
targs_in, targs_in,
...@@ -1464,7 +1469,46 @@ build_template_decl (decl, parms) ...@@ -1464,7 +1469,46 @@ build_template_decl (decl, parms)
return tmpl; 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 /* Creates a TEMPLATE_DECL for the indicated DECL using the template
parameters given by current_template_args, or reuses a parameters given by current_template_args, or reuses a
previously existing one, if appropriate. Returns the DECL, or an previously existing one, if appropriate. Returns the DECL, or an
...@@ -1529,6 +1573,66 @@ push_template_decl (decl) ...@@ -1529,6 +1573,66 @@ push_template_decl (decl)
tree mainargs = CLASSTYPE_TI_ARGS (type); tree mainargs = CLASSTYPE_TI_ARGS (type);
tree spec = DECL_TEMPLATE_SPECIALIZATIONS (maintmpl); 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)) for (; spec; spec = TREE_CHAIN (spec))
{ {
/* purpose: args to main template /* purpose: args to main template
...@@ -2505,6 +2609,8 @@ tree ...@@ -2505,6 +2609,8 @@ tree
lookup_template_function (fns, arglist) lookup_template_function (fns, arglist)
tree fns, arglist; tree fns, arglist;
{ {
tree t;
if (fns == NULL_TREE) if (fns == NULL_TREE)
{ {
cp_error ("non-template used as template"); cp_error ("non-template used as template");
...@@ -2737,9 +2843,19 @@ lookup_template_class (d1, arglist, in_decl, context) ...@@ -2737,9 +2843,19 @@ lookup_template_class (d1, arglist, in_decl, context)
/* Should be defined in parse.h. */ /* Should be defined in parse.h. */
extern int yychar; 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 int
uses_template_parms (t) for_each_template_parm (t, fn, data)
tree t; tree t;
tree_fn_t fn;
void* data;
{ {
if (!t) if (!t)
return 0; return 0;
...@@ -2750,7 +2866,7 @@ uses_template_parms (t) ...@@ -2750,7 +2866,7 @@ uses_template_parms (t)
/* We assume that the object must be instantiated in order to build /* We assume that the object must be instantiated in order to build
the COMPONENT_REF, so we test only whether the type of the the COMPONENT_REF, so we test only whether the type of the
COMPONENT_REF uses template parms. */ 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: case IDENTIFIER_NODE:
if (!IDENTIFIER_TEMPLATE (t)) if (!IDENTIFIER_TEMPLATE (t))
...@@ -2762,49 +2878,52 @@ uses_template_parms (t) ...@@ -2762,49 +2878,52 @@ uses_template_parms (t)
{ {
int i = TREE_VEC_LENGTH (t); int i = TREE_VEC_LENGTH (t);
while (i--) 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 1;
return 0; return 0;
} }
case TREE_LIST: case TREE_LIST:
if (uses_template_parms (TREE_PURPOSE (t)) if (for_each_template_parm (TREE_PURPOSE (t), fn, data)
|| uses_template_parms (TREE_VALUE (t))) || for_each_template_parm (TREE_VALUE (t), fn, data))
return 1; return 1;
return uses_template_parms (TREE_CHAIN (t)); return for_each_template_parm (TREE_CHAIN (t), fn, data);
/* constructed type nodes */ /* constructed type nodes */
case POINTER_TYPE: case POINTER_TYPE:
case REFERENCE_TYPE: case REFERENCE_TYPE:
return uses_template_parms (TREE_TYPE (t)); return for_each_template_parm (TREE_TYPE (t), fn, data);
case RECORD_TYPE: case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_FLAG (t)) 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: case UNION_TYPE:
if (! CLASSTYPE_TEMPLATE_INFO (t)) if (! CLASSTYPE_TEMPLATE_INFO (t))
return 0; 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: 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 1;
return uses_template_parms (TREE_TYPE (t)); return for_each_template_parm (TREE_TYPE (t), fn, data);
case ARRAY_TYPE: case ARRAY_TYPE:
if (uses_template_parms (TYPE_DOMAIN (t))) if (for_each_template_parm (TYPE_DOMAIN (t), fn, data))
return 1; return 1;
return uses_template_parms (TREE_TYPE (t)); return for_each_template_parm (TREE_TYPE (t), fn, data);
case OFFSET_TYPE: 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 1;
return uses_template_parms (TREE_TYPE (t)); return for_each_template_parm (TREE_TYPE (t), fn, data);
case METHOD_TYPE: case METHOD_TYPE:
if (uses_template_parms (TYPE_METHOD_BASETYPE (t))) if (for_each_template_parm (TYPE_METHOD_BASETYPE (t), fn, data))
return 1; return 1;
if (uses_template_parms (TYPE_ARG_TYPES (t))) if (for_each_template_parm (TYPE_ARG_TYPES (t), fn, data))
return 1; return 1;
return uses_template_parms (TREE_TYPE (t)); return for_each_template_parm (TREE_TYPE (t), fn, data);
/* decl nodes */ /* decl nodes */
case TYPE_DECL: case TYPE_DECL:
return uses_template_parms (TREE_TYPE (t)); return for_each_template_parm (TREE_TYPE (t), fn, data);
case TEMPLATE_DECL: case TEMPLATE_DECL:
/* A template template parameter is encountered */ /* A template template parameter is encountered */
...@@ -2816,7 +2935,7 @@ uses_template_parms (t) ...@@ -2816,7 +2935,7 @@ uses_template_parms (t)
return 0; return 0;
case CONST_DECL: case CONST_DECL:
if (uses_template_parms (DECL_INITIAL (t))) if (for_each_template_parm (DECL_INITIAL (t), fn, data))
return 1; return 1;
goto check_type_and_context; goto check_type_and_context;
...@@ -2824,33 +2943,37 @@ uses_template_parms (t) ...@@ -2824,33 +2943,37 @@ uses_template_parms (t)
case VAR_DECL: case VAR_DECL:
/* ??? What about FIELD_DECLs? */ /* ??? What about FIELD_DECLs? */
if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t) 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; return 1;
/* fall through */ /* fall through */
case PARM_DECL: case PARM_DECL:
check_type_and_context: check_type_and_context:
if (uses_template_parms (TREE_TYPE (t))) if (for_each_template_parm (TREE_TYPE (t), fn, data))
return 1; 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 1;
return 0; return 0;
case CALL_EXPR: case CALL_EXPR:
return uses_template_parms (TREE_TYPE (t)); return for_each_template_parm (TREE_TYPE (t), fn, data);
case ADDR_EXPR: 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 */ /* template parm nodes */
case TEMPLATE_TYPE_PARM: case TEMPLATE_TYPE_PARM:
case TEMPLATE_TEMPLATE_PARM: case TEMPLATE_TEMPLATE_PARM:
case TEMPLATE_PARM_INDEX: case TEMPLATE_PARM_INDEX:
return 1; if (fn)
return (*fn)(t, data);
else
return 1;
/* simple type nodes */ /* simple type nodes */
case INTEGER_TYPE: 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 1;
return uses_template_parms (TYPE_MAX_VALUE (t)); return for_each_template_parm (TYPE_MAX_VALUE (t), fn, data);
case REAL_TYPE: case REAL_TYPE:
case COMPLEX_TYPE: case COMPLEX_TYPE:
...@@ -2863,7 +2986,7 @@ uses_template_parms (t) ...@@ -2863,7 +2986,7 @@ uses_template_parms (t)
tree v; tree v;
for (v = TYPE_VALUES (t); v != NULL_TREE; v = TREE_CHAIN (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 1;
} }
return 0; return 0;
...@@ -2885,12 +3008,13 @@ uses_template_parms (t) ...@@ -2885,12 +3008,13 @@ uses_template_parms (t)
return 1; return 1;
case SCOPE_REF: case SCOPE_REF:
return uses_template_parms (TREE_OPERAND (t, 0)); return for_each_template_parm (TREE_OPERAND (t, 0), fn, data);
case CONSTRUCTOR: case CONSTRUCTOR:
if (TREE_TYPE (t) && TYPE_PTRMEMFUNC_P (TREE_TYPE (t))) if (TREE_TYPE (t) && TYPE_PTRMEMFUNC_P (TREE_TYPE (t)))
return uses_template_parms (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (t))); return for_each_template_parm (TYPE_PTRMEMFUNC_FN_TYPE
return uses_template_parms (TREE_OPERAND (t, 1)); (TREE_TYPE (t)), fn, data);
return for_each_template_parm (TREE_OPERAND (t, 1), fn, data);
case MODOP_EXPR: case MODOP_EXPR:
case CAST_EXPR: case CAST_EXPR:
...@@ -2905,7 +3029,7 @@ uses_template_parms (t) ...@@ -2905,7 +3029,7 @@ uses_template_parms (t)
case SIZEOF_EXPR: case SIZEOF_EXPR:
case ALIGNOF_EXPR: case ALIGNOF_EXPR:
return uses_template_parms (TREE_OPERAND (t, 0)); return for_each_template_parm (TREE_OPERAND (t, 0), fn, data);
default: default:
switch (TREE_CODE_CLASS (TREE_CODE (t))) switch (TREE_CODE_CLASS (TREE_CODE (t)))
...@@ -2917,7 +3041,7 @@ uses_template_parms (t) ...@@ -2917,7 +3041,7 @@ uses_template_parms (t)
{ {
int i; int i;
for (i = tree_code_length[(int) TREE_CODE (t)]; --i >= 0;) 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 1;
return 0; return 0;
} }
...@@ -2932,6 +3056,13 @@ uses_template_parms (t) ...@@ -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 *current_tinst_level = 0;
static struct tinst_level *free_tinst_level = 0; static struct tinst_level *free_tinst_level = 0;
static int tinst_depth = 0; static int tinst_depth = 0;
...@@ -3549,7 +3680,7 @@ tsubst (t, args, in_decl) ...@@ -3549,7 +3680,7 @@ tsubst (t, args, in_decl)
r = lookup_template_class (t, argvec, in_decl, context); r = lookup_template_class (t, argvec, in_decl, context);
return cp_build_type_variant (r, TYPE_READONLY (t), return cp_build_type_variant (r, TYPE_READONLY (t),
TYPE_VOLATILE (t)); TYPE_VOLATILE (t));
} }
/* else fall through */ /* else fall through */
...@@ -3625,7 +3756,8 @@ tsubst (t, args, in_decl) ...@@ -3625,7 +3756,8 @@ tsubst (t, args, in_decl)
{ {
tree arg = NULL_TREE; 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); levels = TREE_VEC_LENGTH (args);
if (level <= levels) if (level <= levels)
...@@ -3678,12 +3810,15 @@ tsubst (t, args, in_decl) ...@@ -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 /* If we get here, we must have been looking at a parm for a
more deeply nested template. */ more deeply nested template. Make a new version of this
my_friendly_assert(level > 1, 0); template parameter, but with a lower level. */
/* Make a new version of this template parameter, but with a
lower level. */
switch (TREE_CODE (t)) switch (TREE_CODE (t))
{ {
case TEMPLATE_TYPE_PARM: case TEMPLATE_TYPE_PARM:
...@@ -5111,7 +5246,7 @@ fn_type_unification (fn, explicit_targs, targs, args, return_type, ...@@ -5111,7 +5246,7 @@ fn_type_unification (fn, explicit_targs, targs, args, return_type,
fn_arg_types); fn_arg_types);
i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (fn), i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (fn),
&TREE_VEC_ELT (targs, 0), targs,
fn_arg_types, fn_arg_types,
decl_arg_types, decl_arg_types,
explicit_targs, explicit_targs,
...@@ -5147,15 +5282,17 @@ fn_type_unification (fn, explicit_targs, targs, args, return_type, ...@@ -5147,15 +5282,17 @@ fn_type_unification (fn, explicit_targs, targs, args, return_type,
int int
type_unification (tparms, targs, parms, args, targs_in, type_unification (tparms, targs, parms, args, targs_in,
strict, allow_incomplete) strict, allow_incomplete)
tree tparms, *targs, parms, args, targs_in; tree tparms, targs, parms, args, targs_in;
int strict, allow_incomplete; int strict, allow_incomplete;
{ {
int ntparms = TREE_VEC_LENGTH (tparms); int ntparms = TREE_VEC_LENGTH (tparms);
tree arg; tree arg;
int* explicit_mask;
int i; int i;
int r; 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) if (targs_in != NULL_TREE)
{ {
...@@ -5166,34 +5303,38 @@ type_unification (tparms, targs, parms, args, targs_in, ...@@ -5166,34 +5303,38 @@ type_unification (tparms, targs, parms, args, targs_in,
if (arg_vec == error_mark_node) if (arg_vec == error_mark_node)
return 1; return 1;
explicit_mask = alloca (sizeof (int) * TREE_VEC_LENGTH (targs));
bzero (explicit_mask, sizeof(int) * TREE_VEC_LENGTH (targs));
for (i = 0; for (i = 0;
i < TREE_VEC_LENGTH (arg_vec) i < TREE_VEC_LENGTH (arg_vec)
&& TREE_VEC_ELT (arg_vec, i) != NULL_TREE; && TREE_VEC_ELT (arg_vec, i) != NULL_TREE;
++i) ++i)
/* Insert the template argument. It is encoded as the operands {
of NOP_EXPRs so that unify can tell that it is an explicit TREE_VEC_ELT (targs, i) = TREE_VEC_ELT (arg_vec, i);
arguments. */ /* Let unify know that this argument was explicit. */
targs[i] = build1 (NOP_EXPR, NULL_TREE, TREE_VEC_ELT (arg_vec, i)); explicit_mask [i] = 1;
}
} }
else
r = type_unification_real (tparms, targs, parms, args, 0, explicit_mask = 0;
strict, allow_incomplete);
for (i = 0, arg = targs_in; r = type_unification_real (tparms, targs, parms, args, 0,
arg != NULL_TREE; strict, allow_incomplete, explicit_mask);
arg = TREE_CHAIN (arg), ++i)
if (TREE_CODE (targs[i]) == NOP_EXPR)
targs[i] = TREE_OPERAND (targs[i], 0);
return r; 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 static int
type_unification_real (tparms, targs, parms, args, subr, type_unification_real (tparms, targs, parms, args, subr,
strict, allow_incomplete) strict, allow_incomplete, explicit_mask)
tree tparms, *targs, parms, args; tree tparms, targs, parms, args;
int subr, strict, allow_incomplete; int subr, strict, allow_incomplete;
int* explicit_mask;
{ {
tree parm, arg; tree parm, arg;
int i; int i;
...@@ -5267,12 +5408,12 @@ type_unification_real (tparms, targs, parms, args, subr, ...@@ -5267,12 +5408,12 @@ type_unification_real (tparms, targs, parms, args, subr,
&& TREE_CODE (TREE_VALUE (arg)) == TEMPLATE_DECL) && TREE_CODE (TREE_VALUE (arg)) == TEMPLATE_DECL)
{ {
int ntparms; int ntparms;
tree *targs; tree targs;
/* Have to back unify here */ /* Have to back unify here */
arg = TREE_VALUE (arg); arg = TREE_VALUE (arg);
ntparms = DECL_NTPARMS (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); parm = expr_tree_cons (NULL_TREE, parm, NULL_TREE);
return return
type_unification (DECL_INNERMOST_TEMPLATE_PARMS (arg), type_unification (DECL_INNERMOST_TEMPLATE_PARMS (arg),
...@@ -5304,7 +5445,8 @@ type_unification_real (tparms, targs, parms, args, subr, ...@@ -5304,7 +5445,8 @@ type_unification_real (tparms, targs, parms, args, subr,
arg = TYPE_MAIN_VARIANT (arg); 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: case 0:
break; break;
...@@ -5323,7 +5465,7 @@ type_unification_real (tparms, targs, parms, args, subr, ...@@ -5323,7 +5465,7 @@ type_unification_real (tparms, targs, parms, args, subr,
return 1; return 1;
if (!subr) if (!subr)
for (i = 0; i < ntparms; i++) for (i = 0; i < ntparms; i++)
if (!targs[i]) if (TREE_VEC_ELT (targs, i) == NULL_TREE)
{ {
if (!allow_incomplete) if (!allow_incomplete)
error ("incomplete type unification"); error ("incomplete type unification");
...@@ -5335,11 +5477,13 @@ type_unification_real (tparms, targs, parms, args, subr, ...@@ -5335,11 +5477,13 @@ type_unification_real (tparms, targs, parms, args, subr,
/* Tail recursion is your friend. */ /* Tail recursion is your friend. */
static int static int
unify (tparms, targs, ntparms, parm, arg, strict) unify (tparms, targs, ntparms, parm, arg, strict, explicit_mask)
tree tparms, *targs, parm, arg; tree tparms, targs, parm, arg;
int ntparms, strict; int ntparms, strict;
int* explicit_mask;
{ {
int idx; int idx;
tree targ;
/* I don't think this will do the right thing with respect to types. /* 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 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) ...@@ -5372,12 +5516,13 @@ unify (tparms, targs, ntparms, parm, arg, strict)
case TEMPLATE_TYPE_PARM: case TEMPLATE_TYPE_PARM:
idx = TEMPLATE_TYPE_IDX (parm); idx = TEMPLATE_TYPE_IDX (parm);
targ = TREE_VEC_ELT (targs, idx);
/* Check for mixed types and values. */ /* Check for mixed types and values. */
if (TREE_CODE (TREE_VALUE (TREE_VEC_ELT (tparms, idx))) != TYPE_DECL) if (TREE_CODE (TREE_VALUE (TREE_VEC_ELT (tparms, idx))) != TYPE_DECL)
return 1; return 1;
if (!strict && targs[idx] != NULL_TREE && if (!strict && targ != NULL_TREE
TREE_CODE (targs[idx]) == NOP_EXPR) && explicit_mask && explicit_mask[idx])
/* An explicit template argument. Don't even try to match /* An explicit template argument. Don't even try to match
here; the overload resolution code will manage check to here; the overload resolution code will manage check to
see whether the call is legal. */ see whether the call is legal. */
...@@ -5402,24 +5547,23 @@ unify (tparms, targs, ntparms, parm, arg, strict) ...@@ -5402,24 +5547,23 @@ unify (tparms, targs, ntparms, parm, arg, strict)
} }
#endif #endif
/* Simple cases: Value already set, does match or doesn't. */ /* Simple cases: Value already set, does match or doesn't. */
if (targs[idx] == arg if (targ == arg || (targ && explicit_mask && explicit_mask[idx]))
|| (targs[idx]
&& TREE_CODE (targs[idx]) == NOP_EXPR
&& TREE_OPERAND (targs[idx], 0) == arg))
return 0; return 0;
else if (targs[idx]) else if (targ)
return 1; return 1;
targs[idx] = arg; TREE_VEC_ELT (targs, idx) = arg;
return 0; return 0;
case TEMPLATE_TEMPLATE_PARM: case TEMPLATE_TEMPLATE_PARM:
idx = TEMPLATE_TYPE_IDX (parm); idx = TEMPLATE_TYPE_IDX (parm);
targ = TREE_VEC_ELT (targs, idx);
/* Check for mixed types and values. */ /* Check for mixed types and values. */
if (TREE_CODE (TREE_VALUE (TREE_VEC_ELT (tparms, idx))) != TEMPLATE_DECL) if (TREE_CODE (TREE_VALUE (TREE_VEC_ELT (tparms, idx))) != TEMPLATE_DECL)
return 1; return 1;
if (!strict && targs[idx] != NULL_TREE && if (!strict && targ != NULL_TREE
TREE_CODE (targs[idx]) == NOP_EXPR) && explicit_mask && explicit_mask[idx])
/* An explicit template argument. Don't even try to match /* An explicit template argument. Don't even try to match
here; the overload resolution code will manage check to here; the overload resolution code will manage check to
see whether the call is legal. */ see whether the call is legal. */
...@@ -5465,7 +5609,7 @@ unify (tparms, targs, ntparms, parm, arg, strict) ...@@ -5465,7 +5609,7 @@ unify (tparms, targs, ntparms, parm, arg, strict)
/* This argument can be deduced. */ /* This argument can be deduced. */
if (unify (tparms, targs, ntparms, t, if (unify (tparms, targs, ntparms, t,
TREE_VEC_ELT (argvec, i), strict)) TREE_VEC_ELT (argvec, i), strict, explicit_mask))
return 1; return 1;
} }
} }
...@@ -5473,21 +5617,19 @@ unify (tparms, targs, ntparms, parm, arg, strict) ...@@ -5473,21 +5617,19 @@ unify (tparms, targs, ntparms, parm, arg, strict)
} }
/* Simple cases: Value already set, does match or doesn't. */ /* Simple cases: Value already set, does match or doesn't. */
if (targs[idx] == arg if (targ == arg || (targ && explicit_mask && explicit_mask[idx]))
|| (targs[idx]
&& TREE_CODE (targs[idx]) == NOP_EXPR
&& TREE_OPERAND (targs[idx], 0) == arg))
return 0; return 0;
else if (targs[idx]) else if (targ)
return 1; return 1;
targs[idx] = arg; TREE_VEC_ELT (targs, idx) = arg;
return 0; return 0;
case TEMPLATE_PARM_INDEX: case TEMPLATE_PARM_INDEX:
idx = TEMPLATE_PARM_IDX (parm); 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) if (i == 1)
return 0; return 0;
else if (i == 0) else if (i == 0)
...@@ -5496,24 +5638,24 @@ unify (tparms, targs, ntparms, parm, arg, strict) ...@@ -5496,24 +5638,24 @@ unify (tparms, targs, ntparms, parm, arg, strict)
my_friendly_abort (42); my_friendly_abort (42);
} }
targs[idx] = copy_to_permanent (arg); TREE_VEC_ELT (targs, idx) = copy_to_permanent (arg);
return 0; return 0;
case POINTER_TYPE: case POINTER_TYPE:
if (TREE_CODE (arg) == RECORD_TYPE && TYPE_PTRMEMFUNC_FLAG (arg)) if (TREE_CODE (arg) == RECORD_TYPE && TYPE_PTRMEMFUNC_FLAG (arg))
return unify (tparms, targs, ntparms, parm, 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) if (TREE_CODE (arg) != POINTER_TYPE)
return 1; return 1;
return unify (tparms, targs, ntparms, TREE_TYPE (parm), TREE_TYPE (arg), return unify (tparms, targs, ntparms, TREE_TYPE (parm), TREE_TYPE (arg),
strict); strict, explicit_mask);
case REFERENCE_TYPE: case REFERENCE_TYPE:
if (TREE_CODE (arg) == REFERENCE_TYPE) if (TREE_CODE (arg) == REFERENCE_TYPE)
arg = TREE_TYPE (arg); arg = TREE_TYPE (arg);
return unify (tparms, targs, ntparms, TREE_TYPE (parm), arg, return unify (tparms, targs, ntparms, TREE_TYPE (parm), arg,
strict); strict, explicit_mask);
case ARRAY_TYPE: case ARRAY_TYPE:
if (TREE_CODE (arg) != ARRAY_TYPE) if (TREE_CODE (arg) != ARRAY_TYPE)
...@@ -5523,10 +5665,10 @@ unify (tparms, targs, ntparms, parm, arg, strict) ...@@ -5523,10 +5665,10 @@ unify (tparms, targs, ntparms, parm, arg, strict)
return 1; return 1;
if (TYPE_DOMAIN (parm) != NULL_TREE if (TYPE_DOMAIN (parm) != NULL_TREE
&& unify (tparms, targs, ntparms, TYPE_DOMAIN (parm), && unify (tparms, targs, ntparms, TYPE_DOMAIN (parm),
TYPE_DOMAIN (arg), strict) != 0) TYPE_DOMAIN (arg), strict, explicit_mask) != 0)
return 1; return 1;
return unify (tparms, targs, ntparms, TREE_TYPE (parm), TREE_TYPE (arg), return unify (tparms, targs, ntparms, TREE_TYPE (parm), TREE_TYPE (arg),
strict); strict, explicit_mask);
case REAL_TYPE: case REAL_TYPE:
case COMPLEX_TYPE: case COMPLEX_TYPE:
...@@ -5540,11 +5682,11 @@ unify (tparms, targs, ntparms, parm, arg, strict) ...@@ -5540,11 +5682,11 @@ unify (tparms, targs, ntparms, parm, arg, strict)
{ {
if (TYPE_MIN_VALUE (parm) && TYPE_MIN_VALUE (arg) if (TYPE_MIN_VALUE (parm) && TYPE_MIN_VALUE (arg)
&& unify (tparms, targs, ntparms, TYPE_MIN_VALUE (parm), && unify (tparms, targs, ntparms, TYPE_MIN_VALUE (parm),
TYPE_MIN_VALUE (arg), strict)) TYPE_MIN_VALUE (arg), strict, explicit_mask))
return 1; return 1;
if (TYPE_MAX_VALUE (parm) && TYPE_MAX_VALUE (arg) if (TYPE_MAX_VALUE (parm) && TYPE_MAX_VALUE (arg)
&& unify (tparms, targs, ntparms, TYPE_MAX_VALUE (parm), && unify (tparms, targs, ntparms, TYPE_MAX_VALUE (parm),
TYPE_MAX_VALUE (arg), strict)) TYPE_MAX_VALUE (arg), strict, explicit_mask))
return 1; return 1;
} }
else if (TREE_CODE (parm) == REAL_TYPE else if (TREE_CODE (parm) == REAL_TYPE
...@@ -5565,16 +5707,6 @@ unify (tparms, targs, ntparms, parm, arg, strict) ...@@ -5565,16 +5707,6 @@ unify (tparms, targs, ntparms, parm, arg, strict)
return 1; return 1;
return !tree_int_cst_equal (parm, arg); 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: case TREE_VEC:
{ {
int i; int i;
...@@ -5585,7 +5717,7 @@ unify (tparms, targs, ntparms, parm, arg, strict) ...@@ -5585,7 +5717,7 @@ unify (tparms, targs, ntparms, parm, arg, strict)
for (i = TREE_VEC_LENGTH (parm) - 1; i >= 0; i--) for (i = TREE_VEC_LENGTH (parm) - 1; i >= 0; i--)
if (unify (tparms, targs, ntparms, if (unify (tparms, targs, ntparms,
TREE_VEC_ELT (parm, i), TREE_VEC_ELT (arg, i), TREE_VEC_ELT (parm, i), TREE_VEC_ELT (arg, i),
strict)) strict, explicit_mask))
return 1; return 1;
return 0; return 0;
} }
...@@ -5593,7 +5725,7 @@ unify (tparms, targs, ntparms, parm, arg, strict) ...@@ -5593,7 +5725,7 @@ unify (tparms, targs, ntparms, parm, arg, strict)
case RECORD_TYPE: case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_FLAG (parm)) if (TYPE_PTRMEMFUNC_FLAG (parm))
return unify (tparms, targs, ntparms, TYPE_PTRMEMFUNC_FN_TYPE (parm), return unify (tparms, targs, ntparms, TYPE_PTRMEMFUNC_FN_TYPE (parm),
arg, strict); arg, strict, explicit_mask);
/* Allow trivial conversions. */ /* Allow trivial conversions. */
if (TREE_CODE (arg) != RECORD_TYPE if (TREE_CODE (arg) != RECORD_TYPE
...@@ -5614,7 +5746,7 @@ unify (tparms, targs, ntparms, parm, arg, strict) ...@@ -5614,7 +5746,7 @@ unify (tparms, targs, ntparms, parm, arg, strict)
return 1; return 1;
return unify (tparms, targs, ntparms, CLASSTYPE_TI_ARGS (parm), 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)) else if (TYPE_MAIN_VARIANT (parm) != TYPE_MAIN_VARIANT (arg))
return 1; return 1;
...@@ -5630,20 +5762,20 @@ unify (tparms, targs, ntparms, parm, arg, strict) ...@@ -5630,20 +5762,20 @@ unify (tparms, targs, ntparms, parm, arg, strict)
return 1; return 1;
check_args: check_args:
if (unify (tparms, targs, ntparms, TREE_TYPE (parm), if (unify (tparms, targs, ntparms, TREE_TYPE (parm),
TREE_TYPE (arg), strict)) TREE_TYPE (arg), strict, explicit_mask))
return 1; return 1;
return type_unification_real (tparms, targs, TYPE_ARG_TYPES (parm), return type_unification_real (tparms, targs, TYPE_ARG_TYPES (parm),
TYPE_ARG_TYPES (arg), 1, TYPE_ARG_TYPES (arg), 1,
strict, 0); strict, 0, explicit_mask);
case OFFSET_TYPE: case OFFSET_TYPE:
if (TREE_CODE (arg) != OFFSET_TYPE) if (TREE_CODE (arg) != OFFSET_TYPE)
return 1; return 1;
if (unify (tparms, targs, ntparms, TYPE_OFFSET_BASETYPE (parm), if (unify (tparms, targs, ntparms, TYPE_OFFSET_BASETYPE (parm),
TYPE_OFFSET_BASETYPE (arg), strict)) TYPE_OFFSET_BASETYPE (arg), strict, explicit_mask))
return 1; return 1;
return unify (tparms, targs, ntparms, TREE_TYPE (parm), return unify (tparms, targs, ntparms, TREE_TYPE (parm),
TREE_TYPE (arg), strict); TREE_TYPE (arg), strict, explicit_mask);
case CONST_DECL: case CONST_DECL:
if (arg != decl_constant_value (parm)) if (arg != decl_constant_value (parm))
...@@ -5655,8 +5787,65 @@ unify (tparms, targs, ntparms, parm, arg, strict) ...@@ -5655,8 +5787,65 @@ unify (tparms, targs, ntparms, parm, arg, strict)
return 1; return 1;
default: default:
sorry ("use of `%s' in template type unification", if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (parm))))
tree_code_name [(int) 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; return 1;
} }
} }
...@@ -5837,8 +6026,9 @@ get_class_bindings (tparms, parms, args, outer_args) ...@@ -5837,8 +6026,9 @@ get_class_bindings (tparms, parms, args, outer_args)
for (i = 0; i < TREE_VEC_LENGTH (parms); ++i) for (i = 0; i < TREE_VEC_LENGTH (parms); ++i)
{ {
switch (unify (tparms, &TREE_VEC_ELT (vec, 0), ntparms, switch (unify (tparms, vec, ntparms,
TREE_VEC_ELT (parms, i), TREE_VEC_ELT (args, i), 1)) TREE_VEC_ELT (parms, i), TREE_VEC_ELT (args, i),
1, 0))
{ {
case 0: case 0:
break; break;
......
...@@ -197,7 +197,8 @@ static const struct optable ...@@ -197,7 +197,8 @@ static const struct optable
{"min", "<?", 0}, /* old */ {"min", "<?", 0}, /* old */
{"mn", "<?", DMGL_ANSI}, /* pseudo-ansi */ {"mn", "<?", DMGL_ANSI}, /* pseudo-ansi */
{"nop", "", 0}, /* old (for operator=) */ {"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 *)); ...@@ -330,6 +331,10 @@ forget_types PARAMS ((struct work_stuff *));
static void static void
string_prepends PARAMS ((string *, string *)); 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. /* Translate count to integer, consuming tokens in the process.
Conversion terminates on the first non-digit character. Conversion terminates on the first non-digit character.
Trying to consume something that isn't a count results in Trying to consume something that isn't a count results in
...@@ -996,6 +1001,270 @@ demangle_template_template_parm (work, mangled, tname) ...@@ -996,6 +1001,270 @@ demangle_template_template_parm (work, mangled, tname)
} }
static int 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) demangle_template (work, mangled, tname, trawname, is_type)
struct work_stuff *work; struct work_stuff *work;
const char **mangled; const char **mangled;
...@@ -1004,18 +1273,10 @@ demangle_template (work, mangled, tname, trawname, is_type) ...@@ -1004,18 +1273,10 @@ demangle_template (work, mangled, tname, trawname, is_type)
int is_type; int is_type;
{ {
int i; int i;
int is_pointer;
int is_real;
int is_integral;
int is_char;
int is_bool;
int r; int r;
int need_comma = 0; int need_comma = 0;
int success = 0; int success = 0;
int done;
const char *old_p;
const char *start; const char *start;
int symbol_len;
int is_java_array = 0; int is_java_array = 0;
string temp; string temp;
...@@ -1148,13 +1409,7 @@ demangle_template (work, mangled, tname, trawname, is_type) ...@@ -1148,13 +1409,7 @@ demangle_template (work, mangled, tname, trawname, is_type)
string* s; string* s;
/* otherwise, value parameter */ /* 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 */ /* temp is initialized in do_type */
success = do_type (work, mangled, &temp); success = do_type (work, mangled, &temp);
/* /*
...@@ -1180,193 +1435,16 @@ demangle_template (work, mangled, tname, trawname, is_type) ...@@ -1180,193 +1435,16 @@ demangle_template (work, mangled, tname, trawname, is_type)
else else
s = tname; s = tname;
while (*old_p && !done) success = demangle_template_value_parm (work, mangled, s);
{
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)++; if (!success)
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 (!is_type)
if (symbol_len == 0) string_delete (s);
{ success = 0;
success = 0; break;
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) if (!is_type)
{ {
int len = s->p - s->b; int len = s->p - s->b;
......
// Build don't link:
template <unsigned rank>
class Tensor
{
};
template <unsigned rank>
class Tensor<2> : Tensor<rank> { // ERROR - template parameters not used
};
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.);
}
// 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.
}
// 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.
}
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>());
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment