cp-tree.h (TI_PENDING_SPECIALIZATION_FLAG): Remove.
* cp-tree.h (TI_PENDING_SPECIALIZATION_FLAG): Remove. * class.c (finish_struct): Remove hackery to deal with explicit specializations in class scope. * decl.c (grokfndecl): Improve error-recovery. * decl2.c (grokfield): Likewise. * pt.c (check_specialization_scope): New function. (begin_specialization): Call it. (process_partial_specialization): New function, split out from push_template_decl. Check partial specializations more stringently. (push_template_decl): Call it. (check_explicit_specialization): Don't attempt to handle explicit specializations in class scope. (template_parm_data): Document. Add current_arg and arg_uses_template_parms. (mark_template_parm): Set it. (tsubst_arg_types): Remove unused variable. * semantics.c (begin_class_definition): Tweak. From-SVN: r22271
This commit is contained in:
parent
00dd3ccd9b
commit
6c30752f09
@ -1,3 +1,24 @@
|
||||
1998-09-05 Mark Mitchell <mark@markmitchell.com>
|
||||
|
||||
* cp-tree.h (TI_PENDING_SPECIALIZATION_FLAG): Remove.
|
||||
* class.c (finish_struct): Remove hackery to deal with explicit
|
||||
specializations in class scope.
|
||||
* decl.c (grokfndecl): Improve error-recovery.
|
||||
* decl2.c (grokfield): Likewise.
|
||||
* pt.c (check_specialization_scope): New function.
|
||||
(begin_specialization): Call it.
|
||||
(process_partial_specialization): New function, split out from
|
||||
push_template_decl. Check partial specializations more
|
||||
stringently.
|
||||
(push_template_decl): Call it.
|
||||
(check_explicit_specialization): Don't attempt to handle explicit
|
||||
specializations in class scope.
|
||||
(template_parm_data): Document. Add current_arg and
|
||||
arg_uses_template_parms.
|
||||
(mark_template_parm): Set it.
|
||||
(tsubst_arg_types): Remove unused variable.
|
||||
* semantics.c (begin_class_definition): Tweak.
|
||||
|
||||
1998-09-04 Mark Mitchell <mark@markmitchell.com>
|
||||
|
||||
* inc/typeinfo (type_info::type_info(const char*)): Make
|
||||
|
@ -4148,8 +4148,6 @@ finish_struct (t, list_of_fieldlists, attributes, warn_anon)
|
||||
{
|
||||
tree fields = NULL_TREE;
|
||||
tree *tail = &TYPE_METHODS (t);
|
||||
tree specializations = NULL_TREE;
|
||||
tree *specialization_tail = &specializations;
|
||||
tree name = TYPE_NAME (t);
|
||||
tree x, last_x = NULL_TREE;
|
||||
tree access;
|
||||
@ -4259,19 +4257,6 @@ finish_struct (t, list_of_fieldlists, attributes, warn_anon)
|
||||
if (last_x)
|
||||
TREE_CHAIN (last_x) = next_x;
|
||||
|
||||
if (DECL_TEMPLATE_SPECIALIZATION (x))
|
||||
/* We don't enter the specialization into the class
|
||||
method vector since specializations don't affect
|
||||
overloading. Instead we keep track of the
|
||||
specializations, and process them after the method
|
||||
vector is complete. */
|
||||
{
|
||||
*specialization_tail = x;
|
||||
specialization_tail = &TREE_CHAIN (x);
|
||||
TREE_CHAIN (x) = NULL_TREE;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Link x onto end of TYPE_METHODS. */
|
||||
*tail = x;
|
||||
tail = &TREE_CHAIN (x);
|
||||
@ -4359,27 +4344,6 @@ finish_struct (t, list_of_fieldlists, attributes, warn_anon)
|
||||
t = finish_struct_1 (t, warn_anon);
|
||||
|
||||
TYPE_BEING_DEFINED (t) = 0;
|
||||
|
||||
/* Now, figure out which member templates we're specializing. */
|
||||
for (x = specializations; x != NULL_TREE; x = TREE_CHAIN (x))
|
||||
{
|
||||
int pending_specialization;
|
||||
|
||||
pending_specialization
|
||||
= TI_PENDING_SPECIALIZATION_FLAG (DECL_TEMPLATE_INFO (x));
|
||||
check_explicit_specialization
|
||||
(lookup_template_function (DECL_NAME (x), DECL_TI_ARGS (x)),
|
||||
x, 0, 1 | (8 * pending_specialization));
|
||||
TI_PENDING_SPECIALIZATION_FLAG (DECL_TEMPLATE_INFO (x)) = 0;
|
||||
|
||||
/* Now, the assembler name will be correct for fn, so we
|
||||
make its RTL. */
|
||||
DECL_RTL (x) = 0;
|
||||
make_decl_rtl (x, NULL_PTR, 1);
|
||||
DECL_RTL (DECL_TI_TEMPLATE (x)) = 0;
|
||||
make_decl_rtl (DECL_TI_TEMPLATE (x), NULL_PTR, 1);
|
||||
}
|
||||
|
||||
if (current_class_type)
|
||||
popclass (0);
|
||||
else
|
||||
|
@ -35,7 +35,6 @@ Boston, MA 02111-1307, USA. */
|
||||
(TREE_MANGLED) (in IDENTIFIER_NODE) (commented-out).
|
||||
1: IDENTIFIER_VIRTUAL_P.
|
||||
TI_PENDING_TEMPLATE_FLAG.
|
||||
TI_PENDING_SPECIALIZATION_FLAG.
|
||||
TEMPLATE_PARMS_FOR_INLINE.
|
||||
DELETE_EXPR_USE_VEC (in DELETE_EXPR).
|
||||
(TREE_CALLS_NEW) (in _EXPR or _REF) (commented-out).
|
||||
@ -1267,11 +1266,6 @@ struct lang_decl
|
||||
#define TI_SPEC_INFO(NODE) (TREE_CHAIN (NODE))
|
||||
#define TI_PENDING_TEMPLATE_FLAG(NODE) TREE_LANG_FLAG_1 (NODE)
|
||||
|
||||
/* TI_PENDING_SPECIALIZATION_FLAG on a template-info node indicates
|
||||
that the template is a specialization of a member template, but
|
||||
that we don't yet know which one. */
|
||||
#define TI_PENDING_SPECIALIZATION_FLAG(NODE) TREE_LANG_FLAG_1 (NODE)
|
||||
|
||||
/* The TEMPLATE_DECL instantiated or specialized by NODE. This
|
||||
TEMPLATE_DECL will be the immediate parent, not the most general
|
||||
template. For example, in:
|
||||
|
@ -8016,6 +8016,8 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
|
||||
template_count,
|
||||
2 * (funcdef_flag != 0) +
|
||||
4 * (friendp != 0));
|
||||
if (decl == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
if ((! TYPE_FOR_JAVA (ctype) || check_java_method (ctype, decl))
|
||||
&& check)
|
||||
@ -8063,6 +8065,9 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
|
||||
template_count,
|
||||
2 * (funcdef_flag != 0) +
|
||||
4 * (friendp != 0));
|
||||
if (decl == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
if (ctype != NULL_TREE
|
||||
&& (! TYPE_FOR_JAVA (ctype) || check_java_method (ctype, decl))
|
||||
&& check)
|
||||
@ -10392,10 +10397,15 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
|
||||
if (decl && DECL_NAME (decl))
|
||||
{
|
||||
if (template_class_depth (current_class_type) == 0)
|
||||
decl
|
||||
= check_explicit_specialization
|
||||
(declarator, decl,
|
||||
template_count, 2 * (funcdef_flag != 0) + 4);
|
||||
{
|
||||
decl
|
||||
= check_explicit_specialization
|
||||
(declarator, decl,
|
||||
template_count, 2 * (funcdef_flag != 0) + 4);
|
||||
if (decl == error_mark_node)
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
t = do_friend (ctype, declarator, decl,
|
||||
last_function_parms, flags, quals,
|
||||
funcdef_flag);
|
||||
|
@ -1606,8 +1606,8 @@ grokfield (declarator, declspecs, init, asmspec_tree, attrlist)
|
||||
init = NULL_TREE;
|
||||
|
||||
value = grokdeclarator (declarator, declspecs, FIELD, init != 0, NULL_TREE);
|
||||
if (! value)
|
||||
return value; /* friend or constructor went bad. */
|
||||
if (! value || value == error_mark_node)
|
||||
return NULL_TREE; /* friend or constructor went bad. */
|
||||
|
||||
/* Pass friendly classes back. */
|
||||
if (TREE_CODE (value) == VOID_TYPE)
|
||||
|
347
gcc/cp/pt.c
347
gcc/cp/pt.c
@ -127,6 +127,8 @@ static int template_class_depth_real PROTO((tree, int));
|
||||
static tree tsubst_aggr_type PROTO((tree, tree, tree, int));
|
||||
static tree tsubst_decl PROTO((tree, tree, tree, tree));
|
||||
static tree tsubst_arg_types PROTO((tree, tree, tree));
|
||||
static void check_specialization_scope PROTO((void));
|
||||
static tree process_partial_specialization PROTO((tree));
|
||||
|
||||
/* We use TREE_VECs to hold template arguments. If there is only one
|
||||
level of template arguments, then the TREE_VEC contains the
|
||||
@ -575,12 +577,44 @@ begin_template_parm_list ()
|
||||
note_template_header (0);
|
||||
}
|
||||
|
||||
/* This routine is called when a specialization is declared. If it is
|
||||
illegal to declare a specialization here, an error is reported. */
|
||||
|
||||
void
|
||||
check_specialization_scope ()
|
||||
{
|
||||
tree scope = current_scope ();
|
||||
/* [temp.expl.spec]
|
||||
|
||||
An explicit specialization shall be declared in the namespace of
|
||||
which the template is a member, or, for member templates, in the
|
||||
namespace of which the enclosing class or enclosing class
|
||||
template is a member. An explicit specialization of a member
|
||||
function, member class or static data member of a class template
|
||||
shall be declared in the namespace of which the class template
|
||||
is a member. */
|
||||
if (scope && TREE_CODE (scope) != NAMESPACE_DECL)
|
||||
cp_error ("explicit specialization in non-namespace scope `%D'",
|
||||
scope);
|
||||
/* [temp.expl.spec]
|
||||
|
||||
In an explicit specialization declaration for a member of a class
|
||||
template or a member template that appears in namespace scope,
|
||||
the member template and some of its enclosing class templates may
|
||||
remain unspecialized, except that the declaration shall not
|
||||
explicitly specialize a class member template if its enclosing
|
||||
class templates are not explicitly specialized as well. */
|
||||
if (current_template_parms)
|
||||
cp_error ("enclosing class templates are not explicit specialized");
|
||||
}
|
||||
|
||||
/* We've just seen template <>. */
|
||||
|
||||
void
|
||||
begin_specialization ()
|
||||
{
|
||||
note_template_header (1);
|
||||
check_specialization_scope ();
|
||||
}
|
||||
|
||||
/* Called at then end of processing a declaration preceeded by
|
||||
@ -1209,17 +1243,10 @@ check_explicit_specialization (declarator, decl, template_count, flags)
|
||||
if (ctype != NULL_TREE && TYPE_BEING_DEFINED (ctype))
|
||||
{
|
||||
if (!explicit_instantiation)
|
||||
{
|
||||
/* Since finish_struct_1 has not been called yet, we
|
||||
can't call lookup_fnfields. We note that this
|
||||
template is a specialization, and proceed, letting
|
||||
finish_struct fix this up later. */
|
||||
tree ti = perm_tree_cons (NULL_TREE,
|
||||
TREE_OPERAND (declarator, 1),
|
||||
NULL_TREE);
|
||||
TI_PENDING_SPECIALIZATION_FLAG (ti) = 1;
|
||||
DECL_TEMPLATE_INFO (decl) = ti;
|
||||
}
|
||||
/* A specialization in class scope. This is illegal,
|
||||
but the error will already have been flagged by
|
||||
check_specialization_scope. */
|
||||
return error_mark_node;
|
||||
else
|
||||
/* It's not legal to write an explicit instantiation in
|
||||
class scope, e.g.:
|
||||
@ -1759,8 +1786,23 @@ build_template_decl (decl, parms)
|
||||
|
||||
struct template_parm_data
|
||||
{
|
||||
/* The level of the template parameters we are currently
|
||||
processing. */
|
||||
int level;
|
||||
|
||||
/* The index of the specialization argument we are currently
|
||||
processing. */
|
||||
int current_arg;
|
||||
|
||||
/* An array whose size is the number of template parameters. The
|
||||
elements are non-zero if the parameter has been used in any one
|
||||
of the arguments processed so far. */
|
||||
int* parms;
|
||||
|
||||
/* An array whose size is the number of template arguments. The
|
||||
elements are non-zero if the argument makes use of template
|
||||
parameters of this level. */
|
||||
int* arg_uses_template_parms;
|
||||
};
|
||||
|
||||
/* Subroutine of push_template_decl used to see if each template
|
||||
@ -1790,13 +1832,205 @@ mark_template_parm (t, data)
|
||||
}
|
||||
|
||||
if (level == tpd->level)
|
||||
tpd->parms[idx] = 1;
|
||||
{
|
||||
tpd->parms[idx] = 1;
|
||||
tpd->arg_uses_template_parms[tpd->current_arg] = 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;
|
||||
}
|
||||
|
||||
/* Process the partial specialization DECL. */
|
||||
|
||||
tree
|
||||
process_partial_specialization (decl)
|
||||
tree decl;
|
||||
{
|
||||
tree type = TREE_TYPE (decl);
|
||||
tree maintmpl = CLASSTYPE_TI_TEMPLATE (type);
|
||||
tree specargs = CLASSTYPE_TI_ARGS (type);
|
||||
tree inner_args = innermost_args (specargs);
|
||||
tree inner_parms = INNERMOST_TEMPLATE_PARMS (current_template_parms);
|
||||
tree main_inner_parms = DECL_INNERMOST_TEMPLATE_PARMS (maintmpl);
|
||||
int nargs = TREE_VEC_LENGTH (inner_args);
|
||||
int ntparms = TREE_VEC_LENGTH (inner_parms);
|
||||
int i;
|
||||
int did_error_intro = 0;
|
||||
int issued_default_arg_message = 0;
|
||||
struct template_parm_data tpd;
|
||||
struct template_parm_data tpd2;
|
||||
|
||||
/* [temp.class.spec]
|
||||
|
||||
The template parameter list of a specialization shall not
|
||||
contain default template argument values. */
|
||||
for (i = 0; i < ntparms; ++i)
|
||||
{
|
||||
if (TREE_PURPOSE (TREE_VEC_ELT (inner_parms, i)))
|
||||
{
|
||||
if (!issued_default_arg_message)
|
||||
{
|
||||
cp_error ("default argument in partial specialization `%T'",
|
||||
type);
|
||||
issued_default_arg_message = 1;
|
||||
}
|
||||
TREE_PURPOSE (TREE_VEC_ELT (inner_parms, i)) = NULL_TREE;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
tpd.level = TMPL_PARMS_DEPTH (current_template_parms);
|
||||
tpd.parms = alloca (sizeof (int) * ntparms);
|
||||
bzero (tpd.parms, sizeof (int) * nargs);
|
||||
|
||||
tpd.arg_uses_template_parms = alloca (sizeof (int) * nargs);
|
||||
bzero (tpd.arg_uses_template_parms, sizeof (int) * nargs);
|
||||
for (i = 0; i < nargs; ++i)
|
||||
{
|
||||
tpd.current_arg = i;
|
||||
for_each_template_parm (TREE_VEC_ELT (inner_args, 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 (inner_parms, i)));
|
||||
}
|
||||
|
||||
/* [temp.class.spec]
|
||||
|
||||
The argument list of the specialization shall not be identical to
|
||||
the implicit argument list of the primary template. */
|
||||
if (comp_template_args (inner_args,
|
||||
innermost_args (CLASSTYPE_TI_ARGS (TREE_TYPE
|
||||
(maintmpl)))))
|
||||
cp_error ("partial specialization `%T' does not specialize any template arguments", type);
|
||||
|
||||
/* [temp.class.spec]
|
||||
|
||||
A partially specialized non-type argument expression shall not
|
||||
involve template parameters of the partial specialization except
|
||||
when the argument expression is a simple identifier.
|
||||
|
||||
The type of a template parameter corresponding to a specialized
|
||||
non-type argument shall not be dependent on a parameter of the
|
||||
specialization. */
|
||||
my_friendly_assert (nargs == DECL_NTPARMS (maintmpl), 0);
|
||||
tpd2.parms = 0;
|
||||
for (i = 0; i < nargs; ++i)
|
||||
{
|
||||
tree arg = TREE_VEC_ELT (inner_args, i);
|
||||
if (/* These first two lines are the `non-type' bit. */
|
||||
TREE_CODE_CLASS (TREE_CODE (arg)) != 't'
|
||||
&& TREE_CODE (arg) != TEMPLATE_DECL
|
||||
/* This next line is the `argument expression is not just a
|
||||
simple identifier' condition and also the `specialized
|
||||
non-type argument' bit. */
|
||||
&& TREE_CODE (arg) != TEMPLATE_PARM_INDEX)
|
||||
{
|
||||
if (tpd.arg_uses_template_parms[i])
|
||||
cp_error ("template argument `%E' involves template parameter(s)", arg);
|
||||
else
|
||||
{
|
||||
/* Look at the corresponding template parameter,
|
||||
marking which template parameters its type depends
|
||||
upon. */
|
||||
tree type =
|
||||
TREE_TYPE (TREE_VALUE (TREE_VEC_ELT (main_inner_parms,
|
||||
i)));
|
||||
|
||||
if (!tpd2.parms)
|
||||
{
|
||||
/* We haven't yet initialized TPD2. Do so now. */
|
||||
tpd2.arg_uses_template_parms
|
||||
= (int*) alloca (sizeof (int) * nargs);
|
||||
tpd2.parms = (int*) alloca (sizeof (int) * nargs);
|
||||
tpd2.level =
|
||||
TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (maintmpl));
|
||||
}
|
||||
|
||||
/* Mark the template paramters. But this time, we're
|
||||
looking for the template parameters of the main
|
||||
template, not in the specialization. */
|
||||
tpd2.current_arg = i;
|
||||
tpd2.arg_uses_template_parms[i] = 0;
|
||||
bzero (tpd.parms, sizeof (int) * nargs);
|
||||
for_each_template_parm (type,
|
||||
&mark_template_parm,
|
||||
&tpd2);
|
||||
|
||||
if (tpd2.arg_uses_template_parms [i])
|
||||
{
|
||||
/* The type depended on some template parameters.
|
||||
If they are fully specialized in the
|
||||
specialization, that's OK. */
|
||||
int j;
|
||||
for (j = 0; j < nargs; ++j)
|
||||
if (tpd2.parms[j] != 0
|
||||
&& tpd.arg_uses_template_parms [j])
|
||||
{
|
||||
cp_error ("type `%T' of template argument `%E' depends on template paramter(s)",
|
||||
type,
|
||||
arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (retrieve_specialization (maintmpl, specargs))
|
||||
/* We've already got this specialization. */
|
||||
return decl;
|
||||
|
||||
DECL_TEMPLATE_SPECIALIZATIONS (maintmpl) = CLASSTYPE_TI_SPEC_INFO (type)
|
||||
= perm_tree_cons (inner_args, inner_parms,
|
||||
DECL_TEMPLATE_SPECIALIZATIONS (maintmpl));
|
||||
TREE_TYPE (DECL_TEMPLATE_SPECIALIZATIONS (maintmpl)) = type;
|
||||
return decl;
|
||||
}
|
||||
|
||||
/* 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
|
||||
@ -1868,92 +2102,7 @@ push_template_decl_real (decl, is_friend)
|
||||
if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)
|
||||
&& TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE
|
||||
&& CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)))
|
||||
{
|
||||
tree type = TREE_TYPE (decl);
|
||||
tree maintmpl = CLASSTYPE_TI_TEMPLATE (type);
|
||||
tree specargs = CLASSTYPE_TI_ARGS (type);
|
||||
|
||||
/* 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 (INNERMOST_TEMPLATE_PARMS (current_template_parms));
|
||||
int did_error_intro = 0;
|
||||
|
||||
tpd.level = TMPL_PARMS_DEPTH (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 (specargs); ++i)
|
||||
for_each_template_parm (TREE_VEC_ELT (specargs, 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)));
|
||||
}
|
||||
|
||||
/* [temp.class.spec]
|
||||
|
||||
The argument list of the specialization shall not be
|
||||
identical to the implicit argument list of the primary
|
||||
template. */
|
||||
if (comp_template_args (specargs,
|
||||
CLASSTYPE_TI_ARGS (TREE_TYPE (maintmpl))))
|
||||
cp_error ("partial specialization `%T' does not specialize any template arguments", type);
|
||||
|
||||
if (retrieve_specialization (maintmpl, specargs))
|
||||
/* We've already got this specialization. */
|
||||
return decl;
|
||||
|
||||
DECL_TEMPLATE_SPECIALIZATIONS (maintmpl) = CLASSTYPE_TI_SPEC_INFO (type)
|
||||
= perm_tree_cons (innermost_args (specargs),
|
||||
INNERMOST_TEMPLATE_PARMS (current_template_parms),
|
||||
DECL_TEMPLATE_SPECIALIZATIONS (maintmpl));
|
||||
TREE_TYPE (DECL_TEMPLATE_SPECIALIZATIONS (maintmpl)) = type;
|
||||
return decl;
|
||||
}
|
||||
return process_partial_specialization (decl);
|
||||
|
||||
args = current_template_args ();
|
||||
|
||||
@ -5194,7 +5343,6 @@ tsubst_decl (t, args, type, in_decl)
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/* Substitue into the ARG_TYPES of a function type. */
|
||||
|
||||
tree
|
||||
@ -5204,7 +5352,6 @@ tsubst_arg_types (arg_types, args, in_decl)
|
||||
tree in_decl;
|
||||
{
|
||||
tree remaining_arg_types;
|
||||
tree result;
|
||||
tree type;
|
||||
|
||||
if (!arg_types || arg_types == void_list_node)
|
||||
|
@ -1234,9 +1234,9 @@ begin_class_definition (t)
|
||||
&& TREE_CODE (TYPE_CONTEXT (t)) != NAMESPACE_DECL
|
||||
&& ! current_class_type)
|
||||
push_template_decl (TYPE_STUB_DECL (t));
|
||||
maybe_process_partial_specialization (t);
|
||||
pushclass (t, 0);
|
||||
TYPE_BEING_DEFINED (t) = 1;
|
||||
maybe_process_partial_specialization (t);
|
||||
/* Reset the interface data, at the earliest possible
|
||||
moment, as it might have been set via a class foo;
|
||||
before. */
|
||||
|
@ -5,11 +5,13 @@ struct S
|
||||
{
|
||||
template <class T>
|
||||
void foo(T t);
|
||||
|
||||
template <>
|
||||
void foo<int>(int) {}
|
||||
};
|
||||
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void S<char*>::foo<int>(int) {}
|
||||
|
||||
int main()
|
||||
{
|
||||
S<char*> s;
|
||||
|
@ -7,13 +7,14 @@ struct S
|
||||
template <class T>
|
||||
void foo(T t);
|
||||
|
||||
template <>
|
||||
void foo(int) { }
|
||||
|
||||
template <class T>
|
||||
void bar(T t) { this->template foo<U>(3.74); }
|
||||
};
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void S<int>::foo(int) { }
|
||||
|
||||
int main()
|
||||
{
|
||||
S<int> s;
|
||||
|
@ -4,11 +4,11 @@ struct S
|
||||
{
|
||||
template <class T>
|
||||
void foo(T t);
|
||||
|
||||
template <>
|
||||
void foo<int>(int i) { }
|
||||
};
|
||||
|
||||
template <>
|
||||
void S::foo<int>(int i) { }
|
||||
|
||||
int main()
|
||||
{
|
||||
S s;
|
||||
|
@ -4,12 +4,13 @@ struct S
|
||||
struct Y {
|
||||
template <class T>
|
||||
void foo(T t);
|
||||
|
||||
template <>
|
||||
void foo<int>(int i) { }
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void S::Y<char>::foo<int>(int i) { }
|
||||
|
||||
int main()
|
||||
{
|
||||
S::Y<char> s;
|
||||
|
@ -4,9 +4,6 @@ struct S
|
||||
{
|
||||
template <class T>
|
||||
void foo(T t);
|
||||
|
||||
template <>
|
||||
void foo(int i);
|
||||
};
|
||||
|
||||
|
||||
|
@ -4,9 +4,6 @@ struct S
|
||||
{
|
||||
template <class T>
|
||||
void foo(T t);
|
||||
|
||||
template <>
|
||||
void foo(int i);
|
||||
};
|
||||
|
||||
|
||||
|
@ -7,9 +7,9 @@ struct S3
|
||||
static char* h(U);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
template <>
|
||||
char* S3<T>::h(int) { return __PRETTY_FUNCTION__; }
|
||||
template <>
|
||||
char* S3<double>::h(int) { return __PRETTY_FUNCTION__; }
|
||||
|
||||
template <>
|
||||
template <>
|
||||
|
@ -5,14 +5,15 @@ struct S
|
||||
{
|
||||
template <int i>
|
||||
int f(int j) { abort(); return 0; }
|
||||
|
||||
template <>
|
||||
int f<7>(int j) { return j + 7; }
|
||||
|
||||
template <>
|
||||
int f<8>(int j) { return j + 8; }
|
||||
};
|
||||
|
||||
template <>
|
||||
template <>
|
||||
int S<double>::f<7>(int j) { return j + 7; }
|
||||
|
||||
template <>
|
||||
template <>
|
||||
int S<double>::f<8>(int j) { return j + 8; }
|
||||
|
||||
int main()
|
||||
{
|
||||
|
@ -7,9 +7,9 @@ struct S
|
||||
int f(U u);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
template <>
|
||||
int S<T>::f(int i) { return 1; }
|
||||
template <>
|
||||
int S<char>::f(int i) { return 1; }
|
||||
|
||||
int main()
|
||||
{
|
||||
|
@ -8,9 +8,9 @@ struct S
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
template <>
|
||||
int S<T>::f<int>(int i) { return 1; }
|
||||
template <>
|
||||
int S<char>::f<int>(int i) { return 1; }
|
||||
|
||||
int main()
|
||||
{
|
||||
|
@ -14,11 +14,11 @@ struct S1
|
||||
|
||||
template <class T>
|
||||
void f(T* t);
|
||||
|
||||
template <>
|
||||
void f(int* ip) {}
|
||||
};
|
||||
|
||||
template <>
|
||||
void S1::f(int* ip) {}
|
||||
|
||||
template <class U>
|
||||
struct S2
|
||||
{
|
||||
@ -27,11 +27,12 @@ struct S2
|
||||
|
||||
template <class T>
|
||||
void f(T* t);
|
||||
|
||||
template <>
|
||||
void f(int* ip) {}
|
||||
};
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void S2<double>::f(int* ip) {}
|
||||
|
||||
int main()
|
||||
{
|
||||
int* ip;
|
||||
|
@ -28,9 +28,9 @@ struct S3
|
||||
static int h(U);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
template <>
|
||||
int S3<T>::h(int) { return 0; }
|
||||
template <>
|
||||
int S3<double>::h(int) { return 0; }
|
||||
|
||||
template <>
|
||||
template <>
|
||||
|
11
gcc/testsuite/g++.old-deja/g++.pt/spec20.C
Normal file
11
gcc/testsuite/g++.old-deja/g++.pt/spec20.C
Normal file
@ -0,0 +1,11 @@
|
||||
// Build don't link:
|
||||
|
||||
template <class T>
|
||||
struct S {
|
||||
template <class U> void f(U);
|
||||
template <> void f<int>(int); // ERROR - specialization
|
||||
|
||||
template <class V> struct I {};
|
||||
template <class V> struct I<V*> {};
|
||||
template <> struct I<int>; // ERROR - specialization
|
||||
};
|
16
gcc/testsuite/g++.old-deja/g++.pt/spec21.C
Normal file
16
gcc/testsuite/g++.old-deja/g++.pt/spec21.C
Normal file
@ -0,0 +1,16 @@
|
||||
// Build don't link:
|
||||
|
||||
template <class T> struct S {};
|
||||
template <class T = int> struct S<T*> {}; // ERROR - default argument
|
||||
|
||||
template <int I, int J> struct A {};
|
||||
template <int I> struct A<I+5, I*2> {}; // ERROR - argument involves parameter
|
||||
|
||||
template <class T, T t> struct C {};
|
||||
template <class T> struct C<T, 1>; // ERROR - type depends on parameter
|
||||
int i;
|
||||
template <class T> struct C<T*, &i>; // ERROR - type depends on parameter
|
||||
|
||||
template< int X, int (*array_ptr)[X] > class B {};
|
||||
int array[5];
|
||||
template< int X > class B<X,&array> { }; // ERROR - type depends on parameter
|
15
gcc/testsuite/g++.old-deja/g++.pt/spec22.C
Normal file
15
gcc/testsuite/g++.old-deja/g++.pt/spec22.C
Normal file
@ -0,0 +1,15 @@
|
||||
// Build don't link:
|
||||
|
||||
template <class T>
|
||||
struct S
|
||||
{
|
||||
template <class U>
|
||||
void f();
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
template <> // ERROR - enclosing classes not specialized
|
||||
void S<T>::f<int> ()
|
||||
{
|
||||
}
|
@ -4,21 +4,23 @@ struct S1
|
||||
{
|
||||
template <class T>
|
||||
void f(T t1, T t2);
|
||||
|
||||
template <>
|
||||
void f(int i1, int i2);
|
||||
};
|
||||
|
||||
|
||||
template <>
|
||||
void S1::f(int i1, int i2);
|
||||
|
||||
template <class U>
|
||||
struct S2
|
||||
{
|
||||
template <class T>
|
||||
void f(T t1, T t2);
|
||||
|
||||
template <>
|
||||
void f(int i1, int i2);
|
||||
};
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void S2<char>::f(int i1, int i2);
|
||||
|
||||
void h()
|
||||
{
|
||||
S1 s1;
|
||||
|
Loading…
Reference in New Issue
Block a user