Commit 74b846e0 by Mark Mitchell Committed by Mark Mitchell

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
parent d4537148
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 { ...@@ -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)); ...@@ -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)); ...@@ -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));
......
...@@ -1358,6 +1358,8 @@ check_classfn (ctype, function) ...@@ -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.
......
...@@ -551,8 +551,7 @@ begin_template_parm_list () ...@@ -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 () ...@@ -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 () ...@@ -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) ...@@ -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);
{
/* The last template header was of the form template <>. */
if (template_header_count > template_count) switch (tsk)
{
case tsk_none:
if (processing_specialization)
{ {
/* 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; specialization = 1;
SET_DECL_TEMPLATE_SPECIALIZATION (decl);
} }
else if (template_header_count == template_count) else if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
{ {
/* The counts are equal. So, this might be a if (is_friend)
specialization, but it is not a specialization of a /* This could be something like:
member template. It might be something like
template <class T> struct S { template <class T> void f(T);
void f(int i); class S { friend void f<>(int); } */
};
template <>
void S<int>::f(int i) {} */
specialization = 1; specialization = 1;
SET_DECL_TEMPLATE_SPECIALIZATION (decl);
}
else else
{ {
/* This cannot be an explicit specialization. There are not /* This case handles bogus declarations like template <>
enough headers for all of the qualifying classes. For template <class T> void f<int>(); */
example, we might have:
template <>
void S<int>::T<char>::f();
But, we're missing another template <>. */ cp_error ("template-id `%D' in declaration of primary template",
cp_error("too few template parameter lists in declaration of `%D'", decl); declarator);
return decl; return decl;
} }
} }
else if (processing_explicit_instantiation) break;
{
if (template_header_count) 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"); 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;
case tsk_excessive_parms:
cp_error ("too many template parameter lists in declaration of `%D'",
decl);
return error_mark_node;
/* Fall through. */
case tsk_expl_spec:
SET_DECL_TEMPLATE_SPECIALIZATION (decl);
if (ctype)
member_specialization = 1;
else
specialization = 1;
break;
case tsk_insufficient_parms:
if (template_header_count)
{
cp_error("too few template parameter lists in declaration of `%D'",
decl);
return decl;
} }
else if (ctype != NULL_TREE else if (ctype != NULL_TREE
&& !TYPE_BEING_DEFINED (ctype) && !TYPE_BEING_DEFINED (ctype)
&& CLASSTYPE_TEMPLATE_INSTANTIATION (ctype) && CLASSTYPE_TEMPLATE_INSTANTIATION (ctype)
&& !is_friend) && !is_friend)
{ {
/* This case catches outdated code that looks like this: /* For backwards compatibility, we accept:
template <class T> struct S { void f(); }; template <class T> struct S { void f(); };
void S<int>::f() {} // Missing template <> void S<int>::f() {} // Missing template <>
We disable this check when the type is being defined to That used to be legal C++. */
avoid complaining about default compiler-generated
constructors, destructors, and assignment operators.
Since the type is an instantiation, not a specialization,
these are the only functions that can be defined before
the class is complete. */
/* If they said
template <class T> void S<int>::f() {}
that's bogus. */
if (template_header_count)
{
cp_error ("template parameters specified in specialization");
return decl;
}
if (pedantic) if (pedantic)
cp_pedwarn cp_pedwarn
("explicit specialization not preceded by `template <>'"); ("explicit specialization not preceded by `template <>'");
specialization = 1; specialization = 1;
SET_DECL_TEMPLATE_SPECIALIZATION (decl); SET_DECL_TEMPLATE_SPECIALIZATION (decl);
} }
else if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR) break;
{
if (is_friend)
/* This could be something like:
template <class T> void f(T); case tsk_template:
class S { friend void f<>(int); } */ if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
specialization = 1;
else
{ {
/* 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) ...@@ -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,8 +1481,17 @@ check_explicit_specialization (declarator, decl, template_count, flags) ...@@ -1474,8 +1481,17 @@ 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
...@@ -1504,7 +1520,7 @@ check_explicit_specialization (declarator, decl, template_count, flags) ...@@ -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 () ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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() { ...@@ -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;
......
// 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment