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)
{
/* 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); switch (tsk)
if (ctype) {
member_specialization = 1; case tsk_none:
else if (processing_specialization)
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(); };
void S<int>::f() {} // Missing template <>
We disable this check when the type is being defined to case tsk_excessive_parms:
avoid complaining about default compiler-generated cp_error ("too many template parameter lists in declaration of `%D'",
constructors, destructors, and assignment operators. decl);
Since the type is an instantiation, not a specialization, return error_mark_node;
these are the only functions that can be defined before
the class is complete. */
/* If they said /* Fall through. */
template <class T> void S<int>::f() {} case tsk_expl_spec:
that's bogus. */ SET_DECL_TEMPLATE_SPECIALIZATION (decl);
if (ctype)
member_specialization = 1;
else
specialization = 1;
break;
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) ...@@ -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) ...@@ -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) ...@@ -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