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:
parent
70186b342c
commit
4c57111494
9 changed files with 206 additions and 72 deletions
|
@ -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.
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
109
gcc/cp/pt.c
109
gcc/cp/pt.c
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
23
gcc/testsuite/g++.old-deja/g++.pt/friend39.C
Normal file
23
gcc/testsuite/g++.old-deja/g++.pt/friend39.C
Normal 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();
|
18
gcc/testsuite/g++.old-deja/g++.pt/spec27.C
Normal file
18
gcc/testsuite/g++.old-deja/g++.pt/spec27.C
Normal 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> >
|
||||
{
|
||||
};
|
Loading…
Add table
Reference in a new issue