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>
* 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. */
} 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).
Each language context defines how this variable should be set. */
extern int strict_prototype;
......@@ -3682,10 +3708,10 @@ extern int toplevel_bindings_p PARAMS ((void));
extern int namespace_bindings_p PARAMS ((void));
extern void keep_next_level PARAMS ((int));
extern int kept_level_p PARAMS ((void));
extern void declare_pseudo_global_level PARAMS ((void));
extern int pseudo_global_level_p PARAMS ((void));
extern int template_parm_scope_p PARAMS ((void));
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 resume_level PARAMS ((struct binding_level *));
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 tree declare_global_var PARAMS ((tree, tree));
extern void register_dtor_fn PARAMS ((tree));
extern tmpl_spec_kind current_tmpl_spec_kind PARAMS ((int));
/* in decl2.c */
extern void init_decl2 PARAMS ((void));
......
......@@ -1358,6 +1358,8 @@ check_classfn (ctype, function)
tree *end = 0;
if (DECL_USE_TEMPLATE (function)
&& !(TREE_CODE (function) == TEMPLATE_DECL
&& DECL_TEMPLATE_SPECIALIZATION (function))
&& is_member_template (DECL_TI_TEMPLATE (function)))
/* Since this is a specialization of a member template,
we're not going to find the declaration in the class.
......
......@@ -551,8 +551,7 @@ begin_template_parm_list ()
pushtag contains special code to call pushdecl_with_scope on the
TEMPLATE_DECL for S2. */
pushlevel (0);
declare_pseudo_global_level ();
begin_scope (sk_template_parms);
++processing_template_decl;
++processing_template_parmlist;
note_template_header (0);
......@@ -596,6 +595,7 @@ check_specialization_scope ()
void
begin_specialization ()
{
begin_scope (sk_template_spec);
note_template_header (1);
check_specialization_scope ();
}
......@@ -606,6 +606,7 @@ begin_specialization ()
void
end_specialization ()
{
finish_scope ();
reset_specialization ();
}
......@@ -1166,109 +1167,99 @@ check_explicit_specialization (declarator, decl, template_count, flags)
int specialization = 0;
int explicit_instantiation = 0;
int member_specialization = 0;
tree ctype = DECL_CLASS_CONTEXT (decl);
tree dname = DECL_NAME (decl);
tmpl_spec_kind tsk;
if (processing_specialization)
{
/* The last template header was of the form template <>. */
tsk = current_tmpl_spec_kind (template_count);
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;
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
specialization, but it is not a specialization of a
member template. It might be something like
if (is_friend)
/* This could be something like:
template <class T> struct S {
void f(int i);
};
template <>
void S<int>::f(int i) {} */
template <class T> void f(T);
class S { friend void f<>(int); } */
specialization = 1;
SET_DECL_TEMPLATE_SPECIALIZATION (decl);
}
else
{
/* This cannot be an explicit specialization. There are not
enough headers for all of the qualifying classes. For
example, we might have:
template <>
void S<int>::T<char>::f();
/* This case handles bogus declarations like template <>
template <class T> void f<int>(); */
But, we're missing another template <>. */
cp_error("too few template parameter lists in declaration of `%D'", decl);
cp_error ("template-id `%D' in declaration of primary template",
declarator);
return decl;
}
}
else if (processing_explicit_instantiation)
{
if (template_header_count)
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)
cp_error ("definition provided for explicit instantiation");
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
&& !TYPE_BEING_DEFINED (ctype)
&& CLASSTYPE_TEMPLATE_INSTANTIATION (ctype)
&& !is_friend)
{
/* This case catches outdated code that looks like this:
/* For backwards compatibility, we accept:
template <class T> struct S { void f(); };
void S<int>::f() {} // Missing template <>
We disable this check when the type is being defined to
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;
}
That used to be legal C++. */
if (pedantic)
cp_pedwarn
("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:
break;
template <class T> void f(T);
class S { friend void f<>(int); } */
specialization = 1;
else
case tsk_template:
if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
{
/* This case handles bogus declarations like template <>
template <class T> void f<int>(); */
......@@ -1277,6 +1268,22 @@ check_explicit_specialization (declarator, decl, template_count, flags)
declarator);
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)
......@@ -1474,8 +1481,17 @@ check_explicit_specialization (declarator, decl, template_count, flags)
targs = new_targs;
}
decl = instantiate_template (tmpl, targs);
return decl;
return instantiate_template (tmpl, targs);
}
/* 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
......@@ -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
just an ordinary member function and doesn't need special
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. */
if ((is_member_template (tmpl) || ctype == NULL_TREE)
&& name_mangling_version >= 1)
......@@ -1863,11 +1879,10 @@ end_template_decl ()
return;
/* This matches the pushlevel in begin_template_parm_list. */
poplevel (0, 0, 0);
finish_scope ();
--processing_template_decl;
current_template_parms = TREE_CHAIN (current_template_parms);
(void) get_pending_sizes (); /* Why? */
}
/* 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);
/* See if this is a primary template. */
primary = pseudo_global_level_p ();
primary = template_parm_scope_p ();
if (primary)
{
......@@ -2444,9 +2459,6 @@ push_template_decl_real (decl, is_friend)
tree a, t, current, parms;
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 ((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 U> friend void f();
};
template <class U> friend void f() {}
template <class U> void f() {}
template S<int>;
template void f<double>();
......@@ -7395,7 +7407,7 @@ instantiate_template (tmpl, targ_ptr)
if (spec != NULL_TREE)
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
arguments we must add the arguments used to perform the
......@@ -8944,6 +8956,8 @@ most_general_template (decl)
tree 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
IDENTIFIER_NODE in some cases. (See cp-tree.h for
details.) */
......
......@@ -49,7 +49,7 @@ unsigned short X_one<T>::ret_id() {
return id;
}
export template <class T> template <class T2> // WARNING -
export template <class T2> // WARNING -
bool compare_ge(T2 test) {
if (test > type)
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