From ed44da020e182d3eee3610fe8e5eacb9518f9848 Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Thu, 6 Aug 1998 16:58:43 +0000 Subject: [PATCH] cp-tree.h (ENUM_TEMPLATE_INFO): New macro. * cp-tree.h (ENUM_TEMPLATE_INFO): New macro. (TYPE_TEMPLATE_INFO): Likewise. (SET_TYPE_TEMPLATE_INFO): Likewise. (ENUM_TI_TEMPLATE): Likewise. (ENUM_TI_ARGS): Likewise. (lookup_nested_type_by_name): Remove. * decl.c (maybe_process_template_type_declaration): Handle enums. (start_enum): Don't check for primary-template enum declarations here. (finish_enum): Clean up, document. Make sure template enum constants get the correct type. (build_enumerator): Copy initializers for template enumerations, too. (grok_enum_decls): Document. * lex.c (do_identifier): Document use of LOOKUP_EXPR a bit better. Build LOOKUP_EXPRs for local variables, even if they are TREE_PERMANENT. * pt.c (tsubst_enum): Remove field_chain parameter. (template_class_depth): Include the depth of surrounding function contexts. (push_template_decl): Check for primary-template enum declarations here. Deal with enumeration templates. (lookup_template_class): Likewise. (for_each_template_parm): Likewise. (instantiate_class_template): Don't call tsubst_enum directly, call tsubst instead, to instantiate enums. Deal with all field_chain issues here, not in tsubst_enum. (lookup_nested_type_by_name): Remove. (tsubst_aggr_type): Revise handling of enumeration types. (tsubst): Likewise. (tsubst_copy): Likewise. (tsubst_expr): Call tsubst, not tsubst_enum for TAG_DEFNs. From-SVN: r21622 --- gcc/cp/ChangeLog | 35 +++ gcc/cp/cp-tree.h | 38 ++- gcc/cp/decl.c | 117 +++++--- gcc/cp/lex.c | 17 ++ gcc/cp/pt.c | 301 ++++++++++++-------- gcc/testsuite/g++.old-deja/g++.pt/crash19.C | 19 ++ gcc/testsuite/g++.old-deja/g++.pt/enum6.C | 14 + gcc/testsuite/g++.old-deja/g++.pt/enum7.C | 27 ++ 8 files changed, 411 insertions(+), 157 deletions(-) create mode 100644 gcc/testsuite/g++.old-deja/g++.pt/crash19.C create mode 100644 gcc/testsuite/g++.old-deja/g++.pt/enum6.C create mode 100644 gcc/testsuite/g++.old-deja/g++.pt/enum7.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 12218d8ae80..f6bc1b67b19 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,38 @@ +1998-08-06 Mark Mitchell + + * cp-tree.h (ENUM_TEMPLATE_INFO): New macro. + (TYPE_TEMPLATE_INFO): Likewise. + (SET_TYPE_TEMPLATE_INFO): Likewise. + (ENUM_TI_TEMPLATE): Likewise. + (ENUM_TI_ARGS): Likewise. + (lookup_nested_type_by_name): Remove. + * decl.c (maybe_process_template_type_declaration): Handle enums. + (start_enum): Don't check for primary-template enum declarations + here. + (finish_enum): Clean up, document. Make sure template enum + constants get the correct type. + (build_enumerator): Copy initializers for template enumerations, + too. + (grok_enum_decls): Document. + * lex.c (do_identifier): Document use of LOOKUP_EXPR a bit + better. Build LOOKUP_EXPRs for local variables, even if they are + TREE_PERMANENT. + * pt.c (tsubst_enum): Remove field_chain parameter. + (template_class_depth): Include the depth of surrounding function + contexts. + (push_template_decl): Check for primary-template enum declarations + here. Deal with enumeration templates. + (lookup_template_class): Likewise. + (for_each_template_parm): Likewise. + (instantiate_class_template): Don't call tsubst_enum directly, + call tsubst instead, to instantiate enums. Deal with all + field_chain issues here, not in tsubst_enum. + (lookup_nested_type_by_name): Remove. + (tsubst_aggr_type): Revise handling of enumeration types. + (tsubst): Likewise. + (tsubst_copy): Likewise. + (tsubst_expr): Call tsubst, not tsubst_enum for TAG_DEFNs. + 1998-08-04 Mark Mitchell * decl.c (pushtag): Don't mangle the name of a TYPE_DECL if it diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index aa84e0fa1d2..fdcd704803f 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1245,15 +1245,38 @@ struct lang_decl /* For a VAR_DECL or FUNCTION_DECL: template-specific information. */ #define DECL_TEMPLATE_INFO(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.template_info) + +/* Template information for a RECORD_TYPE or UNION_TYPE. */ #define CLASSTYPE_TEMPLATE_INFO(NODE) (TYPE_LANG_SPECIFIC(NODE)->template_info) + +/* Template information for an ENUMERAL_TYPE. Although an enumeration may + not be a primary template, it may be declared within the scope of a + primary template and the enumeration constants may depend on + non-type template parameters. */ +#define ENUM_TEMPLATE_INFO(NODE) (TYPE_BINFO (NODE)) + +/* Template information for an ENUMERAL_, RECORD_, or UNION_TYPE. */ +#define TYPE_TEMPLATE_INFO(NODE) \ + (TREE_CODE (NODE) == ENUMERAL_TYPE \ + ? ENUM_TEMPLATE_INFO (NODE) : CLASSTYPE_TEMPLATE_INFO (NODE)) + +/* Set the template information for an ENUMERAL_, RECORD_, or + UNION_TYPE to VAL. */ +#define SET_TYPE_TEMPLATE_INFO(NODE, VAL) \ + (TREE_CODE (NODE) == ENUMERAL_TYPE \ + ? (ENUM_TEMPLATE_INFO (NODE) = VAL) \ + : (CLASSTYPE_TEMPLATE_INFO (NODE) = VAL)) + #define TI_TEMPLATE(NODE) (TREE_PURPOSE (NODE)) #define TI_ARGS(NODE) (TREE_VALUE (NODE)) #define TI_SPEC_INFO(NODE) (TREE_CHAIN (NODE)) #define TI_PENDING_TEMPLATE_FLAG(NODE) TREE_LANG_FLAG_1 (NODE) + /* TI_PENDING_SPECIALIZATION_FLAG on a template-info node indicates that the template is a specialization of a member template, but that we don't yet know which one. */ #define TI_PENDING_SPECIALIZATION_FLAG(NODE) TREE_LANG_FLAG_1 (NODE) + /* The TEMPLATE_DECL instantiated or specialized by NODE. This TEMPLATE_DECL will be the immediate parent, not the most general template. For example, in: @@ -1273,6 +1296,7 @@ struct lang_decl the DECL_TI_TEMPLATE will be a LOOKUP_EXPR for `f' and the DECL_TI_ARGS will be {int}. */ #define DECL_TI_TEMPLATE(NODE) TI_TEMPLATE (DECL_TEMPLATE_INFO (NODE)) + /* The template arguments used to obtain this decl from the most general form of DECL_TI_TEMPLATE. For the example given for DECL_TI_TEMPLATE, the DECL_TI_ARGS will be {int, double}. These @@ -1282,6 +1306,19 @@ struct lang_decl #define CLASSTYPE_TI_TEMPLATE(NODE) TI_TEMPLATE (CLASSTYPE_TEMPLATE_INFO (NODE)) #define CLASSTYPE_TI_ARGS(NODE) TI_ARGS (CLASSTYPE_TEMPLATE_INFO (NODE)) #define CLASSTYPE_TI_SPEC_INFO(NODE) TI_SPEC_INFO (CLASSTYPE_TEMPLATE_INFO (NODE)) +#define ENUM_TI_TEMPLATE(NODE) \ + TI_TEMPLATE (ENUM_TEMPLATE_INFO (NODE)) +#define ENUM_TI_ARGS(NODE) \ + TI_ARGS (ENUM_TEMPLATE_INFO (NODE)) + +/* Like DECL_TI_TEMPLATE, but for an ENUMERAL_, RECORD_, or UNION_TYPE. */ +#define TYPE_TI_TEMPLATE(NODE) \ + (TI_TEMPLATE (TYPE_TEMPLATE_INFO (NODE))) + +/* Like DECL_TI_ARGS, , but for an ENUMERAL_, RECORD_, or UNION_TYPE. */ +#define TYPE_TI_ARGS(NODE) \ + (TI_ARGS (TYPE_TEMPLATE_INFO (NODE))) + #define INNERMOST_TEMPLATE_PARMS(NODE) TREE_VALUE(NODE) #define TEMPLATE_PARMS_FOR_INLINE(NODE) TREE_LANG_FLAG_1 (NODE) @@ -2783,7 +2820,6 @@ extern void mark_class_instantiated PROTO((tree, int)); extern void do_decl_instantiation PROTO((tree, tree, tree)); extern void do_type_instantiation PROTO((tree, tree)); extern tree instantiate_decl PROTO((tree)); -extern tree lookup_nested_type_by_name PROTO((tree, tree)); extern tree do_poplevel PROTO((void)); extern tree get_bindings PROTO((tree, tree, tree)); /* CONT ... */ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 699170a0c92..1b70a1ba915 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2253,26 +2253,29 @@ maybe_process_template_type_declaration (type, globalize, b) { maybe_check_template_type (type); - if (IS_AGGR_TYPE (type) - && (/* If !GLOBALIZE then we are looking at a definition. - It may not be a primary template. (For example, in: + my_friendly_assert (IS_AGGR_TYPE (type) + || TREE_CODE (type) == ENUMERAL_TYPE, 0); + + + if (/* If !GLOBALIZE then we are looking at a definition. + It may not be a primary template. (For example, in: - template - struct S1 { class S2 {}; } + template + struct S1 { class S2 {}; } - we have to push_template_decl for S2.) */ - (processing_template_decl && !globalize) - /* If we are declaring a friend template class, we will - have GLOBALIZE set, since something like: + we have to push_template_decl for S2.) */ + (processing_template_decl && !globalize) + /* If we are declaring a friend template class, we will + have GLOBALIZE set, since something like: - template - struct S1 { - template - friend class S2; - }; + template + struct S1 { + template + friend class S2; + }; - declares S2 to be at global scope. */ - || PROCESSING_REAL_TEMPLATE_DECL_P ())) + declares S2 to be at global scope. */ + || PROCESSING_REAL_TEMPLATE_DECL_P ()) { /* This may change after the call to push_template_decl_real, but we want the original value. */ @@ -2286,7 +2289,8 @@ maybe_process_template_type_declaration (type, globalize, b) declaration of the member class into the class scope. In the friend case, push_template_decl will already have put the friend into global scope, if appropriate. */ - if (!globalize && b->pseudo_global + if (TREE_CODE (type) != ENUMERAL_TYPE + && !globalize && b->pseudo_global && b->level_chain->parm_flag == 2) { pushdecl_with_scope (CLASSTYPE_TI_TEMPLATE (type), @@ -11753,9 +11757,6 @@ start_enum (name) pushtag (name, enumtype, 0); } - if (b->pseudo_global) - cp_error ("template declaration of `%#T'", enumtype); - if (current_class_type) TREE_ADDRESSABLE (b->tags) = 1; @@ -11783,30 +11784,46 @@ finish_enum (enumtype, values) if (values) { - register tree pair; - register tree value = DECL_INITIAL (TREE_VALUE (values)); + tree pair; - if (! processing_template_decl) - { - /* Speed up the main loop by performing some precalculations */ - TREE_TYPE (TREE_VALUE (values)) = enumtype; - TREE_TYPE (value) = enumtype; - minnode = maxnode = value; - } - TREE_VALUE (values) = value; - - for (pair = TREE_CHAIN (values); pair; pair = TREE_CHAIN (pair)) + for (pair = values; pair; pair = TREE_CHAIN (pair)) { - value = DECL_INITIAL (TREE_VALUE (pair)); - if (! processing_template_decl) - { - TREE_TYPE (TREE_VALUE (pair)) = enumtype; + tree decl; + tree value; + + /* The TREE_VALUE is a CONST_DECL for this enumeration + constant. */ + decl = TREE_VALUE (pair); + + /* The type of the CONST_DECL is the type of the enumeration, + not an INTEGER_TYPE. */ + TREE_TYPE (decl) = enumtype; + + /* The DECL_INITIAL will be NULL if we are processing a + template declaration and this enumeration constant had no + explicit initializer. */ + value = DECL_INITIAL (decl); + if (value) + { + /* Set the TREE_TYPE for the VALUE as well. When + processing a template, however, we might have a + TEMPLATE_PARM_INDEX, and we should not change the + type of such a thing. */ + if (TREE_CODE (value) == TEMPLATE_PARM_INDEX) + DECL_INITIAL (decl) = value + = build1 (NOP_EXPR, enumtype, value); TREE_TYPE (value) = enumtype; - if (tree_int_cst_lt (maxnode, value)) + + 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 + values, not the CONST_DECLs. */ TREE_VALUE (pair) = value; } } @@ -11922,16 +11939,17 @@ build_enumerator (name, value) /* Remove no-op casts from the value. */ if (value) STRIP_TYPE_NOPS (value); - - /* We have to always copy here; not all INTEGER_CSTs are unshared, - and there's no wedding ring. Look at size_int()...*/ - value = copy_node (value); #if 0 /* To fix MAX_VAL enum consts. (bkoz) */ TREE_TYPE (value) = integer_type_node; #endif } + /* We have to always copy here; not all INTEGER_CSTs are unshared, + and there's no wedding ring. Look at size_int()...*/ + if (value != NULL_TREE) + value = copy_node (value); + /* C++ associates enums with global, function, or class declarations. */ decl = current_scope (); @@ -11970,6 +11988,23 @@ build_enumerator (name, value) return result; } +/* Called after we have finished the declaration of an enumeration + type, and, perhaps, some objects whose type involves the + enumeration type. DECL, if non-NULL, is the declaration of the + first such object. + + If CURRENT_LOCAL_ENUM is NULL, the DECL is returned. + + If CURRENT_LOCAL_ENUM is non-NULL, it should be the CONST_DECL for + the last enumeration constant of an enumeration type that is a + member of a class. The enumeration constants are already chained + together through their TREE_CHAIN fields. This function sets the + TREE_CHAIN of the last enumeration constant to DECL. The + CONST_DECL for the last enumeration constant is returned. + + CURRENT_LOCAL_ENUM will always be NULL when this function + returns. */ + tree grok_enum_decls (decl) tree decl; diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c index a9166d1fd44..32719659390 100644 --- a/gcc/cp/lex.c +++ b/gcc/cp/lex.c @@ -2988,9 +2988,26 @@ do_identifier (token, parsing, args) else id = hack_identifier (id, token); + /* We must look up dependent names when the template is + instantiated, not while parsing it. For now, we don't + distinguish between dependent and independent names. So, for + example, we look up all overloaded functions at + instantiation-time, even though in some cases we should just use + the DECL we have here. We also use LOOKUP_EXPRs to find things + like local variables, rather than created TEMPLATE_DECLs for the + local variables and then finding matching instantiations. */ if (current_template_parms && (is_overloaded_fn (id) + /* If it's not going to be around at instantiation time, we + look it up then. This is a hack, and should go when we + really get dependent/independent name lookup right. */ || !TREE_PERMANENT (id) + /* Some local VAR_DECLs (such as those for local variables + in member functions of local classes) are built on the + permanent obstack. */ + || (TREE_CODE (id) == VAR_DECL + && CP_DECL_CONTEXT (id) + && TREE_CODE (CP_DECL_CONTEXT (id)) == FUNCTION_DECL) || TREE_CODE (id) == PARM_DECL || TREE_CODE (id) == USING_DECL)) id = build_min_nt (LOOKUP_EXPR, token); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 6775575cb59..3071f1e3715 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, tree *)); +static tree tsubst_enum PROTO((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*, @@ -254,15 +254,29 @@ template_class_depth_real (type, count_specializations) int depth; for (depth = 0; - type && TREE_CODE (type) != FUNCTION_DECL - && TREE_CODE (type) != NAMESPACE_DECL; - type = TYPE_CONTEXT (type)) - if (CLASSTYPE_TEMPLATE_INFO (type) - && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type)) - && ((count_specializations - && CLASSTYPE_TEMPLATE_SPECIALIZATION (type)) - || uses_template_parms (CLASSTYPE_TI_ARGS (type)))) - ++depth; + type && TREE_CODE (type) != NAMESPACE_DECL; + type = (TREE_CODE (type) == FUNCTION_DECL) + ? DECL_REAL_CONTEXT (type) : TYPE_CONTEXT (type)) + { + if (TREE_CODE (type) != FUNCTION_DECL) + { + if (CLASSTYPE_TEMPLATE_INFO (type) + && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type)) + && ((count_specializations + && CLASSTYPE_TEMPLATE_SPECIALIZATION (type)) + || uses_template_parms (CLASSTYPE_TI_ARGS (type)))) + ++depth; + } + else + { + if (DECL_TEMPLATE_INFO (type) + && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (type)) + && ((count_specializations + && DECL_TEMPLATE_SPECIALIZATION (type)) + || uses_template_parms (DECL_TI_ARGS (type)))) + ++depth; + } + } return depth; } @@ -1802,10 +1816,14 @@ push_template_decl_real (decl, is_friend) cp_error ("template with C linkage"); if (TREE_CODE (decl) == TYPE_DECL && ANON_AGGRNAME_P (DECL_NAME (decl))) cp_error ("template class without a name"); + if (TREE_CODE (decl) == TYPE_DECL + && TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE) + cp_error ("template declaration of `%#T'", TREE_TYPE (decl)); } /* Partial specialization. */ if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl) + && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl))) { tree type = TREE_TYPE (decl); @@ -1930,10 +1948,11 @@ push_template_decl_real (decl, is_friend) ctx, decl); if (TREE_CODE (decl) == TYPE_DECL) { - if (IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (decl))) - && CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (decl)) - && CLASSTYPE_TI_TEMPLATE (TREE_TYPE (decl))) - tmpl = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (decl)); + if ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (decl))) + || TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE) + && TYPE_TEMPLATE_INFO (TREE_TYPE (decl)) + && TYPE_TI_TEMPLATE (TREE_TYPE (decl))) + tmpl = TYPE_TI_TEMPLATE (TREE_TYPE (decl)); else { cp_error ("`%D' does not declare a template type", decl); @@ -2037,8 +2056,9 @@ push_template_decl_real (decl, is_friend) if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)) { - CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (tmpl)) = info; - if (!ctx || TREE_CODE (ctx) != FUNCTION_DECL) + SET_TYPE_TEMPLATE_INFO (TREE_TYPE (tmpl), info); + if ((!ctx || TREE_CODE (ctx) != FUNCTION_DECL) + && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE) DECL_NAME (decl) = classtype_mangled_name (TREE_TYPE (decl)); } else if (! DECL_LANG_SPECIFIC (decl)) @@ -3124,9 +3144,11 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope) template = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (d1)); d1 = DECL_NAME (template); } - else if (TREE_CODE_CLASS (TREE_CODE (d1)) == 't' && IS_AGGR_TYPE (d1)) + else if (TREE_CODE (d1) == ENUMERAL_TYPE + || (TREE_CODE_CLASS (TREE_CODE (d1)) == 't' + && IS_AGGR_TYPE (d1))) { - template = CLASSTYPE_TI_TEMPLATE (d1); + template = TYPE_TI_TEMPLATE (d1); d1 = DECL_NAME (template); } else if (TREE_CODE (d1) == TEMPLATE_DECL @@ -3229,7 +3251,7 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope) return error_mark_node; } - arglist = add_to_template_args (CLASSTYPE_TI_ARGS (context), + arglist = add_to_template_args (TYPE_TI_ARGS (context), arglist); arg_depth = TMPL_ARGS_DEPTH (arglist); } @@ -3286,7 +3308,7 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope) the `C' is just the same as `C'. Outside of the class, however, such a reference is an instantiation. */ - if (comp_template_args (CLASSTYPE_TI_ARGS (template_type), + if (comp_template_args (TYPE_TI_ARGS (template_type), arglist)) { found = template_type; @@ -3338,45 +3360,67 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope) push_obstacks (&permanent_obstack, &permanent_obstack); /* Create the type. */ - t = make_lang_type (TREE_CODE (template_type)); - CLASSTYPE_DECLARED_CLASS (t) - = CLASSTYPE_DECLARED_CLASS (template_type); - TYPE_CONTEXT (t) = FROB_CONTEXT (context); + if (TREE_CODE (template_type) == ENUMERAL_TYPE) + { + if (!uses_template_parms (arglist)) + t = tsubst_enum (template_type, arglist); + else + /* We don't want to call tsubst_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. */ + t = make_node (ENUMERAL_TYPE); + } + else + { + t = make_lang_type (TREE_CODE (template_type)); + CLASSTYPE_DECLARED_CLASS (t) + = CLASSTYPE_DECLARED_CLASS (template_type); + CLASSTYPE_GOT_SEMICOLON (t) = 1; + SET_CLASSTYPE_IMPLICIT_INSTANTIATION (t); + } + + /* If we called tsubst_enum above, this information will already + be set up. */ + if (!TYPE_NAME (t)) + { + TYPE_CONTEXT (t) = FROB_CONTEXT (context); - /* Create a stub TYPE_DECL for it. */ - type_decl = build_decl (TYPE_DECL, DECL_NAME (template), t); - SET_DECL_ARTIFICIAL (type_decl); - DECL_CONTEXT (type_decl) = TYPE_CONTEXT (t); - DECL_SOURCE_FILE (type_decl) - = DECL_SOURCE_FILE (TYPE_STUB_DECL (template_type)); - DECL_SOURCE_LINE (type_decl) - = DECL_SOURCE_LINE (TYPE_STUB_DECL (template_type)); - TYPE_STUB_DECL (t) = TYPE_NAME (t) = type_decl; + /* Create a stub TYPE_DECL for it. */ + type_decl = build_decl (TYPE_DECL, DECL_NAME (template), t); + SET_DECL_ARTIFICIAL (type_decl); + DECL_CONTEXT (type_decl) = TYPE_CONTEXT (t); + DECL_SOURCE_FILE (type_decl) + = DECL_SOURCE_FILE (TYPE_STUB_DECL (template_type)); + DECL_SOURCE_LINE (type_decl) + = DECL_SOURCE_LINE (TYPE_STUB_DECL (template_type)); + TYPE_STUB_DECL (t) = TYPE_NAME (t) = type_decl; + } + else + type_decl = TYPE_NAME (t); /* We're done with the permanent obstack, now. */ pop_obstacks (); - /* Seems to be wanted. */ - CLASSTYPE_GOT_SEMICOLON (t) = 1; - /* Set up the template information. */ arglist = copy_to_permanent (arglist); - CLASSTYPE_TEMPLATE_INFO (t) - = perm_tree_cons (template, arglist, NULL_TREE); + 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)); - SET_CLASSTYPE_IMPLICIT_INSTANTIATION (t); /* Reset the name of the type, now that CLASSTYPE_TEMPLATE_INFO is set up. */ - DECL_NAME (type_decl) = classtype_mangled_name (t); + 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)) { DECL_ASSEMBLER_NAME (type_decl) = get_identifier (build_overload_name (t, 1, 1)); - if (flag_external_templates + if (TREE_CODE (t) != ENUMERAL_TYPE + && flag_external_templates && CLASSTYPE_INTERFACE_KNOWN (TREE_TYPE (template)) && ! CLASSTYPE_INTERFACE_ONLY (TREE_TYPE (template))) add_pending_template (t); @@ -3449,15 +3493,19 @@ for_each_template_parm (t, fn, data) case POINTER_TYPE: case REFERENCE_TYPE: return for_each_template_parm (TREE_TYPE (t), fn, data); + case RECORD_TYPE: if (TYPE_PTRMEMFUNC_FLAG (t)) return for_each_template_parm (TYPE_PTRMEMFUNC_FN_TYPE (t), fn, data); + /* Fall through. */ + case UNION_TYPE: - if (! CLASSTYPE_TEMPLATE_INFO (t)) + case ENUMERAL_TYPE: + if (! TYPE_TEMPLATE_INFO (t)) return 0; return for_each_template_parm (TREE_VALUE - (CLASSTYPE_TEMPLATE_INFO (t)), + (TYPE_TEMPLATE_INFO (t)), fn, data); case FUNCTION_TYPE: if (for_each_template_parm (TYPE_ARG_TYPES (t), fn, data)) @@ -3541,16 +3589,6 @@ for_each_template_parm (t, fn, data) case NAMESPACE_DECL: return 0; - case ENUMERAL_TYPE: - { - tree v; - - for (v = TYPE_VALUES (t); v != NULL_TREE; v = TREE_CHAIN (v)) - if (for_each_template_parm (TREE_VALUE (v), fn, data)) - return 1; - } - return 0; - /* constants */ case INTEGER_CST: case REAL_CST: @@ -4207,24 +4245,46 @@ instantiate_class_template (type) tree name = TYPE_IDENTIFIER (tag); tree newtag; - if (TREE_CODE (tag) == ENUMERAL_TYPE) + newtag = tsubst (tag, args, NULL_TREE); + if (TREE_CODE (newtag) == ENUMERAL_TYPE) { - newtag = tsubst_enum (tag, args, field_chain); - while (*field_chain) + extern tree current_local_enum; + tree prev_local_enum = current_local_enum; + + if (TYPE_VALUES (newtag)) { - DECL_FIELD_CONTEXT (*field_chain) = type; - field_chain = &TREE_CHAIN (*field_chain); + tree v; + + /* We must set things up so that CURRENT_LOCAL_ENUM is the + CONST_DECL for the last enumeration constant, since the + CONST_DECLs are chained backwards. */ + for (v = TYPE_VALUES (newtag); TREE_CHAIN (v); + v = TREE_CHAIN (v)) + ; + + current_local_enum + = IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (v)); + *field_chain = grok_enum_decls (NULL_TREE); + current_local_enum = prev_local_enum; + + while (*field_chain) + { + DECL_FIELD_CONTEXT (*field_chain) = type; + field_chain = &TREE_CHAIN (*field_chain); + } } } else - newtag = tsubst (tag, args, NULL_TREE); - - /* Now, we call pushtag to put this NEWTAG into the scope of - TYPE. We first set up the IDENTIFIER_TYPE_VALUE to avoid - pushtag calling push_template_decl. */ - if (name) - SET_IDENTIFIER_TYPE_VALUE (name, newtag); - pushtag (name, newtag, /*globalize=*/0); + { + /* Now, we call pushtag to put this NEWTAG into the scope of + TYPE. We first set up the IDENTIFIER_TYPE_VALUE to avoid + pushtag calling push_template_decl. We don't have to do + this for enums because it will already have been done in + tsubst_enum. */ + if (name) + SET_IDENTIFIER_TYPE_VALUE (name, newtag); + pushtag (name, newtag, /*globalize=*/0); + } } /* Don't replace enum constants here. */ @@ -4371,24 +4431,6 @@ list_eq (t1, t2) return list_eq (TREE_CHAIN (t1), TREE_CHAIN (t2)); } -tree -lookup_nested_type_by_name (ctype, name) - tree ctype, name; -{ - tree t; - - complete_type (ctype); - - for (t = CLASSTYPE_TAGS (ctype); t; t = TREE_CHAIN (t)) - { - if (name == TREE_PURPOSE (t) - /* this catches typedef enum { foo } bar; */ - || name == TYPE_IDENTIFIER (TREE_VALUE (t))) - return TREE_VALUE (t); - } - return NULL_TREE; -} - /* If arg is a non-type template parameter that does not depend on template arguments, fold it like we weren't in the body of a template. */ @@ -4507,11 +4549,11 @@ tsubst_template_parms (parms, args) return r; } -/* Substitute the ARGS into the indicated aggregate type T. If T is - not an aggregate type, it is handled as if by tsubst. IN_DECL is - as for tsubst. If ENTERING_SCOPE is non-zero, T is the context for - a template which we are presently tsubst'ing. Return the - subsituted value. */ +/* Substitute the ARGS into the indicated aggregate (or enumeration) + type T. If T is not an aggregate or enumeration type, it is + handled as if by tsubst. IN_DECL is as for tsubst. If + ENTERING_SCOPE is non-zero, T is the context for a template which + we are presently tsubst'ing. Return the subsituted value. */ tree tsubst_aggr_type (t, args, in_decl, entering_scope) @@ -4535,6 +4577,7 @@ tsubst_aggr_type (t, args, in_decl, entering_scope) } /* else fall through */ + case ENUMERAL_TYPE: case UNION_TYPE: if (uses_template_parms (t)) { @@ -4559,7 +4602,7 @@ tsubst_aggr_type (t, args, in_decl, entering_scope) and supposing that we are instantiating f, then our ARGS will be {int, double}, but, when looking up S we only want {double}. */ - argvec = tsubst (CLASSTYPE_TI_ARGS (t), args, in_decl); + argvec = tsubst (TYPE_TI_ARGS (t), args, in_decl); r = lookup_template_class (t, argvec, in_decl, context, entering_scope); @@ -4614,6 +4657,7 @@ tsubst (t, args, in_decl) { case RECORD_TYPE: case UNION_TYPE: + case ENUMERAL_TYPE: return tsubst_aggr_type (t, args, in_decl, /*entering_scope=*/0); case ERROR_MARK: @@ -4629,18 +4673,6 @@ tsubst (t, args, in_decl) case NAMESPACE_DECL: return t; - case ENUMERAL_TYPE: - { - tree ctx = tsubst_aggr_type (TYPE_CONTEXT (t), args, in_decl, - /*entering_scope=*/1); - if (ctx == NULL_TREE || TREE_CODE (ctx) == NAMESPACE_DECL) - return t; - else if (ctx == current_function_decl) - return lookup_name (TYPE_IDENTIFIER (t), 1); - else - return lookup_nested_type_by_name (ctx, TYPE_IDENTIFIER (t)); - } - case INTEGER_TYPE: if (t == integer_type_node) return t; @@ -5496,12 +5528,45 @@ tsubst_copy (t, args, in_decl) return do_identifier (DECL_NAME (t), 0, NULL_TREE); case CONST_DECL: + { + tree enum_type; + tree v; + + if (!DECL_CONTEXT (t)) + /* This is a global enumeration constant. */ + return t; + + /* Unfortunately, we cannot just call lookup_name here. + Consider: + + template int f() { + enum E { a = I }; + struct S { void g() { E e = a; } }; + }; + + When we instantiate f<7>::S::g(), say, lookup_name is not + clever enough to find f<7>::a. */ + enum_type + = tsubst_aggr_type (TREE_TYPE (t), args, in_decl, + /*entering_scope=*/0); + + for (v = TYPE_VALUES (enum_type); + v != NULL_TREE; + v = TREE_CHAIN (v)) + if (TREE_PURPOSE (v) == DECL_NAME (t)) + return TREE_VALUE (v); + + /* We didn't find the name. That should never happen; if + name-lookup found it during preliminary parsing, we + should find it again here during instantiation. */ + my_friendly_abort (0); + } + break; + case FIELD_DECL: if (DECL_CONTEXT (t)) { tree ctx; - if (TREE_CODE (DECL_CONTEXT (t)) == FUNCTION_DECL) - return lookup_name (DECL_NAME (t), 0); ctx = tsubst_aggr_type (DECL_CONTEXT (t), args, in_decl, /*entering_scope=*/1); @@ -5984,7 +6049,7 @@ tsubst_expr (t, args, in_decl) lineno = TREE_COMPLEXITY (t); t = TREE_TYPE (t); if (TREE_CODE (t) == ENUMERAL_TYPE) - tsubst_enum (t, args, NULL); + tsubst (t, args, NULL_TREE); break; default: @@ -7823,13 +7888,11 @@ add_maybe_template (d, fns) DECL_MAYBE_TEMPLATE (d) = 1; } -/* Instantiate an enumerated type. Used by instantiate_class_template and - tsubst_expr. */ +/* Instantiate an enumerated type. */ static tree -tsubst_enum (tag, args, field_chain) +tsubst_enum (tag, args) tree tag, args; - tree * field_chain; { extern tree current_local_enum; tree prev_local_enum = current_local_enum; @@ -7839,18 +7902,26 @@ tsubst_enum (tag, args, field_chain) for (e = TYPE_VALUES (tag); e; e = TREE_CHAIN (e)) { - tree elt = build_enumerator (TREE_PURPOSE (e), - tsubst_expr (TREE_VALUE (e), args, - NULL_TREE)); + tree value; + tree elt; + + value = TREE_VALUE (e); + if (value) + { + if (TREE_CODE (value) == NOP_EXPR) + /* This is the special case where the value is really a + 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; } finish_enum (newtag, values); - if (NULL != field_chain) - *field_chain = grok_enum_decls (NULL_TREE); - current_local_enum = prev_local_enum; return newtag; diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash19.C b/gcc/testsuite/g++.old-deja/g++.pt/crash19.C new file mode 100644 index 00000000000..2da6dd9bbbf --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/crash19.C @@ -0,0 +1,19 @@ +// Build don't link: + +template +void f() +{ + class C { public: int c; }; + + struct S { + void g() { + C e; + e.c = 3; + }; + }; + + S s; + s.g(); +} + +template void f<7>(); diff --git a/gcc/testsuite/g++.old-deja/g++.pt/enum6.C b/gcc/testsuite/g++.old-deja/g++.pt/enum6.C new file mode 100644 index 00000000000..acfd681ec92 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/enum6.C @@ -0,0 +1,14 @@ +// Build don't link: + +template +struct vector {}; + +template +void fn(T) +{ + enum tern { H, L, X, U }; + + vector ternvec; // ERROR - composed from a local type +} + +template void fn(int); diff --git a/gcc/testsuite/g++.old-deja/g++.pt/enum7.C b/gcc/testsuite/g++.old-deja/g++.pt/enum7.C new file mode 100644 index 00000000000..47dcbfa6761 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/enum7.C @@ -0,0 +1,27 @@ +template +int f() +{ + enum E { a = I }; + + struct S { + int g() { + E e; + e = a; + return (int) e; + }; + }; + + S s; + + return s.g(); +} + + +int main() +{ + if (f<7>() != 7) + return 1; + if (f<-3>() != -3) + return 1; + return 0; +} -- 2.30.2