summaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>1999-01-06 23:38:05 +0000
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>1999-01-06 23:38:05 +0000
commitfb868a5dfb92d0edef5f7fcc9fd0768427afcf9f (patch)
tree54971386a4f6d1b749198b7ad7cac52a63c0a7d5 /gcc/cp
parent41ff59b864580994ab905305afefa3b900be67b3 (diff)
downloadgcc-fb868a5dfb92d0edef5f7fcc9fd0768427afcf9f.tar.gz
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@24548 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog23
-rw-r--r--gcc/cp/cp-tree.h27
-rw-r--r--gcc/cp/decl.c4
-rw-r--r--gcc/cp/friend.c18
-rw-r--r--gcc/cp/lex.c4
-rw-r--r--gcc/cp/pt.c109
-rw-r--r--gcc/cp/semantics.c54
7 files changed, 166 insertions, 73 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 7e1567b489c..478180ab80e 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b255933a1ce..db6e2281577 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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).
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 8dc8008ba98..edad0a98097 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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]
diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c
index 98991ea452b..c26d6956c11 100644
--- a/gcc/cp/friend.c
+++ b/gcc/cp/friend.c
@@ -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);
diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c
index 0d8996f6eb2..505fbba5fed 100644
--- a/gcc/cp/lex.c
+++ b/gcc/cp/lex.c
@@ -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,
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index e27286789ba..9a0545ecd9f 100644
--- a/gcc/cp/pt.c
+++ b/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));
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index b1278dcbb1d..4bd997df447 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -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:
+
+ 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);
- 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);