diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b54b78fadd5..23b61d0e491 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,42 @@ +1998-05-25 Mark Mitchell + + * decl2.c (build_anon_union_vars): Don't crash on empty sub-unions. + + * cp-tree.h (processing_template_parmlist): Declare. + * decl.c (pushtag): Don't call push_template_decl when we + shouldn't. + * pt.c (processing_template_parmlist): New variable. + (TMPL_ARGS_HAVE_MULTIPLE_LEVELS): New macro. + (complete_template_args): Use it. + (add_to_template_args): Likewise. + (innermost_args): Likewise. + (tsubst): Likewise. + (begin_template_parm_list): Use processing_template_parmlist. + (end_template_parm_list): Likewise. + + * cp-tree.h (ANON_UNION_TYPE_P): New macro. + * decl.c (grokdeclarator): Use it. + * decl2.c (grok_x_components): Likewise. + * init.c (initializing_context): Likewise. + * method.c (do_build_copy_constructor): Likewise. + (do_build_assign_ref): Likewise. + * search.c (compute_access): Likewise. + * typeck.c (build_component_ref): Likewise. + + * decl.c (grokdeclarator): Don't give a cv-qualified version of an + unnamed type a typedef name "for linkage purposes". + + * pt.c (lookup_template_class): Don't look at + IDENTIFIER_CLASS_VALUE when there's no current_class_type. + + * method.c (build_overload_int): Handle error cases gracefully. + + * pt.c (instantiate_decl): Handle static member variables + correctly. + + * pt.c (tsubst): Use the tsubst'd type when producing new + TEMPLATE_PARM_INDEX nodes. + 1998-05-24 Mark Mitchell * tree.c (cp_tree_equal): Handle pointers to member functions. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f12a82eb253..f65fbd437ef 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1452,6 +1452,11 @@ extern int flag_new_for_scope; #define ANON_UNION_P(NODE) (DECL_NAME (NODE) == 0) +/* Nonzero if TYPE is an anonymous union type. */ +#define ANON_UNION_TYPE_P(TYPE) \ + (TREE_CODE (TYPE) == UNION_TYPE \ + && ANON_AGGRNAME_P (TYPE_IDENTIFIER (TYPE))) + #define UNKNOWN_TYPE LANG_TYPE /* Define fields and accessors for nodes representing declared names. */ @@ -2644,6 +2649,7 @@ extern int comp_template_args PROTO((tree, tree)); extern int processing_specialization; extern int processing_explicit_instantiation; +extern int processing_template_parmlist; /* in repo.c */ extern void repo_template_used PROTO((tree)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 1fb79382e6f..67604d7cd08 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2291,9 +2291,15 @@ pushtag (name, type, globalize) friend class S2; }; - declares S2 to be at global scope. */ - || (processing_template_decl > - template_class_depth (current_class_type)))) + declares S2 to be at global scope. We must be + careful, however, of the following case: + + template struct S; + + which declares a non-template class `A'. */ + || (!processing_template_parmlist + && (processing_template_decl > + template_class_depth (current_class_type))))) { d = push_template_decl_real (d, globalize); /* If the current binding level is the binding level for @@ -8750,8 +8756,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) /* Static anonymous unions are dealt with here. */ if (staticp && decl_context == TYPENAME && TREE_CODE (declspecs) == TREE_LIST - && TREE_CODE (TREE_VALUE (declspecs)) == UNION_TYPE - && ANON_AGGRNAME_P (TYPE_IDENTIFIER (TREE_VALUE (declspecs)))) + && ANON_UNION_TYPE_P (TREE_VALUE (declspecs))) decl_context = FIELD; /* Give error if `const,' `volatile,' `inline,' `friend,' or `virtual' @@ -9659,6 +9664,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) refer to it, so nothing needs know about the name change. The TYPE_NAME field was filled in by build_struct_xref. */ if (type != error_mark_node + && !TYPE_READONLY (type) && !TYPE_VOLATILE (type) && TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL && ANON_AGGRNAME_P (TYPE_IDENTIFIER (type))) diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 2ad9bbe5f22..e4c14abb30a 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -865,8 +865,7 @@ grok_x_components (specs, components) { case VAR_DECL: /* Static anonymous unions come out as VAR_DECLs. */ - if (TREE_CODE (TREE_TYPE (t)) == UNION_TYPE - && ANON_AGGRNAME_P (TYPE_IDENTIFIER (TREE_TYPE (t)))) + if (ANON_UNION_TYPE_P (TREE_TYPE (t))) return t; /* We return SPECS here, because in the parser it was ending @@ -904,8 +903,7 @@ grok_x_components (specs, components) tcode = enum_type_node; t = xref_tag (tcode, TYPE_IDENTIFIER (t), NULL_TREE, 0); - if (TREE_CODE (t) == UNION_TYPE - && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))) + if (ANON_UNION_TYPE_P (t)) { /* See also shadow_tag. */ @@ -2176,7 +2174,11 @@ build_anon_union_vars (anon_decl, elems, static_p, external_p) if (DECL_NAME (field) == NULL_TREE && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE) - decl = build_anon_union_vars (field, elems, static_p, external_p); + { + decl = build_anon_union_vars (field, elems, static_p, external_p); + if (!decl) + continue; + } else { decl = build_decl (VAR_DECL, DECL_NAME (field), TREE_TYPE (field)); diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 0d0fa8c8023..c706a04ba31 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -866,7 +866,7 @@ initializing_context (field) /* Anonymous union members can be initialized in the first enclosing non-anonymous union context. */ - while (t && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))) + while (t && ANON_UNION_TYPE_P (t)) t = TYPE_CONTEXT (t); return t; } diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 5cf4133166d..054cfddb9f3 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -515,7 +515,13 @@ build_overload_int (value, in_template) id = ansi_opname [(int) TREE_CODE (value)]; my_friendly_assert (id != NULL_TREE, 0); name = IDENTIFIER_POINTER (id); - my_friendly_assert (name[0] == '_' && name[1] == '_', 0); + if (name[0] != '_' || name[1] != '_') + /* On some erroneous inputs, we can get here with VALUE a + LOOKUP_EXPR. In that case, the NAME will be the + identifier for "". We must survive + this routine in order to issue a sensible error + message, so we fall through to the case below. */ + goto bad_value; for (i = 0; i < operands; ++i) { @@ -553,6 +559,7 @@ build_overload_int (value, in_template) This should cause assembler errors we'll notice. */ static int n; + bad_value: sprintf (digit_buffer, " *%d", n++); OB_PUTCP (digit_buffer); } @@ -2180,8 +2187,7 @@ do_build_copy_constructor (fndecl) continue; } else if ((t = TREE_TYPE (field)) != NULL_TREE - && TREE_CODE (t) == UNION_TYPE - && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)) + && ANON_UNION_TYPE_P (t) && TYPE_FIELDS (t) != NULL_TREE) { do @@ -2190,8 +2196,7 @@ do_build_copy_constructor (fndecl) field = largest_union_member (t); } while ((t = TREE_TYPE (field)) != NULL_TREE - && TREE_CODE (t) == UNION_TYPE - && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)) + && ANON_UNION_TYPE_P (t) && TYPE_FIELDS (t) != NULL_TREE); } else @@ -2290,8 +2295,7 @@ do_build_assign_ref (fndecl) continue; } else if ((t = TREE_TYPE (field)) != NULL_TREE - && TREE_CODE (t) == UNION_TYPE - && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)) + && ANON_UNION_TYPE_P (t) && TYPE_FIELDS (t) != NULL_TREE) { do @@ -2301,8 +2305,7 @@ do_build_assign_ref (fndecl) field = largest_union_member (t); } while ((t = TREE_TYPE (field)) != NULL_TREE - && TREE_CODE (t) == UNION_TYPE - && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)) + && ANON_UNION_TYPE_P (t) && TYPE_FIELDS (t) != NULL_TREE); } else diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index d148e0dd93a..dd7060ad43f 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -63,6 +63,7 @@ int minimal_parse_mode; int processing_specialization; int processing_explicit_instantiation; +int processing_template_parmlist; static int template_header_count; static tree saved_trees; @@ -115,6 +116,14 @@ static int check_cv_quals_for_unify PROTO((int, tree, tree)); static tree tsubst_template_arg_vector PROTO((tree, tree)); static void regenerate_decl_from_template PROTO((tree, tree)); +/* Nonzero if ARGVEC contains multiple levels of template arguments. */ +#define TMPL_ARGS_HAVE_MULTIPLE_LEVELS(NODE) \ + (NODE != NULL_TREE \ + && TREE_CODE (NODE) == TREE_VEC \ + && TREE_VEC_LENGTH (NODE) > 0 \ + && TREE_VEC_ELT (NODE, 0) != NULL_TREE \ + && TREE_CODE (TREE_VEC_ELT (NODE, 0)) == TREE_VEC) + /* Do any processing required when DECL (a member template declaration using TEMPLATE_PARAMETERS as its innermost parameter list) is finished. Returns the TEMPLATE_DECL corresponding to DECL, unless @@ -388,7 +397,7 @@ complete_template_args (tmpl, extra_args, unbound_only) my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 0); my_friendly_assert (TREE_CODE (extra_args) == TREE_VEC, 0); - if (TREE_CODE (TREE_VEC_ELT (extra_args, 0)) == TREE_VEC) + if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (extra_args)) extra_arg_depth = TREE_VEC_LENGTH (extra_args); else extra_arg_depth = 1; @@ -411,7 +420,7 @@ complete_template_args (tmpl, extra_args, unbound_only) TEMPLATE_DECL with DECL_TEMPLATE_INFO. DECL_TI_ARGS is all the bound template arguments. */ args = DECL_TI_ARGS (tmpl); - if (TREE_CODE (TREE_VEC_ELT (args, 0)) != TREE_VEC) + if (!TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args)) depth = 1; else depth = TREE_VEC_LENGTH (args); @@ -485,7 +494,7 @@ add_to_template_args (args, extra_args) { tree new_args; - if (TREE_CODE (TREE_VEC_ELT (args, 0)) != TREE_VEC) + if (!TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args)) { new_args = make_tree_vec (2); TREE_VEC_ELT (new_args, 0) = args; @@ -529,6 +538,7 @@ begin_template_parm_list () pushlevel (0); declare_pseudo_global_level (); ++processing_template_decl; + ++processing_template_parmlist; note_template_header (0); } @@ -1452,6 +1462,8 @@ end_template_parm_list (parms) for (parm = parms, nparms = 0; parm; parm = TREE_CHAIN (parm), nparms++) TREE_VEC_ELT (saved_parmlist, nparms) = parm; + --processing_template_parmlist; + return saved_parmlist; } @@ -2858,9 +2870,10 @@ lookup_template_class (d1, arglist, in_decl, context) { if (context) push_decl_namespace (context); - template = - maybe_get_template_decl_from_type_decl - (IDENTIFIER_CLASS_VALUE (d1)); + if (current_class_type != NULL_TREE) + template = + maybe_get_template_decl_from_type_decl + (IDENTIFIER_CLASS_VALUE (d1)); if (template == NULL_TREE) template = lookup_name_nonclass (d1); if (context) @@ -3993,7 +4006,7 @@ innermost_args (args, is_spec) tree args; int is_spec; { - if (args != NULL_TREE && TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC) + if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args)) return TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1 - is_spec); return args; } @@ -4189,8 +4202,7 @@ tsubst (t, args, in_decl) { tree arg = NULL_TREE; - if (TREE_VEC_ELT (args, 0) != NULL_TREE - && TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC) + if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args)) { levels = TREE_VEC_LENGTH (args); if (level <= levels) @@ -4275,7 +4287,7 @@ tsubst (t, args, in_decl) break; case TEMPLATE_PARM_INDEX: - r = reduce_template_parm_level (t, TREE_TYPE (t), levels); + r = reduce_template_parm_level (t, type, levels); break; default: @@ -6220,14 +6232,14 @@ unify (tparms, targs, parm, arg, strict, explicit_mask) /* The PARM is not one we're trying to unify. Just check to see if it matches ARG. */ return (TREE_CODE (arg) == TREE_CODE (parm) - && cp_tree_equal (parm, arg)) ? 0 : 1; + && cp_tree_equal (parm, arg) > 0) ? 0 : 1; idx = TEMPLATE_PARM_IDX (parm); targ = TREE_VEC_ELT (targs, idx); if (targ) { - int i = cp_tree_equal (targ, arg); + int i = (cp_tree_equal (targ, arg) > 0); if (i == 1) return 0; else if (i == 0) @@ -7082,17 +7094,6 @@ instantiate_decl (d) lineno = DECL_SOURCE_LINE (d); input_filename = DECL_SOURCE_FILE (d); - /* We need to set up DECL_INITIAL regardless of pattern_defined if the - variable is a static const initialized in the class body. */ - if (TREE_CODE (d) == VAR_DECL - && ! DECL_INITIAL (d) && DECL_INITIAL (code_pattern)) - { - pushclass (DECL_CONTEXT (d), 2); - DECL_INITIAL (d) = tsubst_expr (DECL_INITIAL (code_pattern), args, - tmpl); - cp_finish_decl (d, DECL_INITIAL (d), NULL_TREE, 0, LOOKUP_NORMAL); - } - if (pattern_defined) { repo_template_used (d); @@ -7123,11 +7124,17 @@ instantiate_decl (d) && ! (TREE_CODE (d) == FUNCTION_DECL && DECL_INLINE (d))) goto out; - /* Defer all templates except inline functions used in another function. */ - if (! pattern_defined - || (! (TREE_CODE (d) == FUNCTION_DECL && DECL_INLINE (d) && nested) - && ! at_eof)) + if (TREE_CODE (d) == VAR_DECL + && DECL_INITIAL (d) == NULL_TREE + && DECL_INITIAL (code_pattern) != NULL_TREE) + /* We need to set up DECL_INITIAL regardless of pattern_defined if + the variable is a static const initialized in the class body. */; + else if (! pattern_defined + || (! (TREE_CODE (d) == FUNCTION_DECL && DECL_INLINE (d) && nested) + && ! at_eof)) { + /* Defer all templates except inline functions used in another + function. */ lineno = line; input_filename = file; diff --git a/gcc/cp/search.c b/gcc/cp/search.c index 1a779138f38..c0db0572ee5 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -969,8 +969,7 @@ compute_access (basetype_path, field) /* Fields coming from nested anonymous unions have their DECL_CLASS_CONTEXT slot set to the union type rather than the record type containing the anonymous union. */ - if (context && TREE_CODE (context) == UNION_TYPE - && ANON_AGGRNAME_P (TYPE_IDENTIFIER (context))) + if (context && ANON_UNION_TYPE_P (context)) context = TYPE_CONTEXT (context); /* Virtual function tables are never private. But we should know that diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 135bbd1f61b..63b2adc2f3b 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -2065,8 +2065,8 @@ build_component_ref (datum, component, basetype_path, protect) { tree context = DECL_FIELD_CONTEXT (field); tree base = context; - while (base != basetype && TYPE_NAME (base) - && ANON_AGGRNAME_P (TYPE_IDENTIFIER (base))) + while (!comptypes (base, basetype,1) && TYPE_NAME (base) + && ANON_UNION_TYPE_P (base)) { base = TYPE_CONTEXT (base); } @@ -2096,7 +2096,7 @@ build_component_ref (datum, component, basetype_path, protect) basetype = base; /* Handle things from anon unions here... */ - if (TYPE_NAME (context) && ANON_AGGRNAME_P (TYPE_IDENTIFIER (context))) + if (TYPE_NAME (context) && ANON_UNION_TYPE_P (context)) { tree subfield = lookup_anon_field (basetype, context); tree subdatum = build_component_ref (datum, subfield, diff --git a/gcc/testsuite/g++.old-deja/g++.other/typedef1.C b/gcc/testsuite/g++.old-deja/g++.other/typedef1.C new file mode 100644 index 00000000000..d44772932ed --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.other/typedef1.C @@ -0,0 +1,13 @@ +// Build don't link: + +typedef const struct { + int x; +} Test; + +void foo(Test); + +void foo(Test t) +{ + t.x = 0; // ERROR - assignment of read-only member + return; +} diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash5.C b/gcc/testsuite/g++.old-deja/g++.pt/crash5.C new file mode 100644 index 00000000000..786cdf2c902 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/crash5.C @@ -0,0 +1,12 @@ +// Build don't link: + +template +struct K { + void f(); +}; + +template +void +K::f() +{ // ERROR - template parameters +} diff --git a/gcc/testsuite/g++.old-deja/g++.pt/memtemp75.C b/gcc/testsuite/g++.old-deja/g++.pt/memtemp75.C new file mode 100644 index 00000000000..4ff38b6c04c --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/memtemp75.C @@ -0,0 +1,25 @@ +// Build don't link: + +void +print(const int& i) +{ +} + +template +class bar +{ +public: + template + void doit(const A& a) + { + B(a); + } +}; + + +int +main() +{ + bar b; + b.template doit(2); +} diff --git a/gcc/testsuite/g++.old-deja/g++.pt/spec18.C b/gcc/testsuite/g++.old-deja/g++.pt/spec18.C new file mode 100644 index 00000000000..d7d034d6f7f --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/spec18.C @@ -0,0 +1,30 @@ +// Build don't link: + +template +void foo(const A& a, const B& b) +{ +} + +template +void foo(const A& a, const int& b) +{ +} + +template +void foo(const A*& a, const B& b) +{ +} + +template<> +void foo(const int&, const double&) +{ +} + + +int +main() +{ + foo("98239", 23); + foo(232, 1.022); +} + diff --git a/gcc/testsuite/g++.old-deja/g++.pt/static2.C b/gcc/testsuite/g++.old-deja/g++.pt/static2.C new file mode 100644 index 00000000000..5060cfdfb9e --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/static2.C @@ -0,0 +1,21 @@ +// Build don't link: + +template +class TEST +{ +public: + TEST (A) {} +}; + +template +class TEST2 +{ + static A i; +}; + +template +A TEST2 ::i (0); + +TEST2 > a; + +template class TEST2 >;