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
This commit is contained in:
Mark Mitchell 1999-01-06 23:38:05 +00:00 committed by Mark Mitchell
parent 70186b342c
commit 4c57111494
9 changed files with 206 additions and 72 deletions

View file

@ -1,3 +1,26 @@
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.
* g++spec.c (LIBSTDCXX): Provide default definition.

View file

@ -1,5 +1,5 @@
/* 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)
This file is part of GNU CC.
@ -293,10 +293,12 @@ struct tree_srcloc
/* 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_TYPENAME_P(NODE) \
(! strncmp (IDENTIFIER_POINTER (NODE), \
IDENTIFIER_POINTER (ansi_opname[(int) TYPE_EXPR]), \
IDENTIFIER_LENGTH (ansi_opname[(int) TYPE_EXPR])))
/* Nonzero if this identifier is the name of a type-conversion
operator. */
#define IDENTIFIER_TYPENAME_P(NODE) \
(! strncmp (IDENTIFIER_POINTER (NODE), \
OPERATOR_TYPENAME_FORMAT, \
strlen (OPERATOR_TYPENAME_FORMAT)))
/* Nonzero means reject anything that ANSI standard C forbids. */
extern int pedantic;
@ -723,11 +725,12 @@ struct lang_type
unsigned has_complex_assign_ref : 1;
unsigned has_abstract_assign_ref : 1;
unsigned non_aggregate : 1;
unsigned is_partial_instantiation : 1;
/* The MIPS compiler gets it wrong if this struct also
does not fill out to a multiple of 4 bytes. Add a
member `dummy' with new bits if you go over the edge. */
unsigned dummy : 12;
unsigned dummy : 11;
} type_flags;
int n_ancestors;
@ -1913,6 +1916,12 @@ extern int flag_new_for_scope;
#define DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION(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
entity with its own template parameter list, and which is not a
full specialization. */
@ -2189,12 +2198,6 @@ extern int current_function_parms_stored;
#define OPERATOR_ASSIGN_FORMAT "__a%s"
#define OPERATOR_FORMAT "__%s"
#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
(names beginning with '$' are gdb-local identifiers).

View file

@ -11653,7 +11653,7 @@ unary_op_p (name)
return (name == ansi_opname [(int) TRUTH_NOT_EXPR]
|| name == ansi_opname [(int) BIT_NOT_EXPR]
|| 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. */
@ -11744,7 +11744,7 @@ grok_op_properties (decl, virtualp, friendp)
an enumeration, or a reference to an enumeration. 13.4.0.6 */
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) MODIFY_EXPR]
|| name == ansi_opname[(int) COMPONENT_REF]

View file

@ -1,5 +1,5 @@
/* 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.
@ -370,16 +370,20 @@ do_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag)
if (is_friend_template)
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
to be a friend, so we do lookup here even if CTYPE is in
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
they are fully specialized. */
if (template_class_depth (ctype) == 0)
decl = check_classfn (ctype, decl);
decl = check_classfn (ctype, decl);
if (decl)
add_friend (current_class_type, decl);

View file

@ -1,5 +1,5 @@
/* 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)
This file is part of GNU CC.
@ -650,7 +650,7 @@ init_parse (filename)
IDENTIFIER_OPNAME_P (ansi_opname[(int) VEC_NEW_EXPR]) = 1;
ansi_opname[(int) VEC_DELETE_EXPR] = get_identifier ("__vd");
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;
/* This is not true: these operators are not defined in ANSI,

View file

@ -1,5 +1,5 @@
/* 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.
Rewritten by Jason Merrill (jason@cygnus.com).
@ -4436,7 +4436,6 @@ instantiate_class_template (type)
{
tree template, args, pattern, t;
tree typedecl;
int is_partial_instantiation;
if (type == error_mark_node)
return error_mark_node;
@ -4457,9 +4456,33 @@ instantiate_class_template (type)
/* Figure out which arguments are being used to do the
instantiation. */
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
point. Since all peeking at the innards of this partial
instantiation are extensions (like the "implicit typename"
@ -4500,9 +4523,39 @@ instantiate_class_template (type)
else
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)
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)
{
/* This TYPE is actually a instantiation of of a partial
@ -4531,31 +4584,6 @@ instantiate_class_template (type)
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_alt_external_templates)
@ -4608,18 +4636,10 @@ instantiate_class_template (type)
TYPE_ALIGN (type) = TYPE_ALIGN (pattern);
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
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 (is_partial_instantiation)
{
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;
}
/* 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);
{
tree binfo = TYPE_BINFO (type);
@ -4850,10 +4870,7 @@ instantiate_class_template (type)
TYPE_BEING_DEFINED (type) = 0;
repo_template_used (type);
done_with_instantiation:
TYPE_BEING_DEFINED (type) = 0;
popclass (0);
pop_from_top_level ();
pop_tinst_level ();
@ -5382,9 +5399,7 @@ tsubst_decl (t, args, type, in_decl)
= tsubst_aggr_type (DECL_CONTEXT (t), args, t, /*entering_scope=*/1);
DECL_CLASS_CONTEXT (r) = ctx;
if (member && !strncmp (OPERATOR_TYPENAME_FORMAT,
IDENTIFIER_POINTER (DECL_NAME (r)),
sizeof (OPERATOR_TYPENAME_FORMAT) - 1))
if (member && IDENTIFIER_TYPENAME_P (DECL_NAME (r)))
/* Type-conversion operator. Reconstruct the name, in
case it's the name of one of the template's parameters. */
DECL_NAME (r) = build_typename_overload (TREE_TYPE (type));

View file

@ -3,7 +3,7 @@
building RTL. These routines are used both during actual parsing
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
formerly in parse.y and pt.c.
@ -1222,10 +1222,58 @@ begin_class_definition (t)
implicit typename, a TYPENAME_TYPE with a type. */
if (TREE_CODE (t) == TYPENAME_TYPE)
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:
if (TYPE_SIZE (t))
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;
}
/* 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);
if (TYPE_SIZE (t) || TYPE_BEING_DEFINED (t))
if (TYPE_BEING_DEFINED (t))
{
t = make_lang_type (TREE_CODE (t));
pushtag (TYPE_IDENTIFIER (t), t, 0);

View file

@ -0,0 +1,23 @@
// 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();

View file

@ -0,0 +1,18 @@
// 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> >
{
};