Commit 4c571114 by Mark Mitchell Committed by Mark Mitchell

cp-tree.h (IDENTIFIER_TYPENAME_P): Use OPERATOR_TYPENAME_FORMAT here.

        * cp-tree.h (IDENTIFIER_TYPENAME_P): Use OPERATOR_TYPENAME_FORMAT
	here.
	(lang_type): Add is_partial_instantiation.  Decrease width of
	dummy.
	(PARTIAL_INSTANTIATION_P): New macro.
	(OPERATOR_TYPENAME_P): Remove.
	* decl.c (unary_op_p): Use IDENTIFIER_TYPENAME_P, not
	OPERATOR_TYPENAME_P.
	(grok_op_properties): Likewise.
	* friend.c (do_friend): Handle friends that are member functions
	correctly.
	* lex.c (init_parse): Use OPERATOR_TYPENAME_FORMAT.
	* pt.c (instantiate_class_template): Rework for clarity.  Avoid
	leaving TYPE_BEING_DEFINED set in obscure cases.  Don't do
	any more partial instantiation than is absolutely necessary for
	implicit typename.  Set PARTIAL_INSTANTIATION_P.
	(tsubst_decl): Use IDENTIFIER_TYPENAME_P.
	* semantics.c (begin_class_definition): Handle partial
	specializations of a type that was previously partially
	instantiated.

From-SVN: r24548
parent 70186b34
1999-01-06 Mark Mitchell <mark@markmitchell.com>
* cp-tree.h (IDENTIFIER_TYPENAME_P): Use OPERATOR_TYPENAME_FORMAT
here.
(lang_type): Add is_partial_instantiation. Decrease width of
dummy.
(PARTIAL_INSTANTIATION_P): New macro.
(OPERATOR_TYPENAME_P): Remove.
* decl.c (unary_op_p): Use IDENTIFIER_TYPENAME_P, not
OPERATOR_TYPENAME_P.
(grok_op_properties): Likewise.
* friend.c (do_friend): Handle friends that are member functions
correctly.
* lex.c (init_parse): Use OPERATOR_TYPENAME_FORMAT.
* pt.c (instantiate_class_template): Rework for clarity. Avoid
leaving TYPE_BEING_DEFINED set in obscure cases. Don't do
any more partial instantiation than is absolutely necessary for
implicit typename. Set PARTIAL_INSTANTIATION_P.
(tsubst_decl): Use IDENTIFIER_TYPENAME_P.
* semantics.c (begin_class_definition): Handle partial
specializations of a type that was previously partially
instantiated.
Wed Jan 6 03:18:53 1999 Mark Elbrecht <snowball3@usa.net. Wed Jan 6 03:18:53 1999 Mark Elbrecht <snowball3@usa.net.
* g++spec.c (LIBSTDCXX): Provide default definition. * g++spec.c (LIBSTDCXX): Provide default definition.
......
/* Definitions for C++ parsing and type checking. /* Definitions for C++ parsing and type checking.
Copyright (C) 1987, 92-97, 1998 Free Software Foundation, Inc. Copyright (C) 1987, 92-97, 1998, 1999 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com) Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC. This file is part of GNU CC.
...@@ -293,10 +293,12 @@ struct tree_srcloc ...@@ -293,10 +293,12 @@ struct tree_srcloc
/* Nonzero if this identifier is the prefix for a mangled C++ operator name. */ /* Nonzero if this identifier is the prefix for a mangled C++ operator name. */
#define IDENTIFIER_OPNAME_P(NODE) TREE_LANG_FLAG_2(NODE) #define IDENTIFIER_OPNAME_P(NODE) TREE_LANG_FLAG_2(NODE)
#define IDENTIFIER_TYPENAME_P(NODE) \ /* Nonzero if this identifier is the name of a type-conversion
(! strncmp (IDENTIFIER_POINTER (NODE), \ operator. */
IDENTIFIER_POINTER (ansi_opname[(int) TYPE_EXPR]), \ #define IDENTIFIER_TYPENAME_P(NODE) \
IDENTIFIER_LENGTH (ansi_opname[(int) TYPE_EXPR]))) (! strncmp (IDENTIFIER_POINTER (NODE), \
OPERATOR_TYPENAME_FORMAT, \
strlen (OPERATOR_TYPENAME_FORMAT)))
/* Nonzero means reject anything that ANSI standard C forbids. */ /* Nonzero means reject anything that ANSI standard C forbids. */
extern int pedantic; extern int pedantic;
...@@ -723,11 +725,12 @@ struct lang_type ...@@ -723,11 +725,12 @@ struct lang_type
unsigned has_complex_assign_ref : 1; unsigned has_complex_assign_ref : 1;
unsigned has_abstract_assign_ref : 1; unsigned has_abstract_assign_ref : 1;
unsigned non_aggregate : 1; unsigned non_aggregate : 1;
unsigned is_partial_instantiation : 1;
/* The MIPS compiler gets it wrong if this struct also /* The MIPS compiler gets it wrong if this struct also
does not fill out to a multiple of 4 bytes. Add a does not fill out to a multiple of 4 bytes. Add a
member `dummy' with new bits if you go over the edge. */ member `dummy' with new bits if you go over the edge. */
unsigned dummy : 12; unsigned dummy : 11;
} type_flags; } type_flags;
int n_ancestors; int n_ancestors;
...@@ -1913,6 +1916,12 @@ extern int flag_new_for_scope; ...@@ -1913,6 +1916,12 @@ extern int flag_new_for_scope;
#define DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION(DECL) \ #define DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION(DECL) \
(DECL_TEMPLATE_INFO (DECL) && !DECL_USE_TEMPLATE (DECL)) (DECL_TEMPLATE_INFO (DECL) && !DECL_USE_TEMPLATE (DECL))
/* Non-zero if TYPE is a partial instantiation of a template class,
i.e., an instantiation whose instantiation arguments involve
template types. */
#define PARTIAL_INSTANTIATION_P(TYPE) \
(TYPE_LANG_SPECIFIC (TYPE)->type_flags.is_partial_instantiation)
/* Non-zero iff we are currently processing a declaration for an /* Non-zero iff we are currently processing a declaration for an
entity with its own template parameter list, and which is not a entity with its own template parameter list, and which is not a
full specialization. */ full specialization. */
...@@ -2189,12 +2198,6 @@ extern int current_function_parms_stored; ...@@ -2189,12 +2198,6 @@ extern int current_function_parms_stored;
#define OPERATOR_ASSIGN_FORMAT "__a%s" #define OPERATOR_ASSIGN_FORMAT "__a%s"
#define OPERATOR_FORMAT "__%s" #define OPERATOR_FORMAT "__%s"
#define OPERATOR_TYPENAME_FORMAT "__op" #define OPERATOR_TYPENAME_FORMAT "__op"
#define OPERATOR_TYPENAME_P(ID_NODE) \
(IDENTIFIER_POINTER (ID_NODE)[0] == '_' \
&& IDENTIFIER_POINTER (ID_NODE)[1] == '_' \
&& IDENTIFIER_POINTER (ID_NODE)[2] == 'o' \
&& IDENTIFIER_POINTER (ID_NODE)[3] == 'p')
/* Cannot use '$' up front, because this confuses gdb /* Cannot use '$' up front, because this confuses gdb
(names beginning with '$' are gdb-local identifiers). (names beginning with '$' are gdb-local identifiers).
......
...@@ -11653,7 +11653,7 @@ unary_op_p (name) ...@@ -11653,7 +11653,7 @@ unary_op_p (name)
return (name == ansi_opname [(int) TRUTH_NOT_EXPR] return (name == ansi_opname [(int) TRUTH_NOT_EXPR]
|| name == ansi_opname [(int) BIT_NOT_EXPR] || name == ansi_opname [(int) BIT_NOT_EXPR]
|| name == ansi_opname [(int) COMPONENT_REF] || name == ansi_opname [(int) COMPONENT_REF]
|| OPERATOR_TYPENAME_P (name)); || IDENTIFIER_TYPENAME_P (name));
} }
/* Do a little sanity-checking on how they declared their operator. */ /* Do a little sanity-checking on how they declared their operator. */
...@@ -11744,7 +11744,7 @@ grok_op_properties (decl, virtualp, friendp) ...@@ -11744,7 +11744,7 @@ grok_op_properties (decl, virtualp, friendp)
an enumeration, or a reference to an enumeration. 13.4.0.6 */ an enumeration, or a reference to an enumeration. 13.4.0.6 */
if (! methodp || DECL_STATIC_FUNCTION_P (decl)) if (! methodp || DECL_STATIC_FUNCTION_P (decl))
{ {
if (OPERATOR_TYPENAME_P (name) if (IDENTIFIER_TYPENAME_P (name)
|| name == ansi_opname[(int) CALL_EXPR] || name == ansi_opname[(int) CALL_EXPR]
|| name == ansi_opname[(int) MODIFY_EXPR] || name == ansi_opname[(int) MODIFY_EXPR]
|| name == ansi_opname[(int) COMPONENT_REF] || name == ansi_opname[(int) COMPONENT_REF]
......
/* Help friends in C++. /* Help friends in C++.
Copyright (C) 1997, 1998 Free Software Foundation, Inc. Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
This file is part of GNU CC. This file is part of GNU CC.
...@@ -370,16 +370,20 @@ do_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag) ...@@ -370,16 +370,20 @@ do_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag)
if (is_friend_template) if (is_friend_template)
decl = DECL_TI_TEMPLATE (push_template_decl (decl)); decl = DECL_TI_TEMPLATE (push_template_decl (decl));
else if (template_class_depth (current_class_type))
decl = push_template_decl_real (decl, /*is_friend=*/1);
/* We can't do lookup in a type that involves template
parameters. Instead, we rely on tsubst_friend_function
to check the validity of the declaration later. */
if (uses_template_parms (ctype))
add_friend (current_class_type, decl);
/* A nested class may declare a member of an enclosing class /* A nested class may declare a member of an enclosing class
to be a friend, so we do lookup here even if CTYPE is in to be a friend, so we do lookup here even if CTYPE is in
the process of being defined. */ the process of being defined. */
if (TYPE_SIZE (ctype) != 0 || TYPE_BEING_DEFINED (ctype)) else if (TYPE_SIZE (ctype) != 0 || TYPE_BEING_DEFINED (ctype))
{ {
/* But, we defer looup in template specializations until decl = check_classfn (ctype, decl);
they are fully specialized. */
if (template_class_depth (ctype) == 0)
decl = check_classfn (ctype, decl);
if (decl) if (decl)
add_friend (current_class_type, decl); add_friend (current_class_type, decl);
......
/* Separate lexical analyzer for GNU C++. /* Separate lexical analyzer for GNU C++.
Copyright (C) 1987, 89, 92-97, 1998 Free Software Foundation, Inc. Copyright (C) 1987, 89, 92-97, 1998, 1999 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com) Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC. This file is part of GNU CC.
...@@ -650,7 +650,7 @@ init_parse (filename) ...@@ -650,7 +650,7 @@ init_parse (filename)
IDENTIFIER_OPNAME_P (ansi_opname[(int) VEC_NEW_EXPR]) = 1; IDENTIFIER_OPNAME_P (ansi_opname[(int) VEC_NEW_EXPR]) = 1;
ansi_opname[(int) VEC_DELETE_EXPR] = get_identifier ("__vd"); ansi_opname[(int) VEC_DELETE_EXPR] = get_identifier ("__vd");
IDENTIFIER_OPNAME_P (ansi_opname[(int) VEC_DELETE_EXPR]) = 1; IDENTIFIER_OPNAME_P (ansi_opname[(int) VEC_DELETE_EXPR]) = 1;
ansi_opname[(int) TYPE_EXPR] = get_identifier ("__op"); ansi_opname[(int) TYPE_EXPR] = get_identifier (OPERATOR_TYPENAME_FORMAT);
IDENTIFIER_OPNAME_P (ansi_opname[(int) TYPE_EXPR]) = 1; IDENTIFIER_OPNAME_P (ansi_opname[(int) TYPE_EXPR]) = 1;
/* This is not true: these operators are not defined in ANSI, /* This is not true: these operators are not defined in ANSI,
......
/* Handle parameterized types (templates) for GNU C++. /* Handle parameterized types (templates) for GNU C++.
Copyright (C) 1992, 93-97, 1998 Free Software Foundation, Inc. Copyright (C) 1992, 93-97, 1998, 1999 Free Software Foundation, Inc.
Written by Ken Raeburn (raeburn@cygnus.com) while at Watchmaker Computing. Written by Ken Raeburn (raeburn@cygnus.com) while at Watchmaker Computing.
Rewritten by Jason Merrill (jason@cygnus.com). Rewritten by Jason Merrill (jason@cygnus.com).
...@@ -4436,7 +4436,6 @@ instantiate_class_template (type) ...@@ -4436,7 +4436,6 @@ instantiate_class_template (type)
{ {
tree template, args, pattern, t; tree template, args, pattern, t;
tree typedecl; tree typedecl;
int is_partial_instantiation;
if (type == error_mark_node) if (type == error_mark_node)
return error_mark_node; return error_mark_node;
...@@ -4457,9 +4456,33 @@ instantiate_class_template (type) ...@@ -4457,9 +4456,33 @@ instantiate_class_template (type)
/* Figure out which arguments are being used to do the /* Figure out which arguments are being used to do the
instantiation. */ instantiation. */
args = CLASSTYPE_TI_ARGS (type); args = CLASSTYPE_TI_ARGS (type);
is_partial_instantiation = uses_template_parms (args); PARTIAL_INSTANTIATION_P (type) = uses_template_parms (args);
if (is_partial_instantiation) if (pedantic && PARTIAL_INSTANTIATION_P (type))
/* If this is a partial instantiation, then we can't instantiate
the type; there's no telling whether or not one of the
template parameters might eventually be instantiated to some
value that results in a specialization being used. For
example, consider:
template <class T>
struct S {};
template <class U>
void f(S<U>);
template <>
struct S<int> {};
Now, the `S<U>' in `f<int>' is the specialization, not an
instantiation of the original template. Mark the type as
complete, in the same way that we do for a definition of a
template class. */
goto end;
/* Determine what specialization of the original template to
instantiate. */
if (PARTIAL_INSTANTIATION_P (type))
/* There's no telling which specialization is appropriate at this /* There's no telling which specialization is appropriate at this
point. Since all peeking at the innards of this partial point. Since all peeking at the innards of this partial
instantiation are extensions (like the "implicit typename" instantiation are extensions (like the "implicit typename"
...@@ -4500,9 +4523,39 @@ instantiate_class_template (type) ...@@ -4500,9 +4523,39 @@ instantiate_class_template (type)
else else
pattern = TREE_TYPE (template); pattern = TREE_TYPE (template);
/* If the template we're instantiating is incomplete, then clearly
there's nothing we can do. */
if (TYPE_SIZE (pattern) == NULL_TREE) if (TYPE_SIZE (pattern) == NULL_TREE)
goto end; goto end;
/* If this is a partial instantiation, don't tsubst anything. We will
only use this type for implicit typename, so the actual contents don't
matter. All that matters is whether a particular name is a type. */
if (PARTIAL_INSTANTIATION_P (type))
{
/* The fields set here must be kept in sync with those cleared
in begin_class_definition. */
TYPE_BINFO_BASETYPES (type) = TYPE_BINFO_BASETYPES (pattern);
TYPE_FIELDS (type) = TYPE_FIELDS (pattern);
TYPE_METHODS (type) = TYPE_METHODS (pattern);
CLASSTYPE_TAGS (type) = CLASSTYPE_TAGS (pattern);
/* Pretend that the type is complete, so that we will look
inside it during name lookup and such. */
TYPE_SIZE (type) = integer_zero_node;
goto end;
}
/* If we've recursively instantiated too many templates, stop. */
if (! push_tinst_level (type))
goto end;
/* Now we're really doing the instantiation. Mark the type as in
the process of being defined. */
TYPE_BEING_DEFINED (type) = 1;
maybe_push_to_top_level (uses_template_parms (type));
pushclass (type, 0);
if (t) if (t)
{ {
/* This TYPE is actually a instantiation of of a partial /* This TYPE is actually a instantiation of of a partial
...@@ -4531,31 +4584,6 @@ instantiate_class_template (type) ...@@ -4531,31 +4584,6 @@ instantiate_class_template (type)
args = inner_args; args = inner_args;
} }
if (pedantic && is_partial_instantiation)
{
/* If this is a partial instantiation, then we can't instantiate
the type; there's no telling whether or not one of the
template parameters might eventually be instantiated to some
value that results in a specialization being used. We do
mark the type as complete so that, for example, declaring one
of its members to be a friend will not be rejected. */
TYPE_SIZE (type) = integer_zero_node;
goto end;
}
TYPE_BEING_DEFINED (type) = 1;
if (! push_tinst_level (type))
goto end;
maybe_push_to_top_level (uses_template_parms (type));
pushclass (type, 0);
/* We must copy the arguments to the permanent obstack since
during the tsubst'ing below they may wind up in the
DECL_TI_ARGS of some instantiated member template. */
args = copy_to_permanent (args);
if (flag_external_templates) if (flag_external_templates)
{ {
if (flag_alt_external_templates) if (flag_alt_external_templates)
...@@ -4608,18 +4636,10 @@ instantiate_class_template (type) ...@@ -4608,18 +4636,10 @@ instantiate_class_template (type)
TYPE_ALIGN (type) = TYPE_ALIGN (pattern); TYPE_ALIGN (type) = TYPE_ALIGN (pattern);
TYPE_FOR_JAVA (type) = TYPE_FOR_JAVA (pattern); /* For libjava's JArray<T> */ TYPE_FOR_JAVA (type) = TYPE_FOR_JAVA (pattern); /* For libjava's JArray<T> */
/* If this is a partial instantiation, don't tsubst anything. We will /* We must copy the arguments to the permanent obstack since
only use this type for implicit typename, so the actual contents don't during the tsubst'ing below they may wind up in the
matter. All that matters is whether a particular name is a type. */ DECL_TI_ARGS of some instantiated member template. */
if (is_partial_instantiation) args = copy_to_permanent (args);
{
TYPE_BINFO_BASETYPES (type) = TYPE_BINFO_BASETYPES (pattern);
TYPE_FIELDS (type) = TYPE_FIELDS (pattern);
TYPE_METHODS (type) = TYPE_METHODS (pattern);
CLASSTYPE_TAGS (type) = CLASSTYPE_TAGS (pattern);
TYPE_SIZE (type) = integer_zero_node;
goto done_with_instantiation;
}
{ {
tree binfo = TYPE_BINFO (type); tree binfo = TYPE_BINFO (type);
...@@ -4850,10 +4870,7 @@ instantiate_class_template (type) ...@@ -4850,10 +4870,7 @@ instantiate_class_template (type)
TYPE_BEING_DEFINED (type) = 0; TYPE_BEING_DEFINED (type) = 0;
repo_template_used (type); repo_template_used (type);
done_with_instantiation:
TYPE_BEING_DEFINED (type) = 0;
popclass (0); popclass (0);
pop_from_top_level (); pop_from_top_level ();
pop_tinst_level (); pop_tinst_level ();
...@@ -5382,9 +5399,7 @@ tsubst_decl (t, args, type, in_decl) ...@@ -5382,9 +5399,7 @@ tsubst_decl (t, args, type, in_decl)
= tsubst_aggr_type (DECL_CONTEXT (t), args, t, /*entering_scope=*/1); = tsubst_aggr_type (DECL_CONTEXT (t), args, t, /*entering_scope=*/1);
DECL_CLASS_CONTEXT (r) = ctx; DECL_CLASS_CONTEXT (r) = ctx;
if (member && !strncmp (OPERATOR_TYPENAME_FORMAT, if (member && IDENTIFIER_TYPENAME_P (DECL_NAME (r)))
IDENTIFIER_POINTER (DECL_NAME (r)),
sizeof (OPERATOR_TYPENAME_FORMAT) - 1))
/* Type-conversion operator. Reconstruct the name, in /* Type-conversion operator. Reconstruct the name, in
case it's the name of one of the template's parameters. */ case it's the name of one of the template's parameters. */
DECL_NAME (r) = build_typename_overload (TREE_TYPE (type)); DECL_NAME (r) = build_typename_overload (TREE_TYPE (type));
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
building RTL. These routines are used both during actual parsing building RTL. These routines are used both during actual parsing
and during the instantiation of template functions. and during the instantiation of template functions.
Copyright (C) 1998 Free Software Foundation, Inc. Copyright (C) 1998, 1999 Free Software Foundation, Inc.
Written by Mark Mitchell (mmitchell@usa.net) based on code found Written by Mark Mitchell (mmitchell@usa.net) based on code found
formerly in parse.y and pt.c. formerly in parse.y and pt.c.
...@@ -1222,10 +1222,58 @@ begin_class_definition (t) ...@@ -1222,10 +1222,58 @@ begin_class_definition (t)
implicit typename, a TYPENAME_TYPE with a type. */ implicit typename, a TYPENAME_TYPE with a type. */
if (TREE_CODE (t) == TYPENAME_TYPE) if (TREE_CODE (t) == TYPENAME_TYPE)
t = TREE_TYPE (t); t = TREE_TYPE (t);
/* If we generated a partial instantiation of this type, but now
we're seeing a real definition, we're actually looking at a
partial specialization. Consider:
template <class T, class U>
struct Y {};
template <class T>
struct X {};
template <class T, class U>
void f()
{
typename X<Y<T, U> >::A a;
}
template <class T, class U>
struct X<Y<T, U> >
{
};
We have to undo the effects of the previous partial
instantiation. */
if (PARTIAL_INSTANTIATION_P (t))
{
if (!pedantic)
{
/* Unfortunately, when we're not in pedantic mode, we
attempt to actually fill in some of the fields of the
partial instantiation, in order to support the implicit
typename extension. Clear those fields now, in
preparation for the definition here. The fields cleared
here must match those set in instantiate_class_template.
Look for a comment mentioning begin_class_definition
there. */
TYPE_BINFO_BASETYPES (t) = NULL_TREE;
TYPE_FIELDS (t) = NULL_TREE;
TYPE_METHODS (t) = NULL_TREE;
CLASSTYPE_TAGS (t) = NULL_TREE;
TYPE_SIZE (t) = NULL_TREE;
}
if (TYPE_SIZE (t)) /* This isn't a partial instantiation any more. */
PARTIAL_INSTANTIATION_P (t) = 0;
}
/* If this type was already complete, and we see another definition,
that's an error. */
else if (TYPE_SIZE (t))
duplicate_tag_error (t); duplicate_tag_error (t);
if (TYPE_SIZE (t) || TYPE_BEING_DEFINED (t))
if (TYPE_BEING_DEFINED (t))
{ {
t = make_lang_type (TREE_CODE (t)); t = make_lang_type (TREE_CODE (t));
pushtag (TYPE_IDENTIFIER (t), t, 0); pushtag (TYPE_IDENTIFIER (t), t, 0);
......
// Build don't link:
template <class T>
struct S;
template <class T>
class C
{
friend void S<T>::f();
int i;
};
template <class T>
struct S
{
void f() {
C<T> c;
c.i = 3;
}
};
template void S<int>::f();
// Build don't link:
template <class T, class U>
struct Y {};
template <class T>
struct X {};
template <class T, class U>
void f()
{
typename X<Y<T, U> >::A a;
}
template <class T, class U>
struct X<Y<T, U> >
{
};
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