* 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
+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.
$(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 $@ \
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,
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)
{
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));
}
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:
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
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;
}
{
/* 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;
}
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)
{
case BOOLEAN_TYPE:
{
build_overload_int (value, in_template);
- numeric_output_need_bar = 1;
return;
}
case REAL_TYPE:
{
OB_PUTC ('i');
build_overload_int (a3, in_template);
- numeric_output_need_bar = 1;
return;
}
}
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)
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 */
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;
}
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);
#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;
#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));
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
/* 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,
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
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
lookup_template_function (fns, arglist)
tree fns, arglist;
{
+ tree t;
+
if (fns == NULL_TREE)
{
cp_error ("non-template used as template");
/* 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;
/* 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))
{
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 */
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;
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:
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;
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:
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)))
{
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;
}
}
}
+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;
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 */
{
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)
}
}
+ 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:
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,
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)
{
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;
&& 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),
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;
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");
/* 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
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. */
}
#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. */
/* 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;
}
}
}
/* 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)
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)
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:
{
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
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;
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;
}
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
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;
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))
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;
}
}
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;
{"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 */
};
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
return (success);
}
+static int
+demangle_integral_value (work, mangled, s)
+ struct work_stuff *work;
+ const char** mangled;
+ string* s;
+{
+ int success;
+
+ if (**mangled == 'E')
+ {
+ int need_operator = 0;
+
+ success = 1;
+ string_appendn (s, "(", 1);
+ (*mangled)++;
+ while (success && **mangled != 'W' && **mangled != '\0')
+ {
+ if (need_operator)
+ {
+ size_t i;
+ size_t len;
+
+ success = 0;
+
+ len = strlen (*mangled);
+
+ for (i = 0;
+ i < sizeof (optable) / sizeof (optable [0]);
+ ++i)
+ {
+ size_t l = strlen (optable[i].in);
+
+ if (l <= len
+ && memcmp (optable[i].in, *mangled, l) == 0)
+ {
+ string_appendn (s, " ", 1);
+ string_append (s, optable[i].out);
+ string_appendn (s, " ", 1);
+ success = 1;
+ (*mangled) += l;
+ break;
+ }
+ }
+
+ if (!success)
+ break;
+ }
+ else
+ need_operator = 1;
+
+ success = demangle_template_value_parm (work, mangled, s);
+ }
+
+ if (**mangled != 'W')
+ success = 0;
+ else
+ {
+ string_appendn (s, ")", 1);
+ (*mangled)++;
+ }
+ }
+ else if (**mangled == 'Q')
+ success = demangle_qualified (work, mangled, s, 0, 1);
+ else
+ {
+ success = 0;
+
+ if (**mangled == 'm')
+ {
+ string_appendn (s, "-", 1);
+ (*mangled)++;
+ }
+ while (isdigit (**mangled))
+ {
+ string_appendn (s, *mangled, 1);
+ (*mangled)++;
+ success = 1;
+ }
+ }
+
+ return success;
+}
+
+static int
+demangle_template_value_parm (work, mangled, s)
+ struct work_stuff *work;
+ const char **mangled;
+ string* s;
+{
+ const char *old_p = *mangled;
+ int is_pointer = 0;
+ int is_real = 0;
+ int is_integral = 0;
+ int is_char = 0;
+ int is_bool = 0;
+ int done = 0;
+ int success = 1;
+
+ while (*old_p && !done)
+ {
+ switch (*old_p)
+ {
+ case 'P':
+ case 'p':
+ case 'R':
+ done = is_pointer = 1;
+ break;
+ case 'C': /* const */
+ case 'S': /* explicitly signed [char] */
+ case 'U': /* unsigned */
+ case 'V': /* volatile */
+ case 'F': /* function */
+ case 'M': /* member function */
+ case 'O': /* ??? */
+ case 'J': /* complex */
+ old_p++;
+ continue;
+ case 'E': /* expression */
+ case 'Q': /* qualified name */
+ done = is_integral = 1;
+ break;
+ case 'T': /* remembered type */
+ abort ();
+ break;
+ case 'v': /* void */
+ abort ();
+ break;
+ case 'x': /* long long */
+ case 'l': /* long */
+ case 'i': /* int */
+ case 's': /* short */
+ case 'w': /* wchar_t */
+ done = is_integral = 1;
+ break;
+ case 'b': /* bool */
+ done = is_bool = 1;
+ break;
+ case 'c': /* char */
+ done = is_char = 1;
+ break;
+ case 'r': /* long double */
+ case 'd': /* double */
+ case 'f': /* float */
+ done = is_real = 1;
+ break;
+ default:
+ /* it's probably user defined type, let's assume
+ it's integral, it seems hard to figure out
+ what it really is */
+ done = is_integral = 1;
+ }
+ }
+ if (**mangled == 'Y')
+ {
+ /* The next argument is a template parameter. */
+ int idx;
+
+ (*mangled)++;
+ idx = consume_count_with_underscores (mangled);
+ if (idx == -1
+ || (work->tmpl_argvec && idx >= work->ntmpl_args)
+ || consume_count_with_underscores (mangled) == -1)
+ return -1;
+ if (work->tmpl_argvec)
+ string_append (s, work->tmpl_argvec[idx]);
+ else
+ {
+ char buf[10];
+ sprintf(buf, "T%d", idx);
+ string_append (s, buf);
+ }
+ }
+ else if (is_integral)
+ success = demangle_integral_value (work, mangled, s);
+ else if (is_char)
+ {
+ char tmp[2];
+ int val;
+ if (**mangled == 'm')
+ {
+ string_appendn (s, "-", 1);
+ (*mangled)++;
+ }
+ string_appendn (s, "'", 1);
+ val = consume_count(mangled);
+ if (val == 0)
+ return -1;
+ tmp[0] = (char)val;
+ tmp[1] = '\0';
+ string_appendn (s, &tmp[0], 1);
+ string_appendn (s, "'", 1);
+ }
+ else if (is_bool)
+ {
+ int val = consume_count (mangled);
+ if (val == 0)
+ string_appendn (s, "false", 5);
+ else if (val == 1)
+ string_appendn (s, "true", 4);
+ else
+ success = 0;
+ }
+ else if (is_real)
+ {
+ if (**mangled == 'm')
+ {
+ string_appendn (s, "-", 1);
+ (*mangled)++;
+ }
+ while (isdigit (**mangled))
+ {
+ string_appendn (s, *mangled, 1);
+ (*mangled)++;
+ }
+ if (**mangled == '.') /* fraction */
+ {
+ string_appendn (s, ".", 1);
+ (*mangled)++;
+ while (isdigit (**mangled))
+ {
+ string_appendn (s, *mangled, 1);
+ (*mangled)++;
+ }
+ }
+ if (**mangled == 'e') /* exponent */
+ {
+ string_appendn (s, "e", 1);
+ (*mangled)++;
+ while (isdigit (**mangled))
+ {
+ string_appendn (s, *mangled, 1);
+ (*mangled)++;
+ }
+ }
+ }
+ else if (is_pointer)
+ {
+ int symbol_len = consume_count (mangled);
+ if (symbol_len == 0)
+ return -1;
+ if (symbol_len == 0)
+ string_appendn (s, "0", 1);
+ else
+ {
+ char *p = xmalloc (symbol_len + 1), *q;
+ strncpy (p, *mangled, symbol_len);
+ p [symbol_len] = '\0';
+ q = cplus_demangle (p, work->options);
+ string_appendn (s, "&", 1);
+ if (q)
+ {
+ string_append (s, q);
+ free (q);
+ }
+ else
+ string_append (s, p);
+ free (p);
+ }
+ *mangled += symbol_len;
+ }
+
+ return success;
+}
+
static int
demangle_template (work, mangled, tname, trawname, is_type)
struct work_stuff *work;
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;
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);
/*
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;
--- /dev/null
+// Build don't link:
+
+template <unsigned rank>
+class Tensor
+{
+};
+
+template <unsigned rank>
+class Tensor<2> : Tensor<rank> { // ERROR - template parameters not used
+};
+
--- /dev/null
+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.);
+}
--- /dev/null
+// 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.
+}
--- /dev/null
+// 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.
+}
--- /dev/null
+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>());
+}
+