cp-tree.h (scope_kind): New type.
* cp-tree.h (scope_kind): New type. (tmpl_spec_kind): Likewise. (declare_pseudo_global_level): Remove. (pseudo_global_level_p): Rename to template_parm_scope_p. (pushlevel): Remove declaration. (begin_scope): New function. (finish_scope): Likewise. (current_tmpl_spec_kind): Likewise. * decl.c (struct binding_level): Shorten parm_flag to 2 bits. Shorten keep to 2 bits. Rename pseudo_global to template_parms_p. Add template_spec_p. (toplevel_bindings_p): Adjust. (declare_pseudo_global_level): Remove. (pseudo_global_level_p): Rename to template_parm_scope_p. (current_tmpl_spec_kind): New function. (begin_scope): Likewise. (finish_scope): Likewise. (maybe_push_to_top_level): Adjust. (maybe_process_template_type_declaration): Likewise. (pushtag): Likewise. (pushdecl_nonclass_level): Likewise. (lookup_tag): Likewise. (grokfndecl): Handle member template specializations. Share constructor and non-constructor code. * decl2.c (check_classfn): Handle member template specializations. * pt.c (begin_template_parm_list): Use begin_scope. (begin_specialization): Likewise. (end_specialization): Likewise. (check_explicit_specialization): Use current_tmpl_spec_kind. Handle member template specializations. (end_template_decl): Use finish_scope. Remove call to get_pending_sizes. (push_template_decl_real): Remove bogus error message. (tsubst_decl): Fix typo in code contained in comment. (instantiate_template): Handle member template specializations. (most_general_template): Likewise. From-SVN: r32494
This commit is contained in:
parent
d453714896
commit
74b846e0de
|
@ -1,3 +1,42 @@
|
||||||
|
2000-03-11 Mark Mitchell <mark@codesourcery.com>
|
||||||
|
|
||||||
|
* cp-tree.h (scope_kind): New type.
|
||||||
|
(tmpl_spec_kind): Likewise.
|
||||||
|
(declare_pseudo_global_level): Remove.
|
||||||
|
(pseudo_global_level_p): Rename to template_parm_scope_p.
|
||||||
|
(pushlevel): Remove declaration.
|
||||||
|
(begin_scope): New function.
|
||||||
|
(finish_scope): Likewise.
|
||||||
|
(current_tmpl_spec_kind): Likewise.
|
||||||
|
* decl.c (struct binding_level): Shorten parm_flag to 2 bits.
|
||||||
|
Shorten keep to 2 bits. Rename pseudo_global to template_parms_p.
|
||||||
|
Add template_spec_p.
|
||||||
|
(toplevel_bindings_p): Adjust.
|
||||||
|
(declare_pseudo_global_level): Remove.
|
||||||
|
(pseudo_global_level_p): Rename to template_parm_scope_p.
|
||||||
|
(current_tmpl_spec_kind): New function.
|
||||||
|
(begin_scope): Likewise.
|
||||||
|
(finish_scope): Likewise.
|
||||||
|
(maybe_push_to_top_level): Adjust.
|
||||||
|
(maybe_process_template_type_declaration): Likewise.
|
||||||
|
(pushtag): Likewise.
|
||||||
|
(pushdecl_nonclass_level): Likewise.
|
||||||
|
(lookup_tag): Likewise.
|
||||||
|
(grokfndecl): Handle member template specializations. Share
|
||||||
|
constructor and non-constructor code.
|
||||||
|
* decl2.c (check_classfn): Handle member template specializations.
|
||||||
|
* pt.c (begin_template_parm_list): Use begin_scope.
|
||||||
|
(begin_specialization): Likewise.
|
||||||
|
(end_specialization): Likewise.
|
||||||
|
(check_explicit_specialization): Use current_tmpl_spec_kind.
|
||||||
|
Handle member template specializations.
|
||||||
|
(end_template_decl): Use finish_scope. Remove call to
|
||||||
|
get_pending_sizes.
|
||||||
|
(push_template_decl_real): Remove bogus error message.
|
||||||
|
(tsubst_decl): Fix typo in code contained in comment.
|
||||||
|
(instantiate_template): Handle member template specializations.
|
||||||
|
(most_general_template): Likewise.
|
||||||
|
|
||||||
2000-03-11 Gabriel Dos Reis <gdr@codesourcery.com>
|
2000-03-11 Gabriel Dos Reis <gdr@codesourcery.com>
|
||||||
|
|
||||||
* lex.c (whitespace_cr): Compress consecutive calls to warning().
|
* lex.c (whitespace_cr): Compress consecutive calls to warning().
|
||||||
|
|
|
@ -3043,6 +3043,32 @@ typedef enum cp_lvalue_kind {
|
||||||
clk_bitfield = 4, /* An lvalue for a bit-field. */
|
clk_bitfield = 4, /* An lvalue for a bit-field. */
|
||||||
} cp_lvalue_kind;
|
} cp_lvalue_kind;
|
||||||
|
|
||||||
|
/* The kinds of scopes we recognize. */
|
||||||
|
typedef enum scope_kind {
|
||||||
|
sk_template_parms, /* A scope for template parameters. */
|
||||||
|
sk_template_spec /* A scope corresponding to a template
|
||||||
|
specialization. There is never anything in
|
||||||
|
this scope. */
|
||||||
|
} scope_kind;
|
||||||
|
|
||||||
|
/* Various kinds of template specialization, instantiation, etc. */
|
||||||
|
typedef enum tmpl_spec_kind {
|
||||||
|
tsk_none, /* Not a template at all. */
|
||||||
|
tsk_invalid_member_spec, /* An explicit member template
|
||||||
|
specialization, but the enclosing
|
||||||
|
classes have not all been explicitly
|
||||||
|
specialized. */
|
||||||
|
tsk_invalid_expl_inst, /* An explicit instantiation containing
|
||||||
|
template parameter lists. */
|
||||||
|
tsk_excessive_parms, /* A template declaration with too many
|
||||||
|
template parameter lists. */
|
||||||
|
tsk_insufficient_parms, /* A template declaration with too few
|
||||||
|
parameter lists. */
|
||||||
|
tsk_template, /* A template declaration. */
|
||||||
|
tsk_expl_spec, /* An explicit specialization. */
|
||||||
|
tsk_expl_inst /* An explicit instantiation. */
|
||||||
|
} tmpl_spec_kind;
|
||||||
|
|
||||||
/* Zero means prototype weakly, as in ANSI C (no args means nothing).
|
/* Zero means prototype weakly, as in ANSI C (no args means nothing).
|
||||||
Each language context defines how this variable should be set. */
|
Each language context defines how this variable should be set. */
|
||||||
extern int strict_prototype;
|
extern int strict_prototype;
|
||||||
|
@ -3682,10 +3708,10 @@ extern int toplevel_bindings_p PARAMS ((void));
|
||||||
extern int namespace_bindings_p PARAMS ((void));
|
extern int namespace_bindings_p PARAMS ((void));
|
||||||
extern void keep_next_level PARAMS ((int));
|
extern void keep_next_level PARAMS ((int));
|
||||||
extern int kept_level_p PARAMS ((void));
|
extern int kept_level_p PARAMS ((void));
|
||||||
extern void declare_pseudo_global_level PARAMS ((void));
|
extern int template_parm_scope_p PARAMS ((void));
|
||||||
extern int pseudo_global_level_p PARAMS ((void));
|
|
||||||
extern void set_class_shadows PARAMS ((tree));
|
extern void set_class_shadows PARAMS ((tree));
|
||||||
extern void pushlevel PARAMS ((int));
|
extern void begin_scope PARAMS ((scope_kind));
|
||||||
|
extern void finish_scope PARAMS ((void));
|
||||||
extern void note_level_for_for PARAMS ((void));
|
extern void note_level_for_for PARAMS ((void));
|
||||||
extern void resume_level PARAMS ((struct binding_level *));
|
extern void resume_level PARAMS ((struct binding_level *));
|
||||||
extern void delete_block PARAMS ((tree));
|
extern void delete_block PARAMS ((tree));
|
||||||
|
@ -3832,6 +3858,7 @@ extern int local_variable_p PARAMS ((tree));
|
||||||
extern int nonstatic_local_decl_p PARAMS ((tree));
|
extern int nonstatic_local_decl_p PARAMS ((tree));
|
||||||
extern tree declare_global_var PARAMS ((tree, tree));
|
extern tree declare_global_var PARAMS ((tree, tree));
|
||||||
extern void register_dtor_fn PARAMS ((tree));
|
extern void register_dtor_fn PARAMS ((tree));
|
||||||
|
extern tmpl_spec_kind current_tmpl_spec_kind PARAMS ((int));
|
||||||
|
|
||||||
/* in decl2.c */
|
/* in decl2.c */
|
||||||
extern void init_decl2 PARAMS ((void));
|
extern void init_decl2 PARAMS ((void));
|
||||||
|
|
346
gcc/cp/decl.c
346
gcc/cp/decl.c
|
@ -456,13 +456,12 @@ struct binding_level
|
||||||
tree dead_vars_from_for;
|
tree dead_vars_from_for;
|
||||||
|
|
||||||
/* 1 for the level that holds the parameters of a function.
|
/* 1 for the level that holds the parameters of a function.
|
||||||
2 for the level that holds a class declaration.
|
2 for the level that holds a class declaration. */
|
||||||
3 for levels that hold parameter declarations. */
|
unsigned parm_flag : 2;
|
||||||
unsigned parm_flag : 4;
|
|
||||||
|
|
||||||
/* 1 means make a BLOCK for this level regardless of all else.
|
/* 1 means make a BLOCK for this level regardless of all else.
|
||||||
2 for temporary binding contours created by the compiler. */
|
2 for temporary binding contours created by the compiler. */
|
||||||
unsigned keep : 3;
|
unsigned keep : 2;
|
||||||
|
|
||||||
/* Nonzero if this level "doesn't exist" for tags. */
|
/* Nonzero if this level "doesn't exist" for tags. */
|
||||||
unsigned tag_transparent : 1;
|
unsigned tag_transparent : 1;
|
||||||
|
@ -472,10 +471,15 @@ struct binding_level
|
||||||
unsigned more_cleanups_ok : 1;
|
unsigned more_cleanups_ok : 1;
|
||||||
unsigned have_cleanups : 1;
|
unsigned have_cleanups : 1;
|
||||||
|
|
||||||
/* Nonzero if this level is for storing the decls for template
|
/* Nonzero if this scope is for storing the decls for template
|
||||||
parameters and generic decls; these decls will be discarded and
|
parameters and generic decls; these decls will be discarded and
|
||||||
replaced with a TEMPLATE_DECL. */
|
replaced with a TEMPLATE_DECL. */
|
||||||
unsigned pseudo_global : 1;
|
unsigned template_parms_p : 1;
|
||||||
|
|
||||||
|
/* Nonzero if this scope corresponds to the `<>' in a
|
||||||
|
`template <>' clause. Whenever this flag is set,
|
||||||
|
TEMPLATE_PARMS_P will be set as well. */
|
||||||
|
unsigned template_spec_p : 1;
|
||||||
|
|
||||||
/* This is set for a namespace binding level. */
|
/* This is set for a namespace binding level. */
|
||||||
unsigned namespace_p : 1;
|
unsigned namespace_p : 1;
|
||||||
|
@ -487,7 +491,7 @@ struct binding_level
|
||||||
/* True if this level corresponds to an EH region, as for a try block. */
|
/* True if this level corresponds to an EH region, as for a try block. */
|
||||||
unsigned eh_region : 1;
|
unsigned eh_region : 1;
|
||||||
|
|
||||||
/* One bit left for this word. */
|
/* Four bits left for this word. */
|
||||||
|
|
||||||
#if defined(DEBUG_CP_BINDING_LEVELS)
|
#if defined(DEBUG_CP_BINDING_LEVELS)
|
||||||
/* Binding depth at which this level began. */
|
/* Binding depth at which this level began. */
|
||||||
|
@ -704,15 +708,15 @@ innermost_nonclass_level ()
|
||||||
/* Nonzero if we are currently in a toplevel binding level. This
|
/* Nonzero if we are currently in a toplevel binding level. This
|
||||||
means either the global binding level or a namespace in a toplevel
|
means either the global binding level or a namespace in a toplevel
|
||||||
binding level. Since there are no non-toplevel namespace levels,
|
binding level. Since there are no non-toplevel namespace levels,
|
||||||
this really means any namespace or pseudo-global level. We also
|
this really means any namespace or template parameter level. We
|
||||||
include a class whose context is toplevel. */
|
also include a class whose context is toplevel. */
|
||||||
|
|
||||||
int
|
int
|
||||||
toplevel_bindings_p ()
|
toplevel_bindings_p ()
|
||||||
{
|
{
|
||||||
struct binding_level *b = innermost_nonclass_level ();
|
struct binding_level *b = innermost_nonclass_level ();
|
||||||
|
|
||||||
return b->namespace_p || b->pseudo_global;
|
return b->namespace_p || b->template_parms_p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Nonzero if this is a namespace scope, or if we are defining a class
|
/* Nonzero if this is a namespace scope, or if we are defining a class
|
||||||
|
@ -750,22 +754,108 @@ kept_level_p ()
|
||||||
&& !current_binding_level->tag_transparent));
|
&& !current_binding_level->tag_transparent));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
declare_pseudo_global_level ()
|
|
||||||
{
|
|
||||||
current_binding_level->pseudo_global = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
declare_namespace_level ()
|
declare_namespace_level ()
|
||||||
{
|
{
|
||||||
current_binding_level->namespace_p = 1;
|
current_binding_level->namespace_p = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns non-zero if this scope was created to store template
|
||||||
|
parameters. */
|
||||||
|
|
||||||
int
|
int
|
||||||
pseudo_global_level_p ()
|
template_parm_scope_p ()
|
||||||
{
|
{
|
||||||
return current_binding_level->pseudo_global;
|
return current_binding_level->template_parms_p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the kind of template specialization we are currently
|
||||||
|
processing, given that it's declaration contained N_CLASS_SCOPES
|
||||||
|
explicit scope qualifications. */
|
||||||
|
|
||||||
|
tmpl_spec_kind
|
||||||
|
current_tmpl_spec_kind (n_class_scopes)
|
||||||
|
int n_class_scopes;
|
||||||
|
{
|
||||||
|
int n_template_parm_scopes = 0;
|
||||||
|
int seen_specialization_p = 0;
|
||||||
|
int innermost_specialization_p = 0;
|
||||||
|
struct binding_level *b;
|
||||||
|
|
||||||
|
/* Scan through the template parameter scopes. */
|
||||||
|
for (b = current_binding_level; b->template_parms_p; b = b->level_chain)
|
||||||
|
{
|
||||||
|
/* If we see a specialization scope inside a parameter scope,
|
||||||
|
then something is wrong. That corresponds to a declaration
|
||||||
|
like:
|
||||||
|
|
||||||
|
template <class T> template <> ...
|
||||||
|
|
||||||
|
which is always illegal since [temp.expl.spec] forbids the
|
||||||
|
specialization of a class member template if the enclosing
|
||||||
|
class templates are not explicitly specialized as well. */
|
||||||
|
if (b->template_spec_p)
|
||||||
|
{
|
||||||
|
if (n_template_parm_scopes == 0)
|
||||||
|
innermost_specialization_p = 1;
|
||||||
|
else
|
||||||
|
seen_specialization_p = 1;
|
||||||
|
}
|
||||||
|
else if (seen_specialization_p == 1)
|
||||||
|
return tsk_invalid_member_spec;
|
||||||
|
|
||||||
|
++n_template_parm_scopes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle explicit instantiations. */
|
||||||
|
if (processing_explicit_instantiation)
|
||||||
|
{
|
||||||
|
if (n_template_parm_scopes != 0)
|
||||||
|
/* We've seen a template parameter list during an explicit
|
||||||
|
instantiation. For example:
|
||||||
|
|
||||||
|
template <class T> template void f(int);
|
||||||
|
|
||||||
|
This is erroneous. */
|
||||||
|
return tsk_invalid_expl_inst;
|
||||||
|
else
|
||||||
|
return tsk_expl_inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n_template_parm_scopes < n_class_scopes)
|
||||||
|
/* We've not seen enough template headers to match all the
|
||||||
|
specialized classes present. For example:
|
||||||
|
|
||||||
|
template <class T> void R<T>::S<T>::f(int);
|
||||||
|
|
||||||
|
This is illegal; there needs to be one set of template
|
||||||
|
parameters for each class. */
|
||||||
|
return tsk_insufficient_parms;
|
||||||
|
else if (n_template_parm_scopes == n_class_scopes)
|
||||||
|
/* We're processing a non-template declaration (even though it may
|
||||||
|
be a member of a template class.) For example:
|
||||||
|
|
||||||
|
template <class T> void S<T>::f(int);
|
||||||
|
|
||||||
|
The `class T' maches the `S<T>', leaving no template headers
|
||||||
|
corresponding to the `f'. */
|
||||||
|
return tsk_none;
|
||||||
|
else if (n_template_parm_scopes > n_class_scopes + 1)
|
||||||
|
/* We've got too many template headers. For example:
|
||||||
|
|
||||||
|
template <> template <class T> void f (T);
|
||||||
|
|
||||||
|
There need to be more enclosing classes. */
|
||||||
|
return tsk_excessive_parms;
|
||||||
|
else
|
||||||
|
/* This must be a template. It's of the form:
|
||||||
|
|
||||||
|
template <class T> template <class U> void S<T>::f(U);
|
||||||
|
|
||||||
|
This is a specialization if the innermost level was a
|
||||||
|
specialization; otherwise it's just a definition of the
|
||||||
|
template. */
|
||||||
|
return innermost_specialization_p ? tsk_expl_spec : tsk_template;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -806,6 +896,38 @@ pushlevel (tag_transparent)
|
||||||
keep_next_level_flag = 0;
|
keep_next_level_flag = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Enter a new scope. The KIND indicates what kind of scope is being
|
||||||
|
created. */
|
||||||
|
|
||||||
|
void
|
||||||
|
begin_scope (sk)
|
||||||
|
scope_kind sk;
|
||||||
|
{
|
||||||
|
pushlevel (0);
|
||||||
|
|
||||||
|
switch (sk)
|
||||||
|
{
|
||||||
|
case sk_template_spec:
|
||||||
|
current_binding_level->template_spec_p = 1;
|
||||||
|
/* Fall through. */
|
||||||
|
|
||||||
|
case sk_template_parms:
|
||||||
|
current_binding_level->template_parms_p = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
my_friendly_abort (20000309);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Exit the current scope. */
|
||||||
|
|
||||||
|
void
|
||||||
|
finish_scope ()
|
||||||
|
{
|
||||||
|
poplevel (0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
note_level_for_for ()
|
note_level_for_for ()
|
||||||
{
|
{
|
||||||
|
@ -2381,7 +2503,7 @@ maybe_push_to_top_level (pseudo)
|
||||||
inserted into namespace level, finish_file wouldn't find them
|
inserted into namespace level, finish_file wouldn't find them
|
||||||
when doing pending instantiations. Therefore, don't stop at
|
when doing pending instantiations. Therefore, don't stop at
|
||||||
namespace level, but continue until :: . */
|
namespace level, but continue until :: . */
|
||||||
if (b == global_binding_level || (pseudo && b->pseudo_global))
|
if (b == global_binding_level || (pseudo && b->template_parms_p))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
old_bindings = store_bindings (b->names, old_bindings);
|
old_bindings = store_bindings (b->names, old_bindings);
|
||||||
|
@ -2590,7 +2712,7 @@ maybe_process_template_type_declaration (type, globalize, b)
|
||||||
friend case, push_template_decl will already have put the
|
friend case, push_template_decl will already have put the
|
||||||
friend into global scope, if appropriate. */
|
friend into global scope, if appropriate. */
|
||||||
if (TREE_CODE (type) != ENUMERAL_TYPE
|
if (TREE_CODE (type) != ENUMERAL_TYPE
|
||||||
&& !globalize && b->pseudo_global
|
&& !globalize && b->template_parms_p
|
||||||
&& b->level_chain->parm_flag == 2)
|
&& b->level_chain->parm_flag == 2)
|
||||||
{
|
{
|
||||||
finish_member_declaration (CLASSTYPE_TI_TEMPLATE (type));
|
finish_member_declaration (CLASSTYPE_TI_TEMPLATE (type));
|
||||||
|
@ -2675,7 +2797,7 @@ pushtag (name, type, globalize)
|
||||||
if (!context)
|
if (!context)
|
||||||
context = current_namespace;
|
context = current_namespace;
|
||||||
|
|
||||||
if ((b->pseudo_global && b->level_chain->parm_flag == 2)
|
if ((b->template_parms_p && b->level_chain->parm_flag == 2)
|
||||||
|| b->parm_flag == 2)
|
|| b->parm_flag == 2)
|
||||||
in_class = 1;
|
in_class = 1;
|
||||||
|
|
||||||
|
@ -4195,29 +4317,6 @@ maybe_push_decl (decl)
|
||||||
return pushdecl (decl);
|
return pushdecl (decl);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* This function is used to push the mangled decls for nested types into
|
|
||||||
the appropriate scope. Previously pushdecl_top_level was used, but that
|
|
||||||
is incorrect for members of local classes. */
|
|
||||||
|
|
||||||
void
|
|
||||||
pushdecl_nonclass_level (x)
|
|
||||||
tree x;
|
|
||||||
{
|
|
||||||
struct binding_level *b = current_binding_level;
|
|
||||||
|
|
||||||
my_friendly_assert (b->parm_flag != 2, 180);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* Get out of template binding levels */
|
|
||||||
while (b->pseudo_global)
|
|
||||||
b = b->level_chain;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pushdecl_with_scope (x, b);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Make the declaration(s) of X appear in CLASS scope
|
/* Make the declaration(s) of X appear in CLASS scope
|
||||||
under the name NAME. */
|
under the name NAME. */
|
||||||
|
|
||||||
|
@ -4969,9 +5068,9 @@ lookup_tag (form, name, binding_level, thislevel_only)
|
||||||
int thislevel_only;
|
int thislevel_only;
|
||||||
{
|
{
|
||||||
register struct binding_level *level;
|
register struct binding_level *level;
|
||||||
/* Non-zero if, we should look past a pseudo-global level, even if
|
/* Non-zero if, we should look past a template parameter level, even
|
||||||
THISLEVEL_ONLY. */
|
if THISLEVEL_ONLY. */
|
||||||
int allow_pseudo_global = 1;
|
int allow_template_parms_p = 1;
|
||||||
|
|
||||||
for (level = binding_level; level; level = level->level_chain)
|
for (level = binding_level; level; level = level->level_chain)
|
||||||
{
|
{
|
||||||
|
@ -4990,11 +5089,11 @@ lookup_tag (form, name, binding_level, thislevel_only)
|
||||||
{
|
{
|
||||||
tree old = binding_for_name (name, tail);
|
tree old = binding_for_name (name, tail);
|
||||||
|
|
||||||
/* If we just skipped past a pseudo global level, even
|
/* If we just skipped past a template parameter level,
|
||||||
though THISLEVEL_ONLY, and we find a template class
|
even though THISLEVEL_ONLY, and we find a template
|
||||||
declaration, then we use the _TYPE node for the
|
class declaration, then we use the _TYPE node for the
|
||||||
template. See the example below. */
|
template. See the example below. */
|
||||||
if (thislevel_only && !allow_pseudo_global
|
if (thislevel_only && !allow_template_parms_p
|
||||||
&& old && BINDING_VALUE (old)
|
&& old && BINDING_VALUE (old)
|
||||||
&& DECL_CLASS_TEMPLATE_P (BINDING_VALUE (old)))
|
&& DECL_CLASS_TEMPLATE_P (BINDING_VALUE (old)))
|
||||||
old = TREE_TYPE (BINDING_VALUE (old));
|
old = TREE_TYPE (BINDING_VALUE (old));
|
||||||
|
@ -5037,7 +5136,7 @@ lookup_tag (form, name, binding_level, thislevel_only)
|
||||||
}
|
}
|
||||||
if (thislevel_only && ! level->tag_transparent)
|
if (thislevel_only && ! level->tag_transparent)
|
||||||
{
|
{
|
||||||
if (level->pseudo_global && allow_pseudo_global)
|
if (level->template_parms_p && allow_template_parms_p)
|
||||||
{
|
{
|
||||||
/* We must deal with cases like this:
|
/* We must deal with cases like this:
|
||||||
|
|
||||||
|
@ -5050,7 +5149,7 @@ lookup_tag (form, name, binding_level, thislevel_only)
|
||||||
template parameters, rather than the (surrounding)
|
template parameters, rather than the (surrounding)
|
||||||
namespace level. Thus, we keep going one more level,
|
namespace level. Thus, we keep going one more level,
|
||||||
even though THISLEVEL_ONLY is non-zero. */
|
even though THISLEVEL_ONLY is non-zero. */
|
||||||
allow_pseudo_global = 0;
|
allow_template_parms_p = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -8680,98 +8779,77 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
|
||||||
return decl;
|
return decl;
|
||||||
|
|
||||||
if (flags == NO_SPECIAL && ctype && constructor_name (cname) == declarator)
|
if (flags == NO_SPECIAL && ctype && constructor_name (cname) == declarator)
|
||||||
|
DECL_CONSTRUCTOR_P (decl) = 1;
|
||||||
|
|
||||||
|
/* Function gets the ugly name, field gets the nice one. This call
|
||||||
|
may change the type of the function (because of default
|
||||||
|
parameters)! */
|
||||||
|
if (ctype != NULL_TREE)
|
||||||
|
grokclassfn (ctype, decl, flags, quals);
|
||||||
|
|
||||||
|
decl = check_explicit_specialization (orig_declarator, decl,
|
||||||
|
template_count,
|
||||||
|
2 * (funcdef_flag != 0) +
|
||||||
|
4 * (friendp != 0));
|
||||||
|
if (decl == error_mark_node)
|
||||||
|
return NULL_TREE;
|
||||||
|
|
||||||
|
if (ctype != NULL_TREE
|
||||||
|
&& (! TYPE_FOR_JAVA (ctype) || check_java_method (decl))
|
||||||
|
&& check)
|
||||||
{
|
{
|
||||||
tree tmp;
|
tree old_decl;
|
||||||
/* Just handle constructors here. We could do this
|
|
||||||
inside the following if stmt, but I think
|
|
||||||
that the code is more legible by breaking this
|
|
||||||
case out. See comments below for what each of
|
|
||||||
the following calls is supposed to do. */
|
|
||||||
DECL_CONSTRUCTOR_P (decl) = 1;
|
|
||||||
|
|
||||||
grokclassfn (ctype, decl, flags, quals);
|
old_decl = check_classfn (ctype, decl);
|
||||||
|
|
||||||
decl = check_explicit_specialization (orig_declarator, decl,
|
if (old_decl && TREE_CODE (old_decl) == TEMPLATE_DECL)
|
||||||
template_count,
|
/* Because grokfndecl is always supposed to return a
|
||||||
2 * (funcdef_flag != 0) +
|
FUNCTION_DECL, we pull out the DECL_TEMPLATE_RESULT
|
||||||
4 * (friendp != 0));
|
here. We depend on our callers to figure out that its
|
||||||
if (decl == error_mark_node)
|
really a template that's being returned. */
|
||||||
return NULL_TREE;
|
old_decl = DECL_TEMPLATE_RESULT (old_decl);
|
||||||
|
|
||||||
if ((! TYPE_FOR_JAVA (ctype) || check_java_method (decl))
|
if (old_decl && DECL_STATIC_FUNCTION_P (old_decl)
|
||||||
&& check)
|
&& TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
|
||||||
{
|
{
|
||||||
tmp = check_classfn (ctype, decl);
|
/* Remove the `this' parm added by grokclassfn.
|
||||||
|
XXX Isn't this done in start_function, too? */
|
||||||
if (tmp && TREE_CODE (tmp) == TEMPLATE_DECL)
|
revert_static_member_fn (&decl, NULL, NULL);
|
||||||
tmp = DECL_TEMPLATE_RESULT(tmp);
|
last_function_parms = TREE_CHAIN (last_function_parms);
|
||||||
|
|
||||||
if (tmp && DECL_ARTIFICIAL (tmp))
|
|
||||||
cp_error ("definition of implicitly-declared `%D'", tmp);
|
|
||||||
if (tmp && duplicate_decls (decl, tmp))
|
|
||||||
return tmp;
|
|
||||||
}
|
}
|
||||||
if (! grok_ctor_properties (ctype, decl))
|
if (old_decl && DECL_ARTIFICIAL (old_decl))
|
||||||
return NULL_TREE;
|
cp_error ("definition of implicitly-declared `%D'", old_decl);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tree tmp;
|
|
||||||
|
|
||||||
/* Function gets the ugly name, field gets the nice one.
|
if (old_decl)
|
||||||
This call may change the type of the function (because
|
|
||||||
of default parameters)! */
|
|
||||||
if (ctype != NULL_TREE)
|
|
||||||
grokclassfn (ctype, decl, flags, quals);
|
|
||||||
|
|
||||||
decl = check_explicit_specialization (orig_declarator, decl,
|
|
||||||
template_count,
|
|
||||||
2 * (funcdef_flag != 0) +
|
|
||||||
4 * (friendp != 0));
|
|
||||||
if (decl == error_mark_node)
|
|
||||||
return NULL_TREE;
|
|
||||||
|
|
||||||
if (ctype != NULL_TREE
|
|
||||||
&& (! TYPE_FOR_JAVA (ctype) || check_java_method (decl))
|
|
||||||
&& check)
|
|
||||||
{
|
{
|
||||||
tmp = check_classfn (ctype, decl);
|
/* Since we've smashed OLD_DECL to its
|
||||||
|
DECL_TEMPLATE_RESULT, we must do the same to DECL. */
|
||||||
|
if (TREE_CODE (decl) == TEMPLATE_DECL)
|
||||||
|
decl = DECL_TEMPLATE_RESULT (decl);
|
||||||
|
|
||||||
if (tmp && TREE_CODE (tmp) == TEMPLATE_DECL)
|
/* Attempt to merge the declarations. This can fail, in
|
||||||
tmp = DECL_TEMPLATE_RESULT (tmp);
|
the case of some illegal specialization declarations. */
|
||||||
|
if (!duplicate_decls (decl, old_decl))
|
||||||
if (tmp && DECL_STATIC_FUNCTION_P (tmp)
|
cp_error ("no `%#D' member function declared in class `%T'",
|
||||||
&& TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
|
decl, ctype);
|
||||||
{
|
return old_decl;
|
||||||
/* Remove the `this' parm added by grokclassfn.
|
|
||||||
XXX Isn't this done in start_function, too? */
|
|
||||||
revert_static_member_fn (&decl, NULL, NULL);
|
|
||||||
last_function_parms = TREE_CHAIN (last_function_parms);
|
|
||||||
}
|
|
||||||
if (tmp && DECL_ARTIFICIAL (tmp))
|
|
||||||
cp_error ("definition of implicitly-declared `%D'", tmp);
|
|
||||||
if (tmp)
|
|
||||||
{
|
|
||||||
/* Attempt to merge the declarations. This can fail, in
|
|
||||||
the case of some illegal specialization declarations. */
|
|
||||||
if (!duplicate_decls (decl, tmp))
|
|
||||||
cp_error ("no `%#D' member function declared in class `%T'",
|
|
||||||
decl, ctype);
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctype == NULL_TREE || check)
|
|
||||||
return decl;
|
|
||||||
|
|
||||||
if (virtualp)
|
|
||||||
{
|
|
||||||
DECL_VIRTUAL_P (decl) = 1;
|
|
||||||
if (DECL_VINDEX (decl) == NULL_TREE)
|
|
||||||
DECL_VINDEX (decl) = error_mark_node;
|
|
||||||
IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)) = 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (DECL_CONSTRUCTOR_P (decl) && !grok_ctor_properties (ctype, decl))
|
||||||
|
return NULL_TREE;
|
||||||
|
|
||||||
|
if (ctype == NULL_TREE || check)
|
||||||
|
return decl;
|
||||||
|
|
||||||
|
if (virtualp)
|
||||||
|
{
|
||||||
|
DECL_VIRTUAL_P (decl) = 1;
|
||||||
|
if (DECL_VINDEX (decl) == NULL_TREE)
|
||||||
|
DECL_VINDEX (decl) = error_mark_node;
|
||||||
|
IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)) = 1;
|
||||||
|
}
|
||||||
|
|
||||||
return decl;
|
return decl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1358,6 +1358,8 @@ check_classfn (ctype, function)
|
||||||
tree *end = 0;
|
tree *end = 0;
|
||||||
|
|
||||||
if (DECL_USE_TEMPLATE (function)
|
if (DECL_USE_TEMPLATE (function)
|
||||||
|
&& !(TREE_CODE (function) == TEMPLATE_DECL
|
||||||
|
&& DECL_TEMPLATE_SPECIALIZATION (function))
|
||||||
&& is_member_template (DECL_TI_TEMPLATE (function)))
|
&& is_member_template (DECL_TI_TEMPLATE (function)))
|
||||||
/* Since this is a specialization of a member template,
|
/* Since this is a specialization of a member template,
|
||||||
we're not going to find the declaration in the class.
|
we're not going to find the declaration in the class.
|
||||||
|
|
206
gcc/cp/pt.c
206
gcc/cp/pt.c
|
@ -551,8 +551,7 @@ begin_template_parm_list ()
|
||||||
|
|
||||||
pushtag contains special code to call pushdecl_with_scope on the
|
pushtag contains special code to call pushdecl_with_scope on the
|
||||||
TEMPLATE_DECL for S2. */
|
TEMPLATE_DECL for S2. */
|
||||||
pushlevel (0);
|
begin_scope (sk_template_parms);
|
||||||
declare_pseudo_global_level ();
|
|
||||||
++processing_template_decl;
|
++processing_template_decl;
|
||||||
++processing_template_parmlist;
|
++processing_template_parmlist;
|
||||||
note_template_header (0);
|
note_template_header (0);
|
||||||
|
@ -596,6 +595,7 @@ check_specialization_scope ()
|
||||||
void
|
void
|
||||||
begin_specialization ()
|
begin_specialization ()
|
||||||
{
|
{
|
||||||
|
begin_scope (sk_template_spec);
|
||||||
note_template_header (1);
|
note_template_header (1);
|
||||||
check_specialization_scope ();
|
check_specialization_scope ();
|
||||||
}
|
}
|
||||||
|
@ -606,6 +606,7 @@ begin_specialization ()
|
||||||
void
|
void
|
||||||
end_specialization ()
|
end_specialization ()
|
||||||
{
|
{
|
||||||
|
finish_scope ();
|
||||||
reset_specialization ();
|
reset_specialization ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1166,109 +1167,99 @@ check_explicit_specialization (declarator, decl, template_count, flags)
|
||||||
int specialization = 0;
|
int specialization = 0;
|
||||||
int explicit_instantiation = 0;
|
int explicit_instantiation = 0;
|
||||||
int member_specialization = 0;
|
int member_specialization = 0;
|
||||||
|
|
||||||
tree ctype = DECL_CLASS_CONTEXT (decl);
|
tree ctype = DECL_CLASS_CONTEXT (decl);
|
||||||
tree dname = DECL_NAME (decl);
|
tree dname = DECL_NAME (decl);
|
||||||
|
tmpl_spec_kind tsk;
|
||||||
|
|
||||||
if (processing_specialization)
|
tsk = current_tmpl_spec_kind (template_count);
|
||||||
|
|
||||||
|
switch (tsk)
|
||||||
{
|
{
|
||||||
/* The last template header was of the form template <>. */
|
case tsk_none:
|
||||||
|
if (processing_specialization)
|
||||||
if (template_header_count > template_count)
|
|
||||||
{
|
{
|
||||||
/* There were more template headers than qualifying template
|
|
||||||
classes. */
|
|
||||||
if (template_header_count - template_count > 1)
|
|
||||||
/* There shouldn't be that many template parameter lists.
|
|
||||||
There can be at most one parameter list for every
|
|
||||||
qualifying class, plus one for the function itself. */
|
|
||||||
cp_error ("too many template parameter lists in declaration of `%D'", decl);
|
|
||||||
|
|
||||||
SET_DECL_TEMPLATE_SPECIALIZATION (decl);
|
|
||||||
if (ctype)
|
|
||||||
member_specialization = 1;
|
|
||||||
else
|
|
||||||
specialization = 1;
|
|
||||||
}
|
|
||||||
else if (template_header_count == template_count)
|
|
||||||
{
|
|
||||||
/* The counts are equal. So, this might be a
|
|
||||||
specialization, but it is not a specialization of a
|
|
||||||
member template. It might be something like
|
|
||||||
|
|
||||||
template <class T> struct S {
|
|
||||||
void f(int i);
|
|
||||||
};
|
|
||||||
template <>
|
|
||||||
void S<int>::f(int i) {} */
|
|
||||||
specialization = 1;
|
specialization = 1;
|
||||||
SET_DECL_TEMPLATE_SPECIALIZATION (decl);
|
SET_DECL_TEMPLATE_SPECIALIZATION (decl);
|
||||||
}
|
}
|
||||||
else
|
else if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
|
||||||
{
|
{
|
||||||
/* This cannot be an explicit specialization. There are not
|
if (is_friend)
|
||||||
enough headers for all of the qualifying classes. For
|
/* This could be something like:
|
||||||
example, we might have:
|
|
||||||
|
|
||||||
template <>
|
|
||||||
void S<int>::T<char>::f();
|
|
||||||
|
|
||||||
But, we're missing another template <>. */
|
template <class T> void f(T);
|
||||||
cp_error("too few template parameter lists in declaration of `%D'", decl);
|
class S { friend void f<>(int); } */
|
||||||
return decl;
|
specialization = 1;
|
||||||
}
|
else
|
||||||
}
|
{
|
||||||
else if (processing_explicit_instantiation)
|
/* This case handles bogus declarations like template <>
|
||||||
{
|
template <class T> void f<int>(); */
|
||||||
if (template_header_count)
|
|
||||||
cp_error ("template parameter list used in explicit instantiation");
|
cp_error ("template-id `%D' in declaration of primary template",
|
||||||
|
declarator);
|
||||||
|
return decl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case tsk_invalid_member_spec:
|
||||||
|
/* The error has already been reported in
|
||||||
|
check_specialization_scope. */
|
||||||
|
return error_mark_node;
|
||||||
|
|
||||||
|
case tsk_invalid_expl_inst:
|
||||||
|
cp_error ("template parameter list used in explicit instantiation");
|
||||||
|
|
||||||
|
/* Fall through. */
|
||||||
|
|
||||||
|
case tsk_expl_inst:
|
||||||
if (have_def)
|
if (have_def)
|
||||||
cp_error ("definition provided for explicit instantiation");
|
cp_error ("definition provided for explicit instantiation");
|
||||||
|
|
||||||
explicit_instantiation = 1;
|
explicit_instantiation = 1;
|
||||||
}
|
break;
|
||||||
else if (ctype != NULL_TREE
|
|
||||||
&& !TYPE_BEING_DEFINED (ctype)
|
|
||||||
&& CLASSTYPE_TEMPLATE_INSTANTIATION (ctype)
|
|
||||||
&& !is_friend)
|
|
||||||
{
|
|
||||||
/* This case catches outdated code that looks like this:
|
|
||||||
|
|
||||||
template <class T> struct S { void f(); };
|
case tsk_excessive_parms:
|
||||||
void S<int>::f() {} // Missing template <>
|
cp_error ("too many template parameter lists in declaration of `%D'",
|
||||||
|
decl);
|
||||||
|
return error_mark_node;
|
||||||
|
|
||||||
We disable this check when the type is being defined to
|
/* Fall through. */
|
||||||
avoid complaining about default compiler-generated
|
case tsk_expl_spec:
|
||||||
constructors, destructors, and assignment operators.
|
SET_DECL_TEMPLATE_SPECIALIZATION (decl);
|
||||||
Since the type is an instantiation, not a specialization,
|
if (ctype)
|
||||||
these are the only functions that can be defined before
|
member_specialization = 1;
|
||||||
the class is complete. */
|
else
|
||||||
|
specialization = 1;
|
||||||
/* If they said
|
break;
|
||||||
template <class T> void S<int>::f() {}
|
|
||||||
that's bogus. */
|
case tsk_insufficient_parms:
|
||||||
if (template_header_count)
|
if (template_header_count)
|
||||||
{
|
{
|
||||||
cp_error ("template parameters specified in specialization");
|
cp_error("too few template parameter lists in declaration of `%D'",
|
||||||
|
decl);
|
||||||
return decl;
|
return decl;
|
||||||
}
|
}
|
||||||
|
else if (ctype != NULL_TREE
|
||||||
|
&& !TYPE_BEING_DEFINED (ctype)
|
||||||
|
&& CLASSTYPE_TEMPLATE_INSTANTIATION (ctype)
|
||||||
|
&& !is_friend)
|
||||||
|
{
|
||||||
|
/* For backwards compatibility, we accept:
|
||||||
|
|
||||||
if (pedantic)
|
template <class T> struct S { void f(); };
|
||||||
cp_pedwarn
|
void S<int>::f() {} // Missing template <>
|
||||||
("explicit specialization not preceded by `template <>'");
|
|
||||||
specialization = 1;
|
|
||||||
SET_DECL_TEMPLATE_SPECIALIZATION (decl);
|
|
||||||
}
|
|
||||||
else if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
|
|
||||||
{
|
|
||||||
if (is_friend)
|
|
||||||
/* This could be something like:
|
|
||||||
|
|
||||||
template <class T> void f(T);
|
That used to be legal C++. */
|
||||||
class S { friend void f<>(int); } */
|
if (pedantic)
|
||||||
specialization = 1;
|
cp_pedwarn
|
||||||
else
|
("explicit specialization not preceded by `template <>'");
|
||||||
|
specialization = 1;
|
||||||
|
SET_DECL_TEMPLATE_SPECIALIZATION (decl);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case tsk_template:
|
||||||
|
if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
|
||||||
{
|
{
|
||||||
/* This case handles bogus declarations like template <>
|
/* This case handles bogus declarations like template <>
|
||||||
template <class T> void f<int>(); */
|
template <class T> void f<int>(); */
|
||||||
|
@ -1277,6 +1268,22 @@ check_explicit_specialization (declarator, decl, template_count, flags)
|
||||||
declarator);
|
declarator);
|
||||||
return decl;
|
return decl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctype && CLASSTYPE_TEMPLATE_INSTANTIATION (ctype))
|
||||||
|
/* This is a specialization of a member template, without
|
||||||
|
specialization the containing class. Something like:
|
||||||
|
|
||||||
|
template <class T> struct S {
|
||||||
|
template <class U> void f (U);
|
||||||
|
};
|
||||||
|
template <> template <class U> void S<int>::f(U) {}
|
||||||
|
|
||||||
|
That's a specialization -- but of the entire template. */
|
||||||
|
specialization = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
my_friendly_abort (20000309);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (specialization || member_specialization)
|
if (specialization || member_specialization)
|
||||||
|
@ -1474,10 +1481,19 @@ check_explicit_specialization (declarator, decl, template_count, flags)
|
||||||
targs = new_targs;
|
targs = new_targs;
|
||||||
}
|
}
|
||||||
|
|
||||||
decl = instantiate_template (tmpl, targs);
|
return instantiate_template (tmpl, targs);
|
||||||
return decl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If this is both a template specialization, then it's a
|
||||||
|
specialization of a member template of a template class.
|
||||||
|
In that case we want to return the TEMPLATE_DECL, not the
|
||||||
|
specialization of it. */
|
||||||
|
if (tsk == tsk_template)
|
||||||
|
{
|
||||||
|
SET_DECL_TEMPLATE_SPECIALIZATION (tmpl);
|
||||||
|
return tmpl;
|
||||||
|
}
|
||||||
|
|
||||||
/* If we though that the DECL was a member function, but it
|
/* If we though that the DECL was a member function, but it
|
||||||
turns out to be specializing a static member function,
|
turns out to be specializing a static member function,
|
||||||
make DECL a static member function as well. */
|
make DECL a static member function as well. */
|
||||||
|
@ -1504,7 +1520,7 @@ check_explicit_specialization (declarator, decl, template_count, flags)
|
||||||
we do not mangle S<int>::f() here. That's because it's
|
we do not mangle S<int>::f() here. That's because it's
|
||||||
just an ordinary member function and doesn't need special
|
just an ordinary member function and doesn't need special
|
||||||
treatment. We do this here so that the ordinary,
|
treatment. We do this here so that the ordinary,
|
||||||
non-template, name-mangling algorith will not be used
|
non-template, name-mangling algorithm will not be used
|
||||||
later. */
|
later. */
|
||||||
if ((is_member_template (tmpl) || ctype == NULL_TREE)
|
if ((is_member_template (tmpl) || ctype == NULL_TREE)
|
||||||
&& name_mangling_version >= 1)
|
&& name_mangling_version >= 1)
|
||||||
|
@ -1863,11 +1879,10 @@ end_template_decl ()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* This matches the pushlevel in begin_template_parm_list. */
|
/* This matches the pushlevel in begin_template_parm_list. */
|
||||||
poplevel (0, 0, 0);
|
finish_scope ();
|
||||||
|
|
||||||
--processing_template_decl;
|
--processing_template_decl;
|
||||||
current_template_parms = TREE_CHAIN (current_template_parms);
|
current_template_parms = TREE_CHAIN (current_template_parms);
|
||||||
(void) get_pending_sizes (); /* Why? */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Given a template argument vector containing the template PARMS.
|
/* Given a template argument vector containing the template PARMS.
|
||||||
|
@ -2370,7 +2385,7 @@ push_template_decl_real (decl, is_friend)
|
||||||
DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);
|
DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);
|
||||||
|
|
||||||
/* See if this is a primary template. */
|
/* See if this is a primary template. */
|
||||||
primary = pseudo_global_level_p ();
|
primary = template_parm_scope_p ();
|
||||||
|
|
||||||
if (primary)
|
if (primary)
|
||||||
{
|
{
|
||||||
|
@ -2444,9 +2459,6 @@ push_template_decl_real (decl, is_friend)
|
||||||
tree a, t, current, parms;
|
tree a, t, current, parms;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (CLASSTYPE_TEMPLATE_INSTANTIATION (ctx))
|
|
||||||
cp_error ("must specialize `%#T' before defining member `%#D'",
|
|
||||||
ctx, decl);
|
|
||||||
if (TREE_CODE (decl) == TYPE_DECL)
|
if (TREE_CODE (decl) == TYPE_DECL)
|
||||||
{
|
{
|
||||||
if ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (decl)))
|
if ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (decl)))
|
||||||
|
@ -5597,7 +5609,7 @@ tsubst_decl (t, args, type, in_decl)
|
||||||
template <class T> struct S {
|
template <class T> struct S {
|
||||||
template <class U> friend void f();
|
template <class U> friend void f();
|
||||||
};
|
};
|
||||||
template <class U> friend void f() {}
|
template <class U> void f() {}
|
||||||
template S<int>;
|
template S<int>;
|
||||||
template void f<double>();
|
template void f<double>();
|
||||||
|
|
||||||
|
@ -7395,7 +7407,7 @@ instantiate_template (tmpl, targ_ptr)
|
||||||
if (spec != NULL_TREE)
|
if (spec != NULL_TREE)
|
||||||
return spec;
|
return spec;
|
||||||
|
|
||||||
if (DECL_TEMPLATE_INFO (tmpl))
|
if (DECL_TEMPLATE_INFO (tmpl) && !DECL_TEMPLATE_SPECIALIZATION (tmpl))
|
||||||
{
|
{
|
||||||
/* The TMPL is a partial instantiation. To get a full set of
|
/* The TMPL is a partial instantiation. To get a full set of
|
||||||
arguments we must add the arguments used to perform the
|
arguments we must add the arguments used to perform the
|
||||||
|
@ -8944,6 +8956,8 @@ most_general_template (decl)
|
||||||
tree decl;
|
tree decl;
|
||||||
{
|
{
|
||||||
while (DECL_TEMPLATE_INFO (decl)
|
while (DECL_TEMPLATE_INFO (decl)
|
||||||
|
&& !(TREE_CODE (decl) == TEMPLATE_DECL
|
||||||
|
&& DECL_TEMPLATE_SPECIALIZATION (decl))
|
||||||
/* The DECL_TI_TEMPLATE can be a LOOKUP_EXPR or
|
/* The DECL_TI_TEMPLATE can be a LOOKUP_EXPR or
|
||||||
IDENTIFIER_NODE in some cases. (See cp-tree.h for
|
IDENTIFIER_NODE in some cases. (See cp-tree.h for
|
||||||
details.) */
|
details.) */
|
||||||
|
|
|
@ -49,7 +49,7 @@ unsigned short X_one<T>::ret_id() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
export template <class T> template <class T2> // WARNING -
|
export template <class T2> // WARNING -
|
||||||
bool compare_ge(T2 test) {
|
bool compare_ge(T2 test) {
|
||||||
if (test > type)
|
if (test > type)
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
// Build don't run:
|
||||||
|
// Origin: Mark Mitchell <mark@codesourcery.com>
|
||||||
|
|
||||||
|
template <int n> struct A {
|
||||||
|
template <class T> A (T t);
|
||||||
|
template <class T> int f(T t) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> template<class T> int A<1>::f(T t) const {return 1;}
|
||||||
|
template <> template<class T> A<1>::A (T t) {}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
A<1> a (3);
|
||||||
|
a.f(1);
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue