diff options
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 23 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 27 | ||||
-rw-r--r-- | gcc/cp/decl.c | 4 | ||||
-rw-r--r-- | gcc/cp/friend.c | 18 | ||||
-rw-r--r-- | gcc/cp/lex.c | 4 | ||||
-rw-r--r-- | gcc/cp/pt.c | 109 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 54 |
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); |