PATCH for partial specialization crash
Mark Mitchell
mmitchell@usa.net
Sat Mar 21 18:37:00 GMT 1998
Jason --
Here's a revised (and hopefully improved) version of the
partial-specialization patch I submitted, and then retracted, earlier.
Is this OK?
--
Mark Mitchell <mmitchell@usa.net>
http://home.earthlink.net/~mbmitchell
Consulting Services Available
Sat Mar 21 18:28:47 1998 Mark Mitchell <mmitchell@usa.net>
* error.c (dump_expr): Remove unused variable `l'.
* cp-tree.h (tree_fn_t): New typedef.
* pt.c (for_each_template_parm): New function, created by
converting uses_template_parms.
(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.
Index: cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.43
diff -c -p -r1.43 cp-tree.h
*** cp-tree.h 1998/03/18 10:51:54 1.43
--- cp-tree.h 1998/03/22 02:23:06
*************** typedef struct
*** 58,63 ****
--- 58,67 ----
tree decl;
} template_parm_index;
+ /* The type of functions taking a tree, and some additional data, and
+ returning an int. */
+ typedef int (*tree_fn_t) PROTO((tree, void*));
+
#define BINDING_SCOPE(NODE) (((struct tree_binding*)NODE)->scope)
#define BINDING_VALUE(NODE) (((struct tree_binding*)NODE)->value)
#define NAMESPACE_BINDING(ID,NS) BINDING_VALUE (binding_for_name (ID, NS))
Index: error.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/error.c,v
retrieving revision 1.29
diff -c -p -r1.29 error.c
*** error.c 1998/02/25 00:49:45 1.29
--- error.c 1998/03/22 02:23:11
*************** dump_expr (t, nop)
*** 1533,1544 ****
}
case TEMPLATE_PARM_INDEX:
! {
! int l = current_template_parms ?
! list_length (current_template_parms) : 0;
!
! dump_decl (TEMPLATE_PARM_DECL (t), -1);
! }
break;
case IDENTIFIER_NODE:
--- 1533,1539 ----
}
case TEMPLATE_PARM_INDEX:
! dump_decl (TEMPLATE_PARM_DECL (t), -1);
break;
case IDENTIFIER_NODE:
Index: pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.101
diff -c -p -r1.101 pt.c
*** pt.c 1998/03/20 10:44:05 1.101
--- pt.c 1998/03/22 02:23:26
*************** static void note_template_header PROTO((
*** 88,93 ****
--- 88,94 ----
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
*************** build_template_decl (decl, parms)
*** 1465,1471 ****
return tmpl;
}
!
/* 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
--- 1466,1509 ----
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 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
*************** push_template_decl (decl)
*** 1530,1535 ****
--- 1568,1633 ----
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_class (d1, arglist, in_d
*** 2738,2746 ****
/* Should be defined in parse.h. */
extern int yychar;
int
! uses_template_parms (t)
tree t;
{
if (!t)
return 0;
--- 2836,2854 ----
/* 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
! for_each_template_parm (t, fn, data)
tree t;
+ tree_fn_t fn;
+ void* data;
{
if (!t)
return 0;
*************** uses_template_parms (t)
*** 2751,2757 ****
/* 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));
case IDENTIFIER_NODE:
if (!IDENTIFIER_TEMPLATE (t))
--- 2859,2865 ----
/* 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 for_each_template_parm (TREE_TYPE (t), fn, data);
case IDENTIFIER_NODE:
if (!IDENTIFIER_TEMPLATE (t))
*************** uses_template_parms (t)
*** 2763,2811 ****
{
int i = TREE_VEC_LENGTH (t);
while (i--)
! if (uses_template_parms (TREE_VEC_ELT (t, i)))
return 1;
return 0;
}
case TREE_LIST:
! if (uses_template_parms (TREE_PURPOSE (t))
! || uses_template_parms (TREE_VALUE (t)))
return 1;
! return uses_template_parms (TREE_CHAIN (t));
/* constructed type nodes */
case POINTER_TYPE:
case REFERENCE_TYPE:
! return uses_template_parms (TREE_TYPE (t));
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_FLAG (t))
! return uses_template_parms (TYPE_PTRMEMFUNC_FN_TYPE (t));
case UNION_TYPE:
if (! CLASSTYPE_TEMPLATE_INFO (t))
return 0;
! return uses_template_parms (TREE_VALUE (CLASSTYPE_TEMPLATE_INFO (t)));
case FUNCTION_TYPE:
! if (uses_template_parms (TYPE_ARG_TYPES (t)))
return 1;
! return uses_template_parms (TREE_TYPE (t));
case ARRAY_TYPE:
! if (uses_template_parms (TYPE_DOMAIN (t)))
return 1;
! return uses_template_parms (TREE_TYPE (t));
case OFFSET_TYPE:
! if (uses_template_parms (TYPE_OFFSET_BASETYPE (t)))
return 1;
! return uses_template_parms (TREE_TYPE (t));
case METHOD_TYPE:
! if (uses_template_parms (TYPE_METHOD_BASETYPE (t)))
return 1;
! if (uses_template_parms (TYPE_ARG_TYPES (t)))
return 1;
! return uses_template_parms (TREE_TYPE (t));
/* decl nodes */
case TYPE_DECL:
! return uses_template_parms (TREE_TYPE (t));
case TEMPLATE_DECL:
/* A template template parameter is encountered */
--- 2871,2922 ----
{
int i = TREE_VEC_LENGTH (t);
while (i--)
! if (for_each_template_parm (TREE_VEC_ELT (t, i), fn, data))
return 1;
return 0;
}
case TREE_LIST:
! if (for_each_template_parm (TREE_PURPOSE (t), fn, data)
! || for_each_template_parm (TREE_VALUE (t), fn, data))
return 1;
! return for_each_template_parm (TREE_CHAIN (t), fn, data);
/* constructed type nodes */
case POINTER_TYPE:
case REFERENCE_TYPE:
! return for_each_template_parm (TREE_TYPE (t), fn, data);
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_FLAG (t))
! return for_each_template_parm (TYPE_PTRMEMFUNC_FN_TYPE (t),
! fn, data);
case UNION_TYPE:
if (! CLASSTYPE_TEMPLATE_INFO (t))
return 0;
! return for_each_template_parm (TREE_VALUE
! (CLASSTYPE_TEMPLATE_INFO (t)),
! fn, data);
case FUNCTION_TYPE:
! if (for_each_template_parm (TYPE_ARG_TYPES (t), fn, data))
return 1;
! return for_each_template_parm (TREE_TYPE (t), fn, data);
case ARRAY_TYPE:
! if (for_each_template_parm (TYPE_DOMAIN (t), fn, data))
return 1;
! return for_each_template_parm (TREE_TYPE (t), fn, data);
case OFFSET_TYPE:
! if (for_each_template_parm (TYPE_OFFSET_BASETYPE (t), fn, data))
return 1;
! return for_each_template_parm (TREE_TYPE (t), fn, data);
case METHOD_TYPE:
! if (for_each_template_parm (TYPE_METHOD_BASETYPE (t), fn, data))
return 1;
! if (for_each_template_parm (TYPE_ARG_TYPES (t), fn, data))
return 1;
! return for_each_template_parm (TREE_TYPE (t), fn, data);
/* decl nodes */
case TYPE_DECL:
! return for_each_template_parm (TREE_TYPE (t), fn, data);
case TEMPLATE_DECL:
/* A template template parameter is encountered */
*************** uses_template_parms (t)
*** 2817,2823 ****
return 0;
case CONST_DECL:
! if (uses_template_parms (DECL_INITIAL (t)))
return 1;
goto check_type_and_context;
--- 2928,2934 ----
return 0;
case CONST_DECL:
! if (for_each_template_parm (DECL_INITIAL (t), fn, data))
return 1;
goto check_type_and_context;
*************** uses_template_parms (t)
*** 2825,2857 ****
case VAR_DECL:
/* ??? What about FIELD_DECLs? */
if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t)
! && uses_template_parms (DECL_TI_ARGS (t)))
return 1;
/* fall through */
case PARM_DECL:
check_type_and_context:
! if (uses_template_parms (TREE_TYPE (t)))
return 1;
! if (DECL_CONTEXT (t) && uses_template_parms (DECL_CONTEXT (t)))
return 1;
return 0;
case CALL_EXPR:
! return uses_template_parms (TREE_TYPE (t));
case ADDR_EXPR:
! return uses_template_parms (TREE_OPERAND (t, 0));
/* template parm nodes */
case TEMPLATE_TYPE_PARM:
case TEMPLATE_TEMPLATE_PARM:
case TEMPLATE_PARM_INDEX:
! return 1;
/* simple type nodes */
case INTEGER_TYPE:
! if (uses_template_parms (TYPE_MIN_VALUE (t)))
return 1;
! return uses_template_parms (TYPE_MAX_VALUE (t));
case REAL_TYPE:
case COMPLEX_TYPE:
--- 2936,2972 ----
case VAR_DECL:
/* ??? What about FIELD_DECLs? */
if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t)
! && for_each_template_parm (DECL_TI_ARGS (t), fn, data))
return 1;
/* fall through */
case PARM_DECL:
check_type_and_context:
! if (for_each_template_parm (TREE_TYPE (t), fn, data))
return 1;
! if (DECL_CONTEXT (t)
! && for_each_template_parm (DECL_CONTEXT (t), fn, data))
return 1;
return 0;
case CALL_EXPR:
! return for_each_template_parm (TREE_TYPE (t), fn, data);
case ADDR_EXPR:
! 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:
! if (fn)
! return (*fn)(t, data);
! else
! return 1;
/* simple type nodes */
case INTEGER_TYPE:
! if (for_each_template_parm (TYPE_MIN_VALUE (t), fn, data))
return 1;
! return for_each_template_parm (TYPE_MAX_VALUE (t), fn, data);
case REAL_TYPE:
case COMPLEX_TYPE:
*************** uses_template_parms (t)
*** 2864,2870 ****
tree v;
for (v = TYPE_VALUES (t); v != NULL_TREE; v = TREE_CHAIN (v))
! if (uses_template_parms (TREE_VALUE (v)))
return 1;
}
return 0;
--- 2979,2985 ----
tree v;
for (v = TYPE_VALUES (t); v != NULL_TREE; v = TREE_CHAIN (v))
! if (for_each_template_parm (TREE_VALUE (v), fn, data))
return 1;
}
return 0;
*************** uses_template_parms (t)
*** 2886,2897 ****
return 1;
case SCOPE_REF:
! return uses_template_parms (TREE_OPERAND (t, 0));
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));
case MODOP_EXPR:
case CAST_EXPR:
--- 3001,3013 ----
return 1;
case SCOPE_REF:
! return for_each_template_parm (TREE_OPERAND (t, 0), fn, data);
case CONSTRUCTOR:
if (TREE_TYPE (t) && TYPE_PTRMEMFUNC_P (TREE_TYPE (t)))
! 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:
*************** uses_template_parms (t)
*** 2906,2912 ****
case SIZEOF_EXPR:
case ALIGNOF_EXPR:
! return uses_template_parms (TREE_OPERAND (t, 0));
default:
switch (TREE_CODE_CLASS (TREE_CODE (t)))
--- 3022,3028 ----
case SIZEOF_EXPR:
case ALIGNOF_EXPR:
! return for_each_template_parm (TREE_OPERAND (t, 0), fn, data);
default:
switch (TREE_CODE_CLASS (TREE_CODE (t)))
*************** uses_template_parms (t)
*** 2918,2924 ****
{
int i;
for (i = tree_code_length[(int) TREE_CODE (t)]; --i >= 0;)
! if (uses_template_parms (TREE_OPERAND (t, i)))
return 1;
return 0;
}
--- 3034,3040 ----
{
int i;
for (i = tree_code_length[(int) TREE_CODE (t)]; --i >= 0;)
! if (for_each_template_parm (TREE_OPERAND (t, i), fn, data))
return 1;
return 0;
}
*************** uses_template_parms (t)
*** 2933,2938 ****
--- 3049,3061 ----
}
}
+ 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;
Index: testsuite/g++.old-deja/g++.pt/crash4.C
===================================================================
RCS file: crash4.C
diff -N crash4.C
*** /dev/null Mon Dec 31 20:00:00 1979
--- crash4.C Sat Mar 21 18:29:40 1998
***************
*** 0 ****
--- 1,12 ----
+ // Build don't link:
+
+ template <unsigned rank>
+ class Tensor
+ {
+ };
+
+ template <unsigned rank>
+ class Tensor<2> : Tensor<rank> // ERROR - template parameters not used
+ {
+ };
+
More information about the Gcc-bugs
mailing list