cp-tree.h (PROCESSING_REAL_TEMPLATE_DECL_P): New macro.
1998-07-31 Mark Mitchell <mark@markmitchell.com> * cp-tree.h (PROCESSING_REAL_TEMPLATE_DECL_P): New macro. (maybe_check_template_type): New function. * decl.c (maybe_process_template_type_declaration): New function, split out from pushtag Call maybe_check_template_type. (pushtag): Use it. Use PROCESSING_REAL_TEMPLATE_DECL_P. (xref_tag): Use PROCESSING_REAL_TEMPLATE_DECL_P. * friend.c (do_friend): Use PROCESSING_REAL_TEMPLATE_DECL_P. * pt.c (template_class_depth_real): Generalization of ... (template_class_depth): Use it. (register_specialization): Use duplicate_decls for duplicate declarations of specializations. (maybe_check_template_type): New function. (push_template_decl_real): Fix comment. (convert_nontype_argument): Likewise. (lookup_template_class): Likewise. Avoid an infinite loop on erroneous code. (tsubst_friend_function): Fix comment. (tsubst, case FUNCTION_DECL): Deal with a DECL_TI_TEMPLATE that is an IDENTIFIER_NODE. * semantics.c (begin_function_definition): Use reset_specialization to note that template headers don't apply directly to declarations after the opening curly for a function. From-SVN: r21505
This commit is contained in:
parent
5f97de0ac9
commit
39c01e4c53
@ -1,3 +1,28 @@
|
|||||||
|
1998-07-31 Mark Mitchell <mark@markmitchell.com>
|
||||||
|
|
||||||
|
* cp-tree.h (PROCESSING_REAL_TEMPLATE_DECL_P): New macro.
|
||||||
|
(maybe_check_template_type): New function.
|
||||||
|
* decl.c (maybe_process_template_type_declaration): New function,
|
||||||
|
split out from pushtag Call maybe_check_template_type.
|
||||||
|
(pushtag): Use it. Use PROCESSING_REAL_TEMPLATE_DECL_P.
|
||||||
|
(xref_tag): Use PROCESSING_REAL_TEMPLATE_DECL_P.
|
||||||
|
* friend.c (do_friend): Use PROCESSING_REAL_TEMPLATE_DECL_P.
|
||||||
|
* pt.c (template_class_depth_real): Generalization of ...
|
||||||
|
(template_class_depth): Use it.
|
||||||
|
(register_specialization): Use duplicate_decls for duplicate
|
||||||
|
declarations of specializations.
|
||||||
|
(maybe_check_template_type): New function.
|
||||||
|
(push_template_decl_real): Fix comment.
|
||||||
|
(convert_nontype_argument): Likewise.
|
||||||
|
(lookup_template_class): Likewise. Avoid an infinite loop on
|
||||||
|
erroneous code.
|
||||||
|
(tsubst_friend_function): Fix comment.
|
||||||
|
(tsubst, case FUNCTION_DECL): Deal with a DECL_TI_TEMPLATE that is
|
||||||
|
an IDENTIFIER_NODE.
|
||||||
|
* semantics.c (begin_function_definition): Use
|
||||||
|
reset_specialization to note that template headers don't apply
|
||||||
|
directly to declarations after the opening curly for a function.
|
||||||
|
|
||||||
1998-07-29 Jason Merrill <jason@yorick.cygnus.com>
|
1998-07-29 Jason Merrill <jason@yorick.cygnus.com>
|
||||||
|
|
||||||
* decl.c (push_overloaded_decl): Use current_namespace instead of
|
* decl.c (push_overloaded_decl): Use current_namespace instead of
|
||||||
|
@ -1692,6 +1692,12 @@ extern int flag_new_for_scope;
|
|||||||
#define SET_CLASSTYPE_EXPLICIT_INSTANTIATION(NODE) \
|
#define SET_CLASSTYPE_EXPLICIT_INSTANTIATION(NODE) \
|
||||||
(CLASSTYPE_USE_TEMPLATE(NODE) = 3)
|
(CLASSTYPE_USE_TEMPLATE(NODE) = 3)
|
||||||
|
|
||||||
|
/* Non-zero iff we are currently processing a declaration for an
|
||||||
|
entity with its own template parameter list, and which is not a
|
||||||
|
full specialization. */
|
||||||
|
#define PROCESSING_REAL_TEMPLATE_DECL_P() \
|
||||||
|
(processing_template_decl > template_class_depth (current_class_type))
|
||||||
|
|
||||||
/* This function may be a guiding decl for a template. */
|
/* This function may be a guiding decl for a template. */
|
||||||
#define DECL_MAYBE_TEMPLATE(NODE) DECL_LANG_FLAG_4 (NODE)
|
#define DECL_MAYBE_TEMPLATE(NODE) DECL_LANG_FLAG_4 (NODE)
|
||||||
/* We know what we're doing with this decl now. */
|
/* We know what we're doing with this decl now. */
|
||||||
@ -2794,6 +2800,7 @@ extern int template_class_depth PROTO((tree));
|
|||||||
extern int is_specialization_of PROTO((tree, tree));
|
extern int is_specialization_of PROTO((tree, tree));
|
||||||
extern int comp_template_args PROTO((tree, tree));
|
extern int comp_template_args PROTO((tree, tree));
|
||||||
extern void maybe_process_partial_specialization PROTO((tree));
|
extern void maybe_process_partial_specialization PROTO((tree));
|
||||||
|
extern void maybe_check_template_type PROTO((tree));
|
||||||
|
|
||||||
extern int processing_specialization;
|
extern int processing_specialization;
|
||||||
extern int processing_explicit_instantiation;
|
extern int processing_explicit_instantiation;
|
||||||
|
145
gcc/cp/decl.c
145
gcc/cp/decl.c
@ -176,6 +176,7 @@ static int member_function_or_else PROTO((tree, tree, char *));
|
|||||||
static void bad_specifiers PROTO((tree, char *, int, int, int, int,
|
static void bad_specifiers PROTO((tree, char *, int, int, int, int,
|
||||||
int));
|
int));
|
||||||
static void lang_print_error_function PROTO((char *));
|
static void lang_print_error_function PROTO((char *));
|
||||||
|
static tree maybe_process_template_type_declaration PROTO((tree, int, struct binding_level*));
|
||||||
|
|
||||||
#if defined (DEBUG_CP_BINDING_LEVELS)
|
#if defined (DEBUG_CP_BINDING_LEVELS)
|
||||||
static void indent PROTO((void));
|
static void indent PROTO((void));
|
||||||
@ -2223,6 +2224,88 @@ pop_everything ()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The type TYPE is being declared. If it is a class template, or a
|
||||||
|
specialization of a class template, do any processing required and
|
||||||
|
perform error-checking. If IS_FRIEND is non-zero, this TYPE is
|
||||||
|
being declared a friend. B is the binding level at which this TYPE
|
||||||
|
should be bound.
|
||||||
|
|
||||||
|
Returns the TYPE_DECL for TYPE, which may have been altered by this
|
||||||
|
processing. */
|
||||||
|
|
||||||
|
static tree
|
||||||
|
maybe_process_template_type_declaration (type, globalize, b)
|
||||||
|
tree type;
|
||||||
|
int globalize;
|
||||||
|
struct binding_level* b;
|
||||||
|
{
|
||||||
|
tree decl = TYPE_NAME (type);
|
||||||
|
|
||||||
|
if (processing_template_parmlist)
|
||||||
|
/* You can't declare a new template type in a template parameter
|
||||||
|
list. But, you can declare a non-template type:
|
||||||
|
|
||||||
|
template <class A*> struct S;
|
||||||
|
|
||||||
|
is a forward-declaration of `A'. */
|
||||||
|
;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
maybe_check_template_type (type);
|
||||||
|
|
||||||
|
if (IS_AGGR_TYPE (type)
|
||||||
|
&& (/* If !GLOBALIZE then we are looking at a definition.
|
||||||
|
It may not be a primary template. (For example, in:
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct S1 { class S2 {}; }
|
||||||
|
|
||||||
|
we have to push_template_decl for S2.) */
|
||||||
|
(processing_template_decl && !globalize)
|
||||||
|
/* If we are declaring a friend template class, we will
|
||||||
|
have GLOBALIZE set, since something like:
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct S1 {
|
||||||
|
template <class U>
|
||||||
|
friend class S2;
|
||||||
|
};
|
||||||
|
|
||||||
|
declares S2 to be at global scope. */
|
||||||
|
|| PROCESSING_REAL_TEMPLATE_DECL_P ()))
|
||||||
|
{
|
||||||
|
/* This may change after the call to
|
||||||
|
push_template_decl_real, but we want the original value. */
|
||||||
|
tree name = DECL_NAME (decl);
|
||||||
|
|
||||||
|
decl = push_template_decl_real (decl, globalize);
|
||||||
|
/* If the current binding level is the binding level for the
|
||||||
|
template parameters (see the comment in
|
||||||
|
begin_template_parm_list) and the enclosing level is a class
|
||||||
|
scope, and we're not looking at a friend, push the
|
||||||
|
declaration of the member class into the class scope. In the
|
||||||
|
friend case, push_template_decl will already have put the
|
||||||
|
friend into global scope, if appropriate. */
|
||||||
|
if (!globalize && b->pseudo_global
|
||||||
|
&& b->level_chain->parm_flag == 2)
|
||||||
|
{
|
||||||
|
pushdecl_with_scope (CLASSTYPE_TI_TEMPLATE (type),
|
||||||
|
b->level_chain);
|
||||||
|
/* Put this tag on the list of tags for the class, since
|
||||||
|
that won't happen below because B is not the class
|
||||||
|
binding level, but is instead the pseudo-global level. */
|
||||||
|
b->level_chain->tags =
|
||||||
|
saveable_tree_cons (name, type, b->level_chain->tags);
|
||||||
|
TREE_NONLOCAL_FLAG (type) = 1;
|
||||||
|
if (TYPE_SIZE (current_class_type) == NULL_TREE)
|
||||||
|
CLASSTYPE_TAGS (current_class_type) = b->level_chain->tags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return decl;
|
||||||
|
}
|
||||||
|
|
||||||
/* Push a tag name NAME for struct/class/union/enum type TYPE.
|
/* Push a tag name NAME for struct/class/union/enum type TYPE.
|
||||||
Normally put it into the inner-most non-tag-transparent scope,
|
Normally put it into the inner-most non-tag-transparent scope,
|
||||||
but if GLOBALIZE is true, put it in the inner-most non-class scope.
|
but if GLOBALIZE is true, put it in the inner-most non-class scope.
|
||||||
@ -2298,63 +2381,8 @@ pushtag (name, type, globalize)
|
|||||||
TYPE_NAME (type) = d;
|
TYPE_NAME (type) = d;
|
||||||
DECL_CONTEXT (d) = FROB_CONTEXT (context);
|
DECL_CONTEXT (d) = FROB_CONTEXT (context);
|
||||||
|
|
||||||
if (processing_template_parmlist)
|
d = maybe_process_template_type_declaration (type,
|
||||||
/* You can't declare a new template type in a template
|
globalize, b);
|
||||||
parameter list. But, you can declare a non-template
|
|
||||||
type:
|
|
||||||
|
|
||||||
template <class A*> struct S;
|
|
||||||
|
|
||||||
is a forward-declaration of `A'. */
|
|
||||||
;
|
|
||||||
else if (IS_AGGR_TYPE (type)
|
|
||||||
&& (/* If !GLOBALIZE then we are looking at a
|
|
||||||
definition. It may not be a primary template.
|
|
||||||
(For example, in:
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct S1 { class S2 {}; }
|
|
||||||
|
|
||||||
we have to push_template_decl for S2.) */
|
|
||||||
(processing_template_decl && !globalize)
|
|
||||||
/* If we are declaring a friend template class, we
|
|
||||||
will have GLOBALIZE set, since something like:
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct S1 {
|
|
||||||
template <class U>
|
|
||||||
friend class S2;
|
|
||||||
};
|
|
||||||
|
|
||||||
declares S2 to be at global scope. */
|
|
||||||
|| (processing_template_decl >
|
|
||||||
template_class_depth (current_class_type))))
|
|
||||||
{
|
|
||||||
d = push_template_decl_real (d, globalize);
|
|
||||||
/* If the current binding level is the binding level for
|
|
||||||
the template parameters (see the comment in
|
|
||||||
begin_template_parm_list) and the enclosing level is
|
|
||||||
a class scope, and we're not looking at a friend,
|
|
||||||
push the declaration of the member class into the
|
|
||||||
class scope. In the friend case, push_template_decl
|
|
||||||
will already have put the friend into global scope,
|
|
||||||
if appropriate. */
|
|
||||||
if (!globalize && b->pseudo_global
|
|
||||||
&& b->level_chain->parm_flag == 2)
|
|
||||||
{
|
|
||||||
pushdecl_with_scope (CLASSTYPE_TI_TEMPLATE (type),
|
|
||||||
b->level_chain);
|
|
||||||
/* Put this tag on the list of tags for the class,
|
|
||||||
since that won't happen below because B is not
|
|
||||||
the class binding level, but is instead the
|
|
||||||
pseudo-global level. */
|
|
||||||
b->level_chain->tags =
|
|
||||||
saveable_tree_cons (name, type, b->level_chain->tags);
|
|
||||||
TREE_NONLOCAL_FLAG (type) = 1;
|
|
||||||
if (TYPE_SIZE (current_class_type) == NULL_TREE)
|
|
||||||
CLASSTYPE_TAGS (current_class_type) = b->level_chain->tags;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (b->parm_flag == 2)
|
if (b->parm_flag == 2)
|
||||||
d = pushdecl_class_level (d);
|
d = pushdecl_class_level (d);
|
||||||
@ -11349,8 +11377,7 @@ xref_tag (code_type_node, name, binfo, globalize)
|
|||||||
{
|
{
|
||||||
if (current_class_type
|
if (current_class_type
|
||||||
&& template_class_depth (current_class_type)
|
&& template_class_depth (current_class_type)
|
||||||
&& (processing_template_decl
|
&& PROCESSING_REAL_TEMPLATE_DECL_P ())
|
||||||
> template_class_depth (current_class_type)))
|
|
||||||
/* Since GLOBALIZE is non-zero, we are not looking at a
|
/* Since GLOBALIZE is non-zero, we are not looking at a
|
||||||
definition of this tag. Since, in addition, we are currently
|
definition of this tag. Since, in addition, we are currently
|
||||||
processing a (member) template declaration of a template
|
processing a (member) template declaration of a template
|
||||||
|
@ -354,8 +354,7 @@ do_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (TREE_CODE (decl) == FUNCTION_DECL)
|
if (TREE_CODE (decl) == FUNCTION_DECL)
|
||||||
is_friend_template = processing_template_decl >
|
is_friend_template = PROCESSING_REAL_TEMPLATE_DECL_P ();
|
||||||
template_class_depth (current_class_type);
|
|
||||||
|
|
||||||
if (ctype)
|
if (ctype)
|
||||||
{
|
{
|
||||||
|
134
gcc/cp/pt.c
134
gcc/cp/pt.c
@ -121,6 +121,7 @@ static tree most_specialized PROTO((tree, tree, tree));
|
|||||||
static tree most_specialized_class PROTO((tree, tree));
|
static tree most_specialized_class PROTO((tree, tree));
|
||||||
static tree most_general_template PROTO((tree));
|
static tree most_general_template PROTO((tree));
|
||||||
static void set_mangled_name_for_template_decl PROTO((tree));
|
static void set_mangled_name_for_template_decl PROTO((tree));
|
||||||
|
static int template_class_depth_real PROTO((tree, int));
|
||||||
|
|
||||||
/* We use TREE_VECs to hold template arguments. If there is only one
|
/* We use TREE_VECs to hold template arguments. If there is only one
|
||||||
level of template arguments, then the TREE_VEC contains the
|
level of template arguments, then the TREE_VEC contains the
|
||||||
@ -234,12 +235,19 @@ finish_member_template_decl (template_parameters, decl)
|
|||||||
struct B {};
|
struct B {};
|
||||||
};
|
};
|
||||||
|
|
||||||
A<T>::B<U> has depth two, while A<T> has depth one. Also,
|
A<T>::B<U> has depth two, while A<T> has depth one.
|
||||||
both A<T>::B<int> and A<int>::B<U> have depth one. */
|
Both A<T>::B<int> and A<int>::B<U> have depth one, if
|
||||||
|
COUNT_SPECIALIZATIONS is 0 or if they are instantiations, not
|
||||||
|
specializations.
|
||||||
|
|
||||||
|
This function is guaranteed to return 0 if passed NULL_TREE so
|
||||||
|
that, for example, `template_class_depth (current_class_type)' is
|
||||||
|
always safe. */
|
||||||
|
|
||||||
int
|
int
|
||||||
template_class_depth (type)
|
template_class_depth_real (type, count_specializations)
|
||||||
tree type;
|
tree type;
|
||||||
|
int count_specializations;
|
||||||
{
|
{
|
||||||
int depth;
|
int depth;
|
||||||
|
|
||||||
@ -249,12 +257,25 @@ template_class_depth (type)
|
|||||||
type = TYPE_CONTEXT (type))
|
type = TYPE_CONTEXT (type))
|
||||||
if (CLASSTYPE_TEMPLATE_INFO (type)
|
if (CLASSTYPE_TEMPLATE_INFO (type)
|
||||||
&& PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type))
|
&& PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type))
|
||||||
&& uses_template_parms (CLASSTYPE_TI_ARGS (type)))
|
&& ((count_specializations
|
||||||
|
&& CLASSTYPE_TEMPLATE_SPECIALIZATION (type))
|
||||||
|
|| uses_template_parms (CLASSTYPE_TI_ARGS (type))))
|
||||||
++depth;
|
++depth;
|
||||||
|
|
||||||
return depth;
|
return depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns the template nesting level of the indicated class TYPE.
|
||||||
|
Like template_class_depth_real, but instantiations do not count in
|
||||||
|
the depth. */
|
||||||
|
|
||||||
|
int
|
||||||
|
template_class_depth (type)
|
||||||
|
tree type;
|
||||||
|
{
|
||||||
|
return template_class_depth_real (type, /*count_specializations=*/0);
|
||||||
|
}
|
||||||
|
|
||||||
/* Returns 1 if processing DECL as part of do_pending_inlines
|
/* Returns 1 if processing DECL as part of do_pending_inlines
|
||||||
needs us to push template parms. */
|
needs us to push template parms. */
|
||||||
|
|
||||||
@ -742,11 +763,8 @@ register_specialization (spec, tmpl, args)
|
|||||||
}
|
}
|
||||||
else if (DECL_TEMPLATE_SPECIALIZATION (fn))
|
else if (DECL_TEMPLATE_SPECIALIZATION (fn))
|
||||||
{
|
{
|
||||||
if (DECL_INITIAL (fn))
|
duplicate_decls (spec, TREE_VALUE (s));
|
||||||
cp_error ("duplicate specialization of %D", fn);
|
return TREE_VALUE (s);
|
||||||
|
|
||||||
TREE_VALUE (s) = spec;
|
|
||||||
return spec;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1300,6 +1318,50 @@ check_explicit_specialization (declarator, decl, template_count, flags)
|
|||||||
return decl;
|
return decl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TYPE is being declared. Verify that the use of template headers
|
||||||
|
and such is reasonable. Issue error messages if not. */
|
||||||
|
|
||||||
|
void
|
||||||
|
maybe_check_template_type (type)
|
||||||
|
tree type;
|
||||||
|
{
|
||||||
|
if (template_header_count)
|
||||||
|
{
|
||||||
|
/* We are in the scope of some `template <...>' header. */
|
||||||
|
|
||||||
|
int context_depth
|
||||||
|
= template_class_depth_real (TYPE_CONTEXT (type),
|
||||||
|
/*count_specializations=*/1);
|
||||||
|
|
||||||
|
if (template_header_count <= context_depth)
|
||||||
|
/* This is OK; the template headers are for the context. We
|
||||||
|
are actually too lenient here; like
|
||||||
|
check_explicit_specialization we should consider the number
|
||||||
|
of template types included in the actual declaration. For
|
||||||
|
example,
|
||||||
|
|
||||||
|
template <class T> struct S {
|
||||||
|
template <class U> template <class V>
|
||||||
|
struct I {};
|
||||||
|
};
|
||||||
|
|
||||||
|
is illegal, but:
|
||||||
|
|
||||||
|
template <class T> struct S {
|
||||||
|
template <class U> struct I;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T> template <class U.
|
||||||
|
struct S<T>::I {};
|
||||||
|
|
||||||
|
is not. */
|
||||||
|
;
|
||||||
|
else if (template_header_count > context_depth + 1)
|
||||||
|
/* There are two many template parameter lists. */
|
||||||
|
cp_error ("too many template parameter lists in declaration of `%T'", type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Returns 1 iff PARMS1 and PARMS2 are identical sets of template
|
/* Returns 1 iff PARMS1 and PARMS2 are identical sets of template
|
||||||
parameters. These are represented in the same format used for
|
parameters. These are represented in the same format used for
|
||||||
DECL_TEMPLATE_PARMS. */
|
DECL_TEMPLATE_PARMS. */
|
||||||
@ -1951,9 +2013,7 @@ push_template_decl_real (decl, is_friend)
|
|||||||
/* Push template declarations for global functions and types. Note
|
/* Push template declarations for global functions and types. Note
|
||||||
that we do not try to push a global template friend declared in a
|
that we do not try to push a global template friend declared in a
|
||||||
template class; such a thing may well depend on the template
|
template class; such a thing may well depend on the template
|
||||||
parameters of the class. With guiding declarations, however, we
|
parameters of the class. */
|
||||||
push the template so that subsequent declarations of the template
|
|
||||||
will match this one. */
|
|
||||||
if (! ctx
|
if (! ctx
|
||||||
&& !(is_friend && template_class_depth (current_class_type) > 0))
|
&& !(is_friend && template_class_depth (current_class_type) > 0))
|
||||||
tmpl = pushdecl_namespace_level (tmpl);
|
tmpl = pushdecl_namespace_level (tmpl);
|
||||||
@ -2278,10 +2338,10 @@ convert_nontype_argument (type, expr)
|
|||||||
if (TREE_CODE (type_referred_to) == FUNCTION_TYPE)
|
if (TREE_CODE (type_referred_to) == FUNCTION_TYPE)
|
||||||
{
|
{
|
||||||
/* For a non-type template-parameter of type reference to
|
/* For a non-type template-parameter of type reference to
|
||||||
function, no conversions apply. If the
|
function, no conversions apply. If the
|
||||||
template-argument represents a set of overloaded
|
template-argument represents a set of overloaded
|
||||||
functions, the matching function is selected from the
|
functions, the matching function is selected from the
|
||||||
set (_over.over_). */
|
set (_over.over_). */
|
||||||
tree fns = expr;
|
tree fns = expr;
|
||||||
tree fn;
|
tree fn;
|
||||||
|
|
||||||
@ -3096,7 +3156,7 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope)
|
|||||||
|
|
||||||
if (arg_depth == 1 && parm_depth > 1)
|
if (arg_depth == 1 && parm_depth > 1)
|
||||||
{
|
{
|
||||||
/* We've been with an incomplete set of template arguments.
|
/* We've been given an incomplete set of template arguments.
|
||||||
For example, given:
|
For example, given:
|
||||||
|
|
||||||
template <class T> struct S1 {
|
template <class T> struct S1 {
|
||||||
@ -3109,8 +3169,28 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope)
|
|||||||
<class U> struct S1<T>::S2'. We must fill in the missing
|
<class U> struct S1<T>::S2'. We must fill in the missing
|
||||||
arguments. */
|
arguments. */
|
||||||
my_friendly_assert (context != NULL_TREE, 0);
|
my_friendly_assert (context != NULL_TREE, 0);
|
||||||
while (!IS_AGGR_TYPE_CODE (TREE_CODE (context)))
|
while (!IS_AGGR_TYPE_CODE (TREE_CODE (context))
|
||||||
|
&& context != global_namespace)
|
||||||
context = DECL_REAL_CONTEXT (context);
|
context = DECL_REAL_CONTEXT (context);
|
||||||
|
|
||||||
|
if (context == global_namespace)
|
||||||
|
/* This is bad. We cannot get enough arguments, even from
|
||||||
|
the surrounding context, to resolve this class. One
|
||||||
|
case where this might happen is (illegal) code like:
|
||||||
|
|
||||||
|
template <class U>
|
||||||
|
template <class T>
|
||||||
|
struct S {
|
||||||
|
A(const A<T>& a) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
We should catch this error sooner (at the opening curly
|
||||||
|
for `S', but it is better to be safe than sorry here. */
|
||||||
|
{
|
||||||
|
cp_error ("invalid use of `%D'", template);
|
||||||
|
return error_mark_node;
|
||||||
|
}
|
||||||
|
|
||||||
arglist = add_to_template_args (CLASSTYPE_TI_ARGS (context),
|
arglist = add_to_template_args (CLASSTYPE_TI_ARGS (context),
|
||||||
arglist);
|
arglist);
|
||||||
arg_depth = TMPL_ARGS_DEPTH (arglist);
|
arg_depth = TMPL_ARGS_DEPTH (arglist);
|
||||||
@ -3667,8 +3747,8 @@ tsubst_friend_function (decl, args)
|
|||||||
args, NULL_TREE),
|
args, NULL_TREE),
|
||||||
tsubst (DECL_TI_ARGS (decl),
|
tsubst (DECL_TI_ARGS (decl),
|
||||||
args, NULL_TREE));
|
args, NULL_TREE));
|
||||||
/* FIXME: The decl we create via the next tsubst be created on a
|
/* FIXME: The decl we create via the next tsubst could be
|
||||||
temporary obstack. */
|
created on a temporary obstack. */
|
||||||
new_friend = tsubst (decl, args, NULL_TREE);
|
new_friend = tsubst (decl, args, NULL_TREE);
|
||||||
tmpl = determine_specialization (template_id, new_friend,
|
tmpl = determine_specialization (template_id, new_friend,
|
||||||
&new_args,
|
&new_args,
|
||||||
@ -4833,12 +4913,14 @@ tsubst (t, args, in_decl)
|
|||||||
};
|
};
|
||||||
|
|
||||||
Here, the DECL_TI_TEMPLATE for the friend declaration
|
Here, the DECL_TI_TEMPLATE for the friend declaration
|
||||||
will be a LOOKUP_EXPR. We are being called from
|
will be a LOOKUP_EXPR or an IDENTIFIER_NODE. We are
|
||||||
tsubst_friend_function, and we want only to create a
|
being called from tsubst_friend_function, and we want
|
||||||
new decl (R) with appropriate types so that we can call
|
only to create a new decl (R) with appropriate types so
|
||||||
determine_specialization. */
|
that we can call determine_specialization. */
|
||||||
my_friendly_assert (TREE_CODE (DECL_TI_TEMPLATE (t))
|
my_friendly_assert ((TREE_CODE (DECL_TI_TEMPLATE (t))
|
||||||
== LOOKUP_EXPR, 0);
|
== LOOKUP_EXPR)
|
||||||
|
|| (TREE_CODE (DECL_TI_TEMPLATE (t))
|
||||||
|
== IDENTIFIER_NODE), 0);
|
||||||
gen_tmpl = NULL_TREE;
|
gen_tmpl = NULL_TREE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1098,6 +1098,10 @@ begin_function_definition (decl_specs, declarator)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
reinit_parse_for_function ();
|
reinit_parse_for_function ();
|
||||||
|
/* The things we're about to see are not directly qualified by any
|
||||||
|
template headers we've seen thus far. */
|
||||||
|
reset_specialization ();
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
gcc/testsuite/g++.old-deja/g++.pt/crash15.C
Normal file
10
gcc/testsuite/g++.old-deja/g++.pt/crash15.C
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// Build don't link:
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
template <class U>
|
||||||
|
struct A { // ERROR - too many template parameter lists
|
||||||
|
public:
|
||||||
|
A() {}
|
||||||
|
|
||||||
|
A(const A<T>& b) {} // ERROR - invalid use of template
|
||||||
|
};
|
4
gcc/testsuite/g++.old-deja/g++.pt/enum5.C
Normal file
4
gcc/testsuite/g++.old-deja/g++.pt/enum5.C
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// Build don't link:
|
||||||
|
|
||||||
|
template <>
|
||||||
|
enum E {e}; // ERROR - template declaration of enum
|
@ -4,7 +4,7 @@ template <class T>
|
|||||||
void foo(T t);
|
void foo(T t);
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void foo(int) {};
|
void foo(int) {}; // ERROR - previously defined here.
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void foo<int>(int) {} // ERROR - duplicate specialization.
|
void foo<int>(int) {} // ERROR - duplicate specialization.
|
||||||
|
22
gcc/testsuite/g++.old-deja/g++.pt/friend28.C
Normal file
22
gcc/testsuite/g++.old-deja/g++.pt/friend28.C
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Build don't link:
|
||||||
|
|
||||||
|
class mystream;
|
||||||
|
|
||||||
|
template <class T> class a {
|
||||||
|
public:
|
||||||
|
friend mystream& operator>> <>( mystream&, a<T>& thea );
|
||||||
|
private:
|
||||||
|
T amember;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T> mystream& operator>>( mystream& s, a<T>& thea );
|
||||||
|
|
||||||
|
template<> mystream& operator>> <int>( mystream& s, a<int>& thea );
|
||||||
|
|
||||||
|
template class a<int>;
|
||||||
|
|
||||||
|
template<> mystream& operator>> <int>( mystream& s, a<int>& thea )
|
||||||
|
{
|
||||||
|
thea.amember = 0;
|
||||||
|
return s;
|
||||||
|
}
|
16
gcc/testsuite/g++.old-deja/g++.pt/friend29.C
Normal file
16
gcc/testsuite/g++.old-deja/g++.pt/friend29.C
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Build don't link:
|
||||||
|
|
||||||
|
template <class T> class a {
|
||||||
|
public:
|
||||||
|
friend void foo<>( a<T>& thea );
|
||||||
|
private:
|
||||||
|
T amember;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T> void foo( a<T>& thea )
|
||||||
|
{
|
||||||
|
thea.amember = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template class a<int>;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user