From dbfe21241f2cd4a39b35ef393710166ad3c4b42b Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Wed, 26 Aug 1998 13:55:47 +0000 Subject: [PATCH] cp-tree.h (finish_enum): Change prototype. * cp-tree.h (finish_enum): Change prototype. * decl.c (finish_enum): Use TYPE_VALUES, rather than taking a VALUES parameter. Don't try to compute mins/maxs if processing_template_decl. * parse.y (structsp): Use new calling sequence for finish_enum. * pt.c (tsubst_enum): Likewise. Take the new type as input. (lookup_template_class): Remove unused variables. Tweak. Register enums on instantiation list before substituting enumeration constants. (tsubst_decl): Remove unused variables. (regenerate_decl_from_template): Likewise. * decl.c (duplicate_decls): Don't obliterate the DECL_TEMPLATE_INFO for a template if we're not replacing it with anything. From-SVN: r22004 --- gcc/cp/ChangeLog | 16 +++++ gcc/cp/cp-tree.h | 2 +- gcc/cp/decl.c | 23 +++--- gcc/cp/parse.y | 10 +-- gcc/cp/pt.c | 88 ++++++++++++++--------- gcc/testsuite/g++.old-deja/g++.pt/enum8.C | 18 +++++ 6 files changed, 110 insertions(+), 47 deletions(-) create mode 100644 gcc/testsuite/g++.old-deja/g++.pt/enum8.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 78b69150416..366f352c4ca 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,21 @@ 1998-08-26 Mark Mitchell + * cp-tree.h (finish_enum): Change prototype. + * decl.c (finish_enum): Use TYPE_VALUES, rather than taking a + VALUES parameter. Don't try to compute mins/maxs if + processing_template_decl. + * parse.y (structsp): Use new calling sequence for finish_enum. + * pt.c (tsubst_enum): Likewise. Take the new type as input. + (lookup_template_class): Remove unused variables. Tweak. + Register enums on instantiation list before substituting + enumeration constants. + (tsubst_decl): Remove unused variables. + (regenerate_decl_from_template): Likewise. + + * decl.c (duplicate_decls): Don't obliterate the + DECL_TEMPLATE_INFO for a template if we're not replacing it with + anything. + * lex.c (do_identifier): Fix typo in comment. Wed Aug 26 10:54:51 1998 Kaveh R. Ghazi diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index a22a5ad61d0..bf91f830c8d 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2562,7 +2562,7 @@ extern tree xref_tag PROTO((tree, tree, tree, int)); extern tree xref_tag_from_type PROTO((tree, tree, int)); extern void xref_basetypes PROTO((tree, tree, tree, tree)); extern tree start_enum PROTO((tree)); -extern tree finish_enum PROTO((tree, tree)); +extern tree finish_enum PROTO((tree)); extern tree build_enumerator PROTO((tree, tree)); extern tree grok_enum_decls PROTO((tree)); extern int start_function PROTO((tree, tree, tree, int)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 0179eafdd26..995207d7cc3 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2982,7 +2982,8 @@ duplicate_decls (newdecl, olddecl) cp_error ("invalid redeclaration of %D", newdecl); TREE_TYPE (olddecl) = TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl)); DECL_TEMPLATE_PARMS (olddecl) = DECL_TEMPLATE_PARMS (newdecl); - DECL_TEMPLATE_INFO (olddecl) = DECL_TEMPLATE_INFO (newdecl); + if (DECL_TEMPLATE_INFO (newdecl)) + DECL_TEMPLATE_INFO (olddecl) = DECL_TEMPLATE_INFO (newdecl); DECL_TEMPLATE_SPECIALIZATIONS (olddecl) = chainon (DECL_TEMPLATE_SPECIALIZATIONS (olddecl), DECL_TEMPLATE_SPECIALIZATIONS (newdecl)); @@ -11861,12 +11862,13 @@ start_enum (name) Returns ENUMTYPE. */ tree -finish_enum (enumtype, values) - register tree enumtype, values; +finish_enum (enumtype) + tree enumtype; { register tree minnode = NULL_TREE, maxnode = NULL_TREE; /* Calculate the maximum value of any enumerator in this type. */ + tree values = TYPE_VALUES (enumtype); if (values) { tree pair; @@ -11899,12 +11901,15 @@ finish_enum (enumtype, values) = build1 (NOP_EXPR, enumtype, value); TREE_TYPE (value) = enumtype; - if (!minnode) - minnode = maxnode = value; - else if (tree_int_cst_lt (maxnode, value)) - maxnode = value; - else if (tree_int_cst_lt (value, minnode)) - minnode = value; + if (!processing_template_decl) + { + if (!minnode) + minnode = maxnode = value; + else if (tree_int_cst_lt (maxnode, value)) + maxnode = value; + else if (tree_int_cst_lt (value, minnode)) + minnode = value; + } } /* In the list we're building up, we want the enumeration diff --git a/gcc/cp/parse.y b/gcc/cp/parse.y index 9b45ea44f5b..c9842f9546f 100644 --- a/gcc/cp/parse.y +++ b/gcc/cp/parse.y @@ -2060,24 +2060,26 @@ structsp: { $3 = suspend_momentary (); $$ = start_enum ($2); } enumlist maybecomma_warn '}' - { $$.t = finish_enum ($4, $5); + { TYPE_VALUES ($4) = $5; + $$.t = finish_enum ($4); $$.new_type_flag = 1; resume_momentary ((int) $3); check_for_missing_semicolon ($4); } | ENUM identifier '{' '}' - { $$.t = finish_enum (start_enum ($2), NULL_TREE); + { $$.t = finish_enum (start_enum ($2)); $$.new_type_flag = 1; check_for_missing_semicolon ($$.t); } | ENUM '{' { $2 = suspend_momentary (); $$ = start_enum (make_anon_name ()); } enumlist maybecomma_warn '}' - { $$.t = finish_enum ($3, $4); + { TYPE_VALUES ($3) = $4; + $$.t = finish_enum ($3); resume_momentary ((int) $1); check_for_missing_semicolon ($3); $$.new_type_flag = 1; } | ENUM '{' '}' - { $$.t = finish_enum (start_enum (make_anon_name()), NULL_TREE); + { $$.t = finish_enum (start_enum (make_anon_name())); $$.new_type_flag = 1; check_for_missing_semicolon ($$.t); } | ENUM identifier diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 3f9dccc8cdb..ddaf5fecb7a 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -85,7 +85,7 @@ static tree tsubst_expr_values PROTO((tree, tree)); static int list_eq PROTO((tree, tree)); static tree get_class_bindings PROTO((tree, tree, tree)); static tree coerce_template_parms PROTO((tree, tree, tree, int, int)); -static tree tsubst_enum PROTO((tree, tree)); +static void tsubst_enum PROTO((tree, tree, tree)); static tree add_to_template_args PROTO((tree, tree)); static tree add_outermost_template_args PROTO((tree, tree)); static void maybe_adjust_types_for_deduction PROTO((unification_kind_t, tree*, @@ -3152,8 +3152,7 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope) int entering_scope; { tree template = NULL_TREE, parmlist; - char *mangled_name; - tree id, t; + tree t; if (TREE_CODE (d1) == IDENTIFIER_NODE) { @@ -3242,11 +3241,14 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope) } else { + extern tree current_local_enum; tree template_type = TREE_TYPE (template); tree type_decl; tree found = NULL_TREE; int arg_depth; int parm_depth; + int is_partial_instantiation; + tree prev_local_enum; template = most_general_template (template); parmlist = DECL_TEMPLATE_PARMS (template); @@ -3398,13 +3400,20 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope) DECL_TEMPLATE_INSTANTIATIONS list, it must be permanent. */ push_obstacks (&permanent_obstack, &permanent_obstack); + /* This type is a "partial instantiation" if any of the template + arguments still inolve template parameters. */ + is_partial_instantiation = uses_template_parms (arglist); + /* Create the type. */ if (TREE_CODE (template_type) == ENUMERAL_TYPE) { - if (!uses_template_parms (arglist)) - t = tsubst_enum (template_type, arglist); + if (!is_partial_instantiation) + { + prev_local_enum = current_local_enum; + t = start_enum (TYPE_IDENTIFIER (template_type)); + } else - /* We don't want to call tsubst_enum for this type, since + /* We don't want to call start_enum for this type, since the values for the enumeration constants may involve template parameters. And, no one should be interested in the enumeration constants for such a type. */ @@ -3439,22 +3448,37 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope) else type_decl = TYPE_NAME (t); - /* We're done with the permanent obstack, now. */ - pop_obstacks (); - /* Set up the template information. */ arglist = copy_to_permanent (arglist); SET_TYPE_TEMPLATE_INFO (t, - perm_tree_cons (template, arglist, NULL_TREE)); - DECL_TEMPLATE_INSTANTIATIONS (template) = perm_tree_cons - (arglist, t, DECL_TEMPLATE_INSTANTIATIONS (template)); + tree_cons (template, arglist, NULL_TREE)); + DECL_TEMPLATE_INSTANTIATIONS (template) + = tree_cons (arglist, t, + DECL_TEMPLATE_INSTANTIATIONS (template)); + + if (TREE_CODE (t) == ENUMERAL_TYPE + && !is_partial_instantiation) + { + /* Now that the type has been registered on the + instantiations list, we set up the enumerators. Because + the enumeration constants may involve the enumeration + type itself, we make sure to register the type first, and + then create the constants. That way, doing tsubst_expr + for the enumeration constants won't result in recursive + calls here; we'll find the instantiation and exit above. */ + tsubst_enum (template_type, t, arglist); + current_local_enum = prev_local_enum; + } + + /* We're done with the permanent obstack, now. */ + pop_obstacks (); /* Reset the name of the type, now that CLASSTYPE_TEMPLATE_INFO is set up. */ if (TREE_CODE (t) != ENUMERAL_TYPE) DECL_NAME (type_decl) = classtype_mangled_name (t); DECL_ASSEMBLER_NAME (type_decl) = DECL_NAME (type_decl); - if (! uses_template_parms (arglist)) + if (!is_partial_instantiation) { DECL_ASSEMBLER_NAME (type_decl) = get_identifier (build_overload_name (t, 1, 1)); @@ -4708,8 +4732,6 @@ tsubst_decl (t, args, type, in_decl) /* We can get here when processing a member template function of a template class. */ tree decl = DECL_TEMPLATE_RESULT (t); - tree parms; - tree* new_parms; tree spec; int is_template_template_parm = DECL_TEMPLATE_TEMPLATE_PARM_P (t); @@ -7781,7 +7803,6 @@ regenerate_decl_from_template (decl, tmpl) tree tmpl; { tree args; - tree save_ti; tree code_pattern; tree new_decl; tree gen_tmpl; @@ -8172,17 +8193,17 @@ add_maybe_template (d, fns) DECL_MAYBE_TEMPLATE (d) = 1; } -/* Instantiate an enumerated type. */ +/* Instantiate an enumerated type. TAG is the template type, NEWTAG + is the instantiation (which should have been created with + start_enum) and ARGS are the template arguments to use. */ -static tree -tsubst_enum (tag, args) - tree tag, args; +static void +tsubst_enum (tag, newtag, args) + tree tag; + tree newtag; + tree args; { - extern tree current_local_enum; - tree prev_local_enum = current_local_enum; - - tree newtag = start_enum (TYPE_IDENTIFIER (tag)); - tree e, values = NULL_TREE; + tree e; for (e = TYPE_VALUES (tag); e; e = TREE_CHAIN (e)) { @@ -8194,21 +8215,22 @@ tsubst_enum (tag, args) { if (TREE_CODE (value) == NOP_EXPR) /* This is the special case where the value is really a - TEMPLATE_PARM_INDEX. See finish_enum. */ + TEMPLATE_PARM_INDEX. See finish_enum. */ value = TREE_OPERAND (value, 0); value = tsubst_expr (value, args, NULL_TREE); } elt = build_enumerator (TREE_PURPOSE (e), value); - TREE_CHAIN (elt) = values; - values = elt; + + /* We save the enumerators we have built so far in the + TYPE_VALUES so that if the enumeration constants for + subsequent enumerators involve those for previous ones, + tsubst_copy will be able to find them. */ + TREE_CHAIN (elt) = TYPE_VALUES (newtag); + TYPE_VALUES (newtag) = elt; } - finish_enum (newtag, values); - - current_local_enum = prev_local_enum; - - return newtag; + finish_enum (newtag); } /* Set the DECL_ASSEMBLER_NAME for DECL, which is a FUNCTION_DECL that diff --git a/gcc/testsuite/g++.old-deja/g++.pt/enum8.C b/gcc/testsuite/g++.old-deja/g++.pt/enum8.C new file mode 100644 index 00000000000..e5cc58a4a2d --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/enum8.C @@ -0,0 +1,18 @@ +// Build don't link: + +template +void f(); + +template <> +void f<4>() {} + +template +struct S +{ + enum E { a = 1, b = a + 3 }; +}; + +int main() +{ + f::b>(); +}