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>
* 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>
* pt.c (complete_template_args): Initialize skip properly.
......
......@@ -107,7 +107,6 @@ cxxmain.o: cplus-dem.c demangle.h
$(LN_S) $(srcdir)/cplus-dem.c cxxmain.c
$(CC) -c -DMAIN $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
-DVERSION=\"$(version)\" cxxmain.c
rm -f cxxmain.c
$(DEMANGLER_PROG): cxxmain.o underscore.o getopt.o getopt1.o $(LIBDEPS)
$(CC) $(ALL_CFLAGS) $(LDFLAGS) $(LIBS) -o $@ \
......
......@@ -3322,7 +3322,8 @@ finish_struct_1 (t, warn_anon)
last_x = x;
if (TREE_CODE (x) == TYPE_DECL)
if (TREE_CODE (x) == TYPE_DECL
|| TREE_CODE (x) == TEMPLATE_DECL)
continue;
/* If we've gotten this far, it's a data member, possibly static,
......@@ -5174,8 +5175,8 @@ instantiate_type (lhstype, rhs, complain)
tree t = make_scratch_vec (n);
int i;
i = type_unification
(DECL_INNERMOST_TEMPLATE_PARMS (elem),
&TREE_VEC_ELT (t, 0), TYPE_ARG_TYPES (TREE_TYPE (elem)),
(DECL_INNERMOST_TEMPLATE_PARMS (elem), t,
TYPE_ARG_TYPES (TREE_TYPE (elem)),
TYPE_ARG_TYPES (lhstype), explicit_targs, 1, 1);
if (i == 0)
{
......
......@@ -2463,7 +2463,7 @@ extern tree instantiate_class_template PROTO((tree));
extern tree instantiate_template PROTO((tree, tree));
extern void overload_template_name PROTO((tree));
extern int fn_type_unification PROTO((tree, tree, tree, tree, tree, int, tree));
extern int type_unification PROTO((tree, tree *, tree, tree, tree, int, int));
extern int type_unification PROTO((tree, tree, tree, tree, tree, int, int));
struct tinst_level *tinst_for_decl PROTO((void));
extern void mark_decl_instantiated PROTO((tree, int));
extern int more_specialized PROTO((tree, tree, tree));
......
......@@ -1533,12 +1533,7 @@ dump_expr (t, nop)
}
case TEMPLATE_PARM_INDEX:
{
int l = current_template_parms ?
list_length (current_template_parms) : 0;
dump_decl (TEMPLATE_PARM_DECL (t), -1);
}
dump_decl (TEMPLATE_PARM_DECL (t), -1);
break;
case IDENTIFIER_NODE:
......
......@@ -471,6 +471,16 @@ build_underscore_int (i)
OB_PUTC ('_');
}
static void
build_overload_scope_ref (value)
tree value;
{
OB_PUTC2 ('Q', '2');
numeric_output_need_bar = 0;
build_mangled_name (TREE_OPERAND (value, 0), 0, 0);
build_overload_identifier (TREE_OPERAND (value, 1));
}
/* Encoding for an INTEGER_CST value. */
static void
......@@ -479,13 +489,70 @@ build_overload_int (value, in_template)
int in_template;
{
if (in_template && TREE_CODE (value) != INTEGER_CST)
/* We don't ever want this output, but it's inconvenient not to
be able to build the string. This should cause assembler
errors we'll notice. */
{
static int n;
sprintf (digit_buffer, " *%d", n++);
OB_PUTCP (digit_buffer);
if (TREE_CODE (value) == SCOPE_REF)
{
build_overload_scope_ref (value);
return;
}
OB_PUTC ('E');
numeric_output_need_bar = 0;
if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (value))))
{
int i;
int operands = tree_code_length[(int) TREE_CODE (value)];
tree id;
char* name;
id = ansi_opname [(int) TREE_CODE (value)];
my_friendly_assert (id != NULL_TREE, 0);
name = IDENTIFIER_POINTER (id);
my_friendly_assert (name[0] == '_' && name[1] == '_', 0);
for (i = 0; i < operands; ++i)
{
tree operand;
enum tree_code tc;
/* We just outputted either the `E' or the name of the
operator. */
numeric_output_need_bar = 0;
if (i != 0)
/* Skip the leading underscores. */
OB_PUTCP (name + 2);
operand = TREE_OPERAND (value, i);
tc = TREE_CODE (operand);
if (TREE_CODE_CLASS (tc) == 't')
/* We can get here with sizeof, e.g.:
template <class T> void f(A<sizeof(T)>); */
process_overload_item (operand, 0);
else if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (tc)))
build_overload_int (operand, in_template);
else
build_overload_value (TREE_TYPE (operand),
operand,
in_template);
}
}
else
{
/* We don't ever want this output, but it's
inconvenient not to be able to build the string.
This should cause assembler errors we'll notice. */
static int n;
sprintf (digit_buffer, " *%d", n++);
OB_PUTCP (digit_buffer);
}
OB_PUTC ('W');
numeric_output_need_bar = 0;
return;
}
......@@ -497,12 +564,14 @@ build_overload_int (value, in_template)
{
/* need to print a DImode value in decimal */
dicat (TREE_INT_CST_LOW (value), TREE_INT_CST_HIGH (value));
numeric_output_need_bar = 1;
return;
}
/* else fall through to print in smaller mode */
}
/* Wordsize or smaller */
icat (TREE_INT_CST_LOW (value));
numeric_output_need_bar = 1;
}
......@@ -531,8 +600,11 @@ build_overload_value (type, value, in_template)
while (TREE_CODE (value) == NON_LVALUE_EXPR
|| TREE_CODE (value) == NOP_EXPR)
value = TREE_OPERAND (value, 0);
my_friendly_assert (TREE_CODE (type) == PARM_DECL, 242);
type = TREE_TYPE (type);
if (TREE_CODE (type) == PARM_DECL)
type = TREE_TYPE (type);
my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (type)) == 't', 0);
if (numeric_output_need_bar)
{
......@@ -569,7 +641,6 @@ build_overload_value (type, value, in_template)
case BOOLEAN_TYPE:
{
build_overload_int (value, in_template);
numeric_output_need_bar = 1;
return;
}
case REAL_TYPE:
......@@ -672,7 +743,6 @@ build_overload_value (type, value, in_template)
{
OB_PUTC ('i');
build_overload_int (a3, in_template);
numeric_output_need_bar = 1;
return;
}
}
......@@ -683,7 +753,6 @@ build_overload_value (type, value, in_template)
if (TREE_CODE (value) == INTEGER_CST)
{
build_overload_int (value, in_template);
numeric_output_need_bar = 1;
return;
}
else if (TREE_CODE (value) == TEMPLATE_PARM_INDEX)
......@@ -707,13 +776,7 @@ build_overload_value (type, value, in_template)
return;
}
else if (TREE_CODE (value) == SCOPE_REF)
{
OB_PUTC2 ('Q', '1');
numeric_output_need_bar = 0;
build_mangled_name (TREE_OPERAND (value, 0), 0, 0);
build_overload_identifier (TREE_OPERAND (value, 1));
return;
}
build_overload_scope_ref (value);
else
my_friendly_abort (71);
break; /* not really needed */
......@@ -865,7 +928,10 @@ build_qualified_name (decl)
if (TREE_CODE (decl) == TYPE_DECL
&& DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl) && !flag_do_squangling)
{
OB_PUTID (DECL_ASSEMBLER_NAME (decl));
tree id = DECL_ASSEMBLER_NAME (decl);
OB_PUTID (id);
if (isdigit (IDENTIFIER_POINTER (id) [IDENTIFIER_LENGTH (id) - 1]))
numeric_output_need_bar = 1;
return;
}
......@@ -907,11 +973,7 @@ build_qualified_name (decl)
if (i > 1)
{
OB_PUTC ('Q');
if (i > 9)
OB_PUTC ('_');
icat (i);
if (i > 9)
OB_PUTC ('_');
build_underscore_int (i);
numeric_output_need_bar = 0;
}
build_overload_nested_name (decl);
......
......@@ -43,6 +43,10 @@ Boston, MA 02111-1307, USA. */
#include <stdlib.h>
#endif
/* The type of functions taking a tree, and some additional data, and
returning an int. */
typedef int (*tree_fn_t) PROTO((tree, void*));
extern struct obstack permanent_obstack;
extern int lineno;
......@@ -69,7 +73,7 @@ static tree saved_trees;
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
static int unify PROTO((tree, tree *, int, tree, tree, int));
static int unify PROTO((tree, tree, int, tree, tree, int, int*));
static void add_pending_template PROTO((tree));
static int push_tinst_level PROTO((tree));
static tree classtype_mangled_name PROTO((tree));
......@@ -81,13 +85,14 @@ static tree get_class_bindings PROTO((tree, tree, tree, tree));
static tree coerce_template_parms PROTO((tree, tree, tree, int, int, int));
static tree tsubst_enum PROTO((tree, tree, tree *));
static tree add_to_template_args PROTO((tree, tree));
static int type_unification_real PROTO((tree, tree, tree, tree,
int, int, int, int*));
static tree complete_template_args PROTO((tree, tree, int));
static int type_unification_real PROTO((tree, tree *, tree, tree,
int, int, int));
static void note_template_header PROTO((int));
static tree maybe_fold_nontype_arg PROTO((tree));
static tree convert_nontype_argument PROTO((tree, tree));
static tree get_bindings_overload PROTO((tree, tree, tree));
static int for_each_template_parm PROTO((tree, tree_fn_t, void*));
/* Do any processing required when DECL (a member template declaration
using TEMPLATE_PARAMETERS as its innermost parameter list) is
......@@ -719,7 +724,7 @@ determine_specialization (template_id, decl, targs_out,
/* We allow incomplete unification here, because we are going to
check all the functions. */
i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (tmpl),
&TREE_VEC_ELT (targs, 0),
targs,
NULL_TREE,
NULL_TREE,
targs_in,
......@@ -1464,7 +1469,46 @@ build_template_decl (decl, parms)
return tmpl;
}
struct template_parm_data
{
int level;
int* parms;
};
/* Subroutine of push_template_decl used to see if each template
parameter in a partial specialization is used in the explicit
argument list. If T is of the LEVEL given in DATA (which is
treated as a template_parm_data*), then DATA->PARMS is marked
appropriately. */
static int
mark_template_parm (t, data)
tree t;
void* data;
{
int level;
int idx;
struct template_parm_data* tpd = (struct template_parm_data*) data;
if (TREE_CODE (t) == TEMPLATE_PARM_INDEX)
{
level = TEMPLATE_PARM_LEVEL (t);
idx = TEMPLATE_PARM_IDX (t);
}
else
{
level = TEMPLATE_TYPE_LEVEL (t);
idx = TEMPLATE_TYPE_IDX (t);
}
if (level == tpd->level)
tpd->parms[idx] = 1;
/* Return zero so that for_each_template_parm will continue the
traversal of the tree; we want to mark *every* template parm. */
return 0;
}
/* Creates a TEMPLATE_DECL for the indicated DECL using the template
parameters given by current_template_args, or reuses a
previously existing one, if appropriate. Returns the DECL, or an
......@@ -1529,6 +1573,66 @@ push_template_decl (decl)
tree mainargs = CLASSTYPE_TI_ARGS (type);
tree spec = DECL_TEMPLATE_SPECIALIZATIONS (maintmpl);
/* We check that each of the template parameters given in the
partial specialization is used in the argument list to the
specialization. For example:
template <class T> struct S;
template <class T> struct S<T*>;
The second declaration is OK because `T*' uses the template
parameter T, whereas
template <class T> struct S<int>;
is no good. Even trickier is:
template <class T>
struct S1
{
template <class U>
struct S2;
template <class U>
struct S2<T>;
};
The S2<T> declaration is actually illegal; it is a
full-specialization. Of course,
template <class U>
struct S2<T (*)(U)>;
or some such would have been OK. */
int i;
struct template_parm_data tpd;
int ntparms = TREE_VEC_LENGTH (TREE_VALUE (current_template_parms));
int did_error_intro = 0;
tpd.level = TREE_INT_CST_HIGH (TREE_PURPOSE (current_template_parms));
tpd.parms = alloca (sizeof (int) * ntparms);
for (i = 0; i < ntparms; ++i)
tpd.parms[i] = 0;
for (i = 0; i < TREE_VEC_LENGTH (mainargs); ++i)
for_each_template_parm (TREE_VEC_ELT (mainargs, i),
&mark_template_parm,
&tpd);
for (i = 0; i < ntparms; ++i)
if (tpd.parms[i] == 0)
{
/* One of the template parms was not used in the
specialization. */
if (!did_error_intro)
{
cp_error ("template parameters not used in partial specialization:");
did_error_intro = 1;
}
cp_error (" `%D'",
TREE_VALUE (TREE_VEC_ELT
(TREE_VALUE (current_template_parms),
i)));
}
for (; spec; spec = TREE_CHAIN (spec))
{
/* purpose: args to main template
......@@ -2505,6 +2609,8 @@ tree
lookup_template_function (fns, arglist)
tree fns, arglist;
{
tree t;
if (fns == NULL_TREE)
{
cp_error ("non-template used as template");
......@@ -2737,9 +2843,19 @@ lookup_template_class (d1, arglist, in_decl, context)
/* Should be defined in parse.h. */
extern int yychar;
/* For each TEMPLATE_TYPE_PARM, TEMPLATE_TEMPLATE_PARM, or
TEMPLATE_PARM_INDEX in T, call FN with the parameter and the DATA.
If FN returns non-zero, the iteration is terminated, and
for_each_template_parm returns 1. Otherwise, the iteration
continues. If FN never returns a non-zero value, the value
returned by for_each_template_parm is 0. If FN is NULL, it is
considered to be the function which always returns 1. */
int
uses_template_parms (t)
for_each_template_parm (t, fn, data)
tree t;
tree_fn_t fn;
void* data;
{
if (!t)
return 0;
......@@ -2750,7 +2866,7 @@ uses_template_parms (t)
/* We assume that the object must be instantiated in order to build
the COMPONENT_REF, so we test only whether the type of the
COMPONENT_REF uses template parms. */
return uses_template_parms (TREE_TYPE (t));
return for_each_template_parm (TREE_TYPE (t), fn, data);
case IDENTIFIER_NODE:
if (!IDENTIFIER_TEMPLATE (t))
......@@ -2762,49 +2878,52 @@ uses_template_parms (t)
{
int i = TREE_VEC_LENGTH (t);
while (i--)
if (uses_template_parms (TREE_VEC_ELT (t, i)))
if (for_each_template_parm (TREE_VEC_ELT (t, i), fn, data))
return 1;
return 0;
}
case TREE_LIST:
if (uses_template_parms (TREE_PURPOSE (t))
|| uses_template_parms (TREE_VALUE (t)))
if (for_each_template_parm (TREE_PURPOSE (t), fn, data)
|| for_each_template_parm (TREE_VALUE (t), fn, data))
return 1;
return uses_template_parms (TREE_CHAIN (t));
return for_each_template_parm (TREE_CHAIN (t), fn, data);
/* constructed type nodes */
case POINTER_TYPE:
case REFERENCE_TYPE:
return uses_template_parms (TREE_TYPE (t));
return for_each_template_parm (TREE_TYPE (t), fn, data);
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_FLAG (t))
return uses_template_parms (TYPE_PTRMEMFUNC_FN_TYPE (t));
return for_each_template_parm (TYPE_PTRMEMFUNC_FN_TYPE (t),
fn, data);
case UNION_TYPE:
if (! CLASSTYPE_TEMPLATE_INFO (t))
return 0;
return uses_template_parms (TREE_VALUE (CLASSTYPE_TEMPLATE_INFO (t)));
return for_each_template_parm (TREE_VALUE
(CLASSTYPE_TEMPLATE_INFO (t)),
fn, data);
case FUNCTION_TYPE:
if (uses_template_parms (TYPE_ARG_TYPES (t)))
if (for_each_template_parm (TYPE_ARG_TYPES (t), fn, data))
return 1;
return uses_template_parms (TREE_TYPE (t));
return for_each_template_parm (TREE_TYPE (t), fn, data);
case ARRAY_TYPE:
if (uses_template_parms (TYPE_DOMAIN (t)))
if (for_each_template_parm (TYPE_DOMAIN (t), fn, data))
return 1;
return uses_template_parms (TREE_TYPE (t));
return for_each_template_parm (TREE_TYPE (t), fn, data);
case OFFSET_TYPE:
if (uses_template_parms (TYPE_OFFSET_BASETYPE (t)))
if (for_each_template_parm (TYPE_OFFSET_BASETYPE (t), fn, data))
return 1;
return uses_template_parms (TREE_TYPE (t));
return for_each_template_parm (TREE_TYPE (t), fn, data);
case METHOD_TYPE:
if (uses_template_parms (TYPE_METHOD_BASETYPE (t)))
if (for_each_template_parm (TYPE_METHOD_BASETYPE (t), fn, data))
return 1;
if (uses_template_parms (TYPE_ARG_TYPES (t)))
if (for_each_template_parm (TYPE_ARG_TYPES (t), fn, data))
return 1;
return uses_template_parms (TREE_TYPE (t));
return for_each_template_parm (TREE_TYPE (t), fn, data);
/* decl nodes */
case TYPE_DECL:
return uses_template_parms (TREE_TYPE (t));
return for_each_template_parm (TREE_TYPE (t), fn, data);
case TEMPLATE_DECL:
/* A template template parameter is encountered */
......@@ -2816,7 +2935,7 @@ uses_template_parms (t)
return 0;
case CONST_DECL:
if (uses_template_parms (DECL_INITIAL (t)))
if (for_each_template_parm (DECL_INITIAL (t), fn, data))
return 1;
goto check_type_and_context;
......@@ -2824,33 +2943,37 @@ uses_template_parms (t)
case VAR_DECL:
/* ??? What about FIELD_DECLs? */
if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t)
&& uses_template_parms (DECL_TI_ARGS (t)))
&& for_each_template_parm (DECL_TI_ARGS (t), fn, data))
return 1;
/* fall through */
case PARM_DECL:
check_type_and_context:
if (uses_template_parms (TREE_TYPE (t)))
if (for_each_template_parm (TREE_TYPE (t), fn, data))
return 1;
if (DECL_CONTEXT (t) && uses_template_parms (DECL_CONTEXT (t)))
if (DECL_CONTEXT (t)
&& for_each_template_parm (DECL_CONTEXT (t), fn, data))
return 1;
return 0;
case CALL_EXPR:
return uses_template_parms (TREE_TYPE (t));
return for_each_template_parm (TREE_TYPE (t), fn, data);
case ADDR_EXPR:
return uses_template_parms (TREE_OPERAND (t, 0));
return for_each_template_parm (TREE_OPERAND (t, 0), fn, data);
/* template parm nodes */
case TEMPLATE_TYPE_PARM:
case TEMPLATE_TEMPLATE_PARM:
case TEMPLATE_PARM_INDEX:
return 1;
if (fn)
return (*fn)(t, data);
else
return 1;
/* simple type nodes */
case INTEGER_TYPE:
if (uses_template_parms (TYPE_MIN_VALUE (t)))
if (for_each_template_parm (TYPE_MIN_VALUE (t), fn, data))
return 1;
return uses_template_parms (TYPE_MAX_VALUE (t));
return for_each_template_parm (TYPE_MAX_VALUE (t), fn, data);
case REAL_TYPE:
case COMPLEX_TYPE:
......@@ -2863,7 +2986,7 @@ uses_template_parms (t)
tree v;
for (v = TYPE_VALUES (t); v != NULL_TREE; v = TREE_CHAIN (v))
if (uses_template_parms (TREE_VALUE (v)))
if (for_each_template_parm (TREE_VALUE (v), fn, data))
return 1;
}
return 0;
......@@ -2885,12 +3008,13 @@ uses_template_parms (t)
return 1;
case SCOPE_REF:
return uses_template_parms (TREE_OPERAND (t, 0));
return for_each_template_parm (TREE_OPERAND (t, 0), fn, data);
case CONSTRUCTOR:
if (TREE_TYPE (t) && TYPE_PTRMEMFUNC_P (TREE_TYPE (t)))
return uses_template_parms (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (t)));
return uses_template_parms (TREE_OPERAND (t, 1));
return for_each_template_parm (TYPE_PTRMEMFUNC_FN_TYPE
(TREE_TYPE (t)), fn, data);
return for_each_template_parm (TREE_OPERAND (t, 1), fn, data);
case MODOP_EXPR:
case CAST_EXPR:
......@@ -2905,7 +3029,7 @@ uses_template_parms (t)
case SIZEOF_EXPR:
case ALIGNOF_EXPR:
return uses_template_parms (TREE_OPERAND (t, 0));
return for_each_template_parm (TREE_OPERAND (t, 0), fn, data);
default:
switch (TREE_CODE_CLASS (TREE_CODE (t)))
......@@ -2917,7 +3041,7 @@ uses_template_parms (t)
{
int i;
for (i = tree_code_length[(int) TREE_CODE (t)]; --i >= 0;)
if (uses_template_parms (TREE_OPERAND (t, i)))
if (for_each_template_parm (TREE_OPERAND (t, i), fn, data))
return 1;
return 0;
}
......@@ -2932,6 +3056,13 @@ uses_template_parms (t)
}
}
int
uses_template_parms (t)
tree t;
{
return for_each_template_parm (t, 0, 0);
}
static struct tinst_level *current_tinst_level = 0;
static struct tinst_level *free_tinst_level = 0;
static int tinst_depth = 0;
......@@ -3549,7 +3680,7 @@ tsubst (t, args, in_decl)
r = lookup_template_class (t, argvec, in_decl, context);
return cp_build_type_variant (r, TYPE_READONLY (t),
TYPE_VOLATILE (t));
TYPE_VOLATILE (t));
}
/* else fall through */
......@@ -3625,7 +3756,8 @@ tsubst (t, args, in_decl)
{
tree arg = NULL_TREE;
if (TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
if (TREE_VEC_ELT (args, 0) != NULL_TREE
&& TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
{
levels = TREE_VEC_LENGTH (args);
if (level <= levels)
......@@ -3678,12 +3810,15 @@ tsubst (t, args, in_decl)
}
}
if (level == 1)
/* This can happen during the attempted tsubst'ing in
unify. This means that we don't yet have any information
about the template parameter in question. */
return t;
/* If we get here, we must have been looking at a parm for a
more deeply nested template. */
my_friendly_assert(level > 1, 0);
/* Make a new version of this template parameter, but with a
lower level. */
more deeply nested template. Make a new version of this
template parameter, but with a lower level. */
switch (TREE_CODE (t))
{
case TEMPLATE_TYPE_PARM:
......@@ -5111,7 +5246,7 @@ fn_type_unification (fn, explicit_targs, targs, args, return_type,
fn_arg_types);
i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (fn),
&TREE_VEC_ELT (targs, 0),
targs,
fn_arg_types,
decl_arg_types,
explicit_targs,
......@@ -5147,15 +5282,17 @@ fn_type_unification (fn, explicit_targs, targs, args, return_type,
int
type_unification (tparms, targs, parms, args, targs_in,
strict, allow_incomplete)
tree tparms, *targs, parms, args, targs_in;
tree tparms, targs, parms, args, targs_in;
int strict, allow_incomplete;
{
int ntparms = TREE_VEC_LENGTH (tparms);
tree arg;
int* explicit_mask;
int i;
int r;
bzero ((char *) targs, sizeof (tree) * ntparms);
for (i = 0; i < ntparms; i++)
TREE_VEC_ELT (targs, i) = NULL_TREE;
if (targs_in != NULL_TREE)
{
......@@ -5166,34 +5303,38 @@ type_unification (tparms, targs, parms, args, targs_in,
if (arg_vec == error_mark_node)
return 1;
explicit_mask = alloca (sizeof (int) * TREE_VEC_LENGTH (targs));
bzero (explicit_mask, sizeof(int) * TREE_VEC_LENGTH (targs));
for (i = 0;
i < TREE_VEC_LENGTH (arg_vec)
&& TREE_VEC_ELT (arg_vec, i) != NULL_TREE;
&& TREE_VEC_ELT (arg_vec, i) != NULL_TREE;
++i)
/* Insert the template argument. It is encoded as the operands
of NOP_EXPRs so that unify can tell that it is an explicit
arguments. */
targs[i] = build1 (NOP_EXPR, NULL_TREE, TREE_VEC_ELT (arg_vec, i));
{
TREE_VEC_ELT (targs, i) = TREE_VEC_ELT (arg_vec, i);
/* Let unify know that this argument was explicit. */
explicit_mask [i] = 1;
}
}
r = type_unification_real (tparms, targs, parms, args, 0,
strict, allow_incomplete);
else
explicit_mask = 0;
for (i = 0, arg = targs_in;
arg != NULL_TREE;
arg = TREE_CHAIN (arg), ++i)
if (TREE_CODE (targs[i]) == NOP_EXPR)
targs[i] = TREE_OPERAND (targs[i], 0);
r = type_unification_real (tparms, targs, parms, args, 0,
strict, allow_incomplete, explicit_mask);
return r;
}
/* Like type_unfication. EXPLICIT_MASK, if non-NULL, is an array of
integers, with ones in positions corresponding to arguments in
targs that were provided explicitly, and zeros elsewhere. */
static int
type_unification_real (tparms, targs, parms, args, subr,
strict, allow_incomplete)
tree tparms, *targs, parms, args;
strict, allow_incomplete, explicit_mask)
tree tparms, targs, parms, args;
int subr, strict, allow_incomplete;
int* explicit_mask;
{
tree parm, arg;
int i;
......@@ -5267,12 +5408,12 @@ type_unification_real (tparms, targs, parms, args, subr,
&& TREE_CODE (TREE_VALUE (arg)) == TEMPLATE_DECL)
{
int ntparms;
tree *targs;
tree targs;
/* Have to back unify here */
arg = TREE_VALUE (arg);
ntparms = DECL_NTPARMS (arg);
targs = (tree *) alloca (sizeof (tree) * ntparms);
targs = make_scratch_vec (ntparms);
parm = expr_tree_cons (NULL_TREE, parm, NULL_TREE);
return
type_unification (DECL_INNERMOST_TEMPLATE_PARMS (arg),
......@@ -5304,7 +5445,8 @@ type_unification_real (tparms, targs, parms, args, subr,
arg = TYPE_MAIN_VARIANT (arg);
}
switch (unify (tparms, targs, ntparms, parm, arg, strict))
switch (unify (tparms, targs, ntparms, parm, arg, strict,
explicit_mask))
{
case 0:
break;
......@@ -5323,7 +5465,7 @@ type_unification_real (tparms, targs, parms, args, subr,
return 1;
if (!subr)
for (i = 0; i < ntparms; i++)
if (!targs[i])
if (TREE_VEC_ELT (targs, i) == NULL_TREE)
{
if (!allow_incomplete)
error ("incomplete type unification");
......@@ -5335,11 +5477,13 @@ type_unification_real (tparms, targs, parms, args, subr,
/* Tail recursion is your friend. */
static int
unify (tparms, targs, ntparms, parm, arg, strict)
tree tparms, *targs, parm, arg;
unify (tparms, targs, ntparms, parm, arg, strict, explicit_mask)
tree tparms, targs, parm, arg;
int ntparms, strict;
int* explicit_mask;
{
int idx;
tree targ;
/* I don't think this will do the right thing with respect to types.
But the only case I've seen it in so far has been array bounds, where
......@@ -5372,12 +5516,13 @@ unify (tparms, targs, ntparms, parm, arg, strict)
case TEMPLATE_TYPE_PARM:
idx = TEMPLATE_TYPE_IDX (parm);
targ = TREE_VEC_ELT (targs, idx);
/* Check for mixed types and values. */
if (TREE_CODE (TREE_VALUE (TREE_VEC_ELT (tparms, idx))) != TYPE_DECL)
return 1;
if (!strict && targs[idx] != NULL_TREE &&
TREE_CODE (targs[idx]) == NOP_EXPR)
if (!strict && targ != NULL_TREE
&& explicit_mask && explicit_mask[idx])
/* An explicit template argument. Don't even try to match
here; the overload resolution code will manage check to
see whether the call is legal. */
......@@ -5402,24 +5547,23 @@ unify (tparms, targs, ntparms, parm, arg, strict)
}
#endif
/* Simple cases: Value already set, does match or doesn't. */
if (targs[idx] == arg
|| (targs[idx]
&& TREE_CODE (targs[idx]) == NOP_EXPR
&& TREE_OPERAND (targs[idx], 0) == arg))
if (targ == arg || (targ && explicit_mask && explicit_mask[idx]))
return 0;
else if (targs[idx])
else if (targ)
return 1;
targs[idx] = arg;
TREE_VEC_ELT (targs, idx) = arg;
return 0;
case TEMPLATE_TEMPLATE_PARM:
idx = TEMPLATE_TYPE_IDX (parm);
targ = TREE_VEC_ELT (targs, idx);
/* Check for mixed types and values. */
if (TREE_CODE (TREE_VALUE (TREE_VEC_ELT (tparms, idx))) != TEMPLATE_DECL)
return 1;
if (!strict && targs[idx] != NULL_TREE &&
TREE_CODE (targs[idx]) == NOP_EXPR)
if (!strict && targ != NULL_TREE
&& explicit_mask && explicit_mask[idx])
/* An explicit template argument. Don't even try to match
here; the overload resolution code will manage check to
see whether the call is legal. */
......@@ -5465,7 +5609,7 @@ unify (tparms, targs, ntparms, parm, arg, strict)
/* This argument can be deduced. */
if (unify (tparms, targs, ntparms, t,
TREE_VEC_ELT (argvec, i), strict))
TREE_VEC_ELT (argvec, i), strict, explicit_mask))
return 1;
}
}
......@@ -5473,21 +5617,19 @@ unify (tparms, targs, ntparms, parm, arg, strict)
}
/* Simple cases: Value already set, does match or doesn't. */
if (targs[idx] == arg
|| (targs[idx]
&& TREE_CODE (targs[idx]) == NOP_EXPR
&& TREE_OPERAND (targs[idx], 0) == arg))
if (targ == arg || (targ && explicit_mask && explicit_mask[idx]))
return 0;
else if (targs[idx])
else if (targ)
return 1;
targs[idx] = arg;
TREE_VEC_ELT (targs, idx) = arg;
return 0;
case TEMPLATE_PARM_INDEX:
idx = TEMPLATE_PARM_IDX (parm);
if (targs[idx])
targ = TREE_VEC_ELT (targs, idx);
if (targ)
{
int i = cp_tree_equal (targs[idx], arg);
int i = cp_tree_equal (targ, arg);
if (i == 1)
return 0;
else if (i == 0)
......@@ -5496,24 +5638,24 @@ unify (tparms, targs, ntparms, parm, arg, strict)
my_friendly_abort (42);
}
targs[idx] = copy_to_permanent (arg);
TREE_VEC_ELT (targs, idx) = copy_to_permanent (arg);
return 0;
case POINTER_TYPE:
if (TREE_CODE (arg) == RECORD_TYPE && TYPE_PTRMEMFUNC_FLAG (arg))
return unify (tparms, targs, ntparms, parm,
TYPE_PTRMEMFUNC_FN_TYPE (arg), strict);
TYPE_PTRMEMFUNC_FN_TYPE (arg), strict, explicit_mask);
if (TREE_CODE (arg) != POINTER_TYPE)
return 1;
return unify (tparms, targs, ntparms, TREE_TYPE (parm), TREE_TYPE (arg),
strict);
strict, explicit_mask);
case REFERENCE_TYPE:
if (TREE_CODE (arg) == REFERENCE_TYPE)
arg = TREE_TYPE (arg);
return unify (tparms, targs, ntparms, TREE_TYPE (parm), arg,
strict);
strict, explicit_mask);
case ARRAY_TYPE:
if (TREE_CODE (arg) != ARRAY_TYPE)
......@@ -5523,10 +5665,10 @@ unify (tparms, targs, ntparms, parm, arg, strict)
return 1;
if (TYPE_DOMAIN (parm) != NULL_TREE
&& unify (tparms, targs, ntparms, TYPE_DOMAIN (parm),
TYPE_DOMAIN (arg), strict) != 0)
TYPE_DOMAIN (arg), strict, explicit_mask) != 0)
return 1;
return unify (tparms, targs, ntparms, TREE_TYPE (parm), TREE_TYPE (arg),
strict);
strict, explicit_mask);
case REAL_TYPE:
case COMPLEX_TYPE:
......@@ -5540,11 +5682,11 @@ unify (tparms, targs, ntparms, parm, arg, strict)
{
if (TYPE_MIN_VALUE (parm) && TYPE_MIN_VALUE (arg)
&& unify (tparms, targs, ntparms, TYPE_MIN_VALUE (parm),
TYPE_MIN_VALUE (arg), strict))
TYPE_MIN_VALUE (arg), strict, explicit_mask))
return 1;
if (TYPE_MAX_VALUE (parm) && TYPE_MAX_VALUE (arg)
&& unify (tparms, targs, ntparms, TYPE_MAX_VALUE (parm),
TYPE_MAX_VALUE (arg), strict))
TYPE_MAX_VALUE (arg), strict, explicit_mask))
return 1;
}
else if (TREE_CODE (parm) == REAL_TYPE
......@@ -5565,16 +5707,6 @@ unify (tparms, targs, ntparms, parm, arg, strict)
return 1;
return !tree_int_cst_equal (parm, arg);
case MINUS_EXPR:
{
tree t1, t2;
t1 = TREE_OPERAND (parm, 0);
t2 = TREE_OPERAND (parm, 1);
return unify (tparms, targs, ntparms, t1,
fold (build (PLUS_EXPR, integer_type_node, arg, t2)),
strict);
}
case TREE_VEC:
{
int i;
......@@ -5585,7 +5717,7 @@ unify (tparms, targs, ntparms, parm, arg, strict)
for (i = TREE_VEC_LENGTH (parm) - 1; i >= 0; i--)
if (unify (tparms, targs, ntparms,
TREE_VEC_ELT (parm, i), TREE_VEC_ELT (arg, i),
strict))
strict, explicit_mask))
return 1;
return 0;
}
......@@ -5593,7 +5725,7 @@ unify (tparms, targs, ntparms, parm, arg, strict)
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_FLAG (parm))
return unify (tparms, targs, ntparms, TYPE_PTRMEMFUNC_FN_TYPE (parm),
arg, strict);
arg, strict, explicit_mask);
/* Allow trivial conversions. */
if (TREE_CODE (arg) != RECORD_TYPE
......@@ -5614,7 +5746,7 @@ unify (tparms, targs, ntparms, parm, arg, strict)
return 1;
return unify (tparms, targs, ntparms, CLASSTYPE_TI_ARGS (parm),
CLASSTYPE_TI_ARGS (t), strict);
CLASSTYPE_TI_ARGS (t), strict, explicit_mask);
}
else if (TYPE_MAIN_VARIANT (parm) != TYPE_MAIN_VARIANT (arg))
return 1;
......@@ -5630,20 +5762,20 @@ unify (tparms, targs, ntparms, parm, arg, strict)
return 1;
check_args:
if (unify (tparms, targs, ntparms, TREE_TYPE (parm),
TREE_TYPE (arg), strict))
TREE_TYPE (arg), strict, explicit_mask))
return 1;
return type_unification_real (tparms, targs, TYPE_ARG_TYPES (parm),
TYPE_ARG_TYPES (arg), 1,
strict, 0);
strict, 0, explicit_mask);
case OFFSET_TYPE:
if (TREE_CODE (arg) != OFFSET_TYPE)
return 1;
if (unify (tparms, targs, ntparms, TYPE_OFFSET_BASETYPE (parm),
TYPE_OFFSET_BASETYPE (arg), strict))
TYPE_OFFSET_BASETYPE (arg), strict, explicit_mask))
return 1;
return unify (tparms, targs, ntparms, TREE_TYPE (parm),
TREE_TYPE (arg), strict);
TREE_TYPE (arg), strict, explicit_mask);
case CONST_DECL:
if (arg != decl_constant_value (parm))
......@@ -5655,8 +5787,65 @@ unify (tparms, targs, ntparms, parm, arg, strict)
return 1;
default:
sorry ("use of `%s' in template type unification",
tree_code_name [(int) TREE_CODE (parm)]);
if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (parm))))
{
/* We're looking at an expression. This can happen with
something like:
template <int I>
void foo(S<I>, S<I + 2>);
If the call looked like:
foo(S<2>(), S<4>());
we would have already matched `I' with `2'. Now, we'd
like to know if `4' matches `I + 2'. So, we substitute
into that expression, and fold constants, in the hope of
figuring it out. */
tree t =
maybe_fold_nontype_arg (tsubst_expr (parm, targs, NULL_TREE));
enum tree_code tc = TREE_CODE (t);
if (tc == MINUS_EXPR
&& TREE_CODE (TREE_OPERAND (t, 0)) == TEMPLATE_PARM_INDEX
&& TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST)
{
/* We handle this case specially, since it comes up with
arrays. In particular, something like:
template <int N> void f(int (&x)[N]);
Here, we are trying to unify the range type, which
looks like [0 ... (N - 1)]. */
tree t1, t2;
t1 = TREE_OPERAND (parm, 0);
t2 = TREE_OPERAND (parm, 1);
t = maybe_fold_nontype_arg (build (PLUS_EXPR,
integer_type_node,
arg, t2));
return unify (tparms, targs, ntparms, t1, t,
strict, explicit_mask);
}
if (!IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (tc)))
/* Good, we mangaged to simplify the exression. */
return unify (tparms, targs, ntparms, t, arg, strict,
explicit_mask);
else
/* Bad, we couldn't simplify this. Assume it doesn't
unify. */
return 1;
}
else
{
sorry ("use of `%s' in template type unification",
tree_code_name [(int) TREE_CODE (parm)]);
break;
}
return 1;
}
}
......@@ -5837,8 +6026,9 @@ get_class_bindings (tparms, parms, args, outer_args)
for (i = 0; i < TREE_VEC_LENGTH (parms); ++i)
{
switch (unify (tparms, &TREE_VEC_ELT (vec, 0), ntparms,
TREE_VEC_ELT (parms, i), TREE_VEC_ELT (args, i), 1))
switch (unify (tparms, vec, ntparms,
TREE_VEC_ELT (parms, i), TREE_VEC_ELT (args, i),
1, 0))
{
case 0:
break;
......
......@@ -197,7 +197,8 @@ static const struct optable
{"min", "<?", 0}, /* old */
{"mn", "<?", DMGL_ANSI}, /* pseudo-ansi */
{"nop", "", 0}, /* old (for operator=) */
{"rm", "->*", DMGL_ANSI} /* ansi */
{"rm", "->*", DMGL_ANSI}, /* ansi */
{"sz", "sizeof ", DMGL_ANSI} /* pseudo-ansi */
};
......@@ -330,6 +331,10 @@ forget_types PARAMS ((struct work_stuff *));
static void
string_prepends PARAMS ((string *, string *));
static int
demangle_template_value_parm PARAMS ((struct work_stuff*,
const char**, string*));
/* Translate count to integer, consuming tokens in the process.
Conversion terminates on the first non-digit character.
Trying to consume something that isn't a count results in
......@@ -996,6 +1001,270 @@ demangle_template_template_parm (work, mangled, tname)
}
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;
......@@ -1004,18 +1273,10 @@ demangle_template (work, mangled, tname, trawname, is_type)
int is_type;
{
int i;
int is_pointer;
int is_real;
int is_integral;
int is_char;
int is_bool;
int r;
int need_comma = 0;
int success = 0;
int done;
const char *old_p;
const char *start;
int symbol_len;
int is_java_array = 0;
string temp;
......@@ -1148,13 +1409,7 @@ demangle_template (work, mangled, tname, trawname, is_type)
string* s;
/* otherwise, value parameter */
old_p = *mangled;
is_pointer = 0;
is_real = 0;
is_integral = 0;
is_char = 0;
is_bool = 0;
done = 0;
/* temp is initialized in do_type */
success = do_type (work, mangled, &temp);
/*
......@@ -1180,193 +1435,16 @@ demangle_template (work, mangled, tname, trawname, is_type)
else
s = tname;
while (*old_p && !done)
{
switch (*old_p)
{
case 'P':
case 'p':
case 'R':
done = is_pointer = 1;
break;
case 'C': /* const */
case 'S': /* explicitly signed [char] */
case 'U': /* unsigned */
case 'V': /* volatile */
case 'F': /* function */
case 'M': /* member function */
case 'O': /* ??? */
case 'J': /* complex */
old_p++;
continue;
case 'Q': /* qualified name */
done = is_integral = 1;
break;
case 'T': /* remembered type */
abort ();
break;
case 'v': /* void */
abort ();
break;
case 'x': /* long long */
case 'l': /* long */
case 'i': /* int */
case 's': /* short */
case 'w': /* wchar_t */
done = is_integral = 1;
break;
case 'b': /* bool */
done = is_bool = 1;
break;
case 'c': /* char */
done = is_char = 1;
break;
case 'r': /* long double */
case 'd': /* double */
case 'f': /* float */
done = is_real = 1;
break;
default:
/* it's probably user defined type, let's assume
it's integral, it seems hard to figure out
what it really is */
done = is_integral = 1;
}
}
if (**mangled == 'Y')
{
/* The next argument is a template parameter. */
int idx;
success = demangle_template_value_parm (work, mangled, s);
(*mangled)++;
idx = consume_count_with_underscores (mangled);
if (idx == -1
|| (work->tmpl_argvec && idx >= work->ntmpl_args)
|| consume_count_with_underscores (mangled) == -1)
{
success = 0;
if (!is_type)
string_delete (s);
break;
}
if (work->tmpl_argvec)
string_append (s, work->tmpl_argvec[idx]);
else
{
char buf[10];
sprintf(buf, "T%d", idx);
string_append (s, buf);
}
}
else if (is_integral)
{
if (**mangled == 'm')
{
string_appendn (s, "-", 1);
(*mangled)++;
}
while (isdigit (**mangled))
{
string_appendn (s, *mangled, 1);
(*mangled)++;
}
}
else if (is_char)
{
char tmp[2];
int val;
if (**mangled == 'm')
{
string_appendn (s, "-", 1);
(*mangled)++;
}
string_appendn (s, "'", 1);
val = consume_count(mangled);
if (val == 0)
{
success = 0;
if (!is_type)
string_delete (s);
break;
}
tmp[0] = (char)val;
tmp[1] = '\0';
string_appendn (s, &tmp[0], 1);
string_appendn (s, "'", 1);
}
else if (is_bool)
{
int val = consume_count (mangled);
if (val == 0)
string_appendn (s, "false", 5);
else if (val == 1)
string_appendn (s, "true", 4);
else
success = 0;
}
else if (is_real)
{
if (**mangled == 'm')
{
string_appendn (s, "-", 1);
(*mangled)++;
}
while (isdigit (**mangled))
{
string_appendn (s, *mangled, 1);
(*mangled)++;
}
if (**mangled == '.') /* fraction */
{
string_appendn (s, ".", 1);
(*mangled)++;
while (isdigit (**mangled))
{
string_appendn (s, *mangled, 1);
(*mangled)++;
}
}
if (**mangled == 'e') /* exponent */
{
string_appendn (s, "e", 1);
(*mangled)++;
while (isdigit (**mangled))
{
string_appendn (s, *mangled, 1);
(*mangled)++;
}
}
}
else if (is_pointer)
if (!success)
{
symbol_len = consume_count (mangled);
if (symbol_len == 0)
{
success = 0;
if (!is_type)
string_delete (s);
break;
}
if (symbol_len == 0)
string_appendn (s, "0", 1);
else
{
char *p = xmalloc (symbol_len + 1), *q;
strncpy (p, *mangled, symbol_len);
p [symbol_len] = '\0';
q = cplus_demangle (p, work->options);
string_appendn (s, "&", 1);
if (q)
{
string_append (s, q);
free (q);
}
else
string_append (s, p);
free (p);
}
*mangled += symbol_len;
if (!is_type)
string_delete (s);
success = 0;
break;
}
if (!is_type)
{
int len = s->p - s->b;
......
// 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