diff options
Diffstat (limited to 'gcc/cp/pt.c')
-rw-r--r-- | gcc/cp/pt.c | 863 |
1 files changed, 772 insertions, 91 deletions
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index c3bafd3..1b64174 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -78,6 +78,23 @@ static GTY(()) tree saved_access_scope; to the EXPR_STMT that is its result. */ static tree cur_stmt_expr; +// -------------------------------------------------------------------------- // +// Local Specialization Stack +// +// Implementation of the RAII helper for creating new local +// specializations. +local_specialization_stack::local_specialization_stack () + : saved (local_specializations) +{ + local_specializations = new hash_map<tree, tree>; +} + +local_specialization_stack::~local_specialization_stack () +{ + delete local_specializations; + local_specializations = saved; +} + /* True if we've recursed into fn_type_unification too many times. */ static bool excessive_deduction_depth; @@ -156,8 +173,6 @@ static tree expand_template_argument_pack (tree); static tree build_template_parm_index (int, int, int, tree, tree); static bool inline_needs_template_parms (tree, bool); static void push_inline_template_parms_recursive (tree, int); -static tree retrieve_local_specialization (tree); -static void register_local_specialization (tree, tree); static tree reduce_template_parm_level (tree, tree, int, tree, tsubst_flags_t); static int mark_template_parm (tree, void *); static int template_parm_this_level_p (tree, void *); @@ -196,17 +211,13 @@ static int invalid_nontype_parm_type_p (tree, tsubst_flags_t); static bool dependent_template_arg_p (tree); static bool any_template_arguments_need_structural_equality_p (tree); static bool dependent_type_p_r (tree); -static tree tsubst_expr (tree, tree, tsubst_flags_t, tree, bool); static tree tsubst_copy (tree, tree, tsubst_flags_t, tree); -static tree tsubst_pack_expansion (tree, tree, tsubst_flags_t, tree); static tree tsubst_decl (tree, tree, tsubst_flags_t); static void perform_typedefs_access_check (tree tmpl, tree targs); static void append_type_to_template_for_access_check_1 (tree, tree, tree, location_t); static tree listify (tree); static tree listify_autos (tree, tree); -static tree template_parm_to_arg (tree t); -static tree current_template_args (void); static tree tsubst_template_parm (tree, tree, tsubst_flags_t); static tree instantiate_alias_template (tree, tree, tsubst_flags_t); static bool complex_alias_template_p (const_tree tmpl); @@ -818,6 +829,98 @@ check_explicit_instantiation_namespace (tree spec) spec, current_namespace, ns); } +// Returns the type of a template specialization only if that +// specialization needs to be defined. Otherwise (e.g., if the type has +// already been defined), the function returns NULL_TREE. +static tree +maybe_new_partial_specialization (tree type) +{ + // An implicit instantiation of an incomplete type implies + // the definition of a new class template. + // + // template<typename T> + // struct S; + // + // template<typename T> + // struct S<T*>; + // + // Here, S<T*> is an implicit instantiation of S whose type + // is incomplete. + if (CLASSTYPE_IMPLICIT_INSTANTIATION (type) && !COMPLETE_TYPE_P (type)) + return type; + + // It can also be the case that TYPE is a completed specialization. + // Continuing the previous example, suppose we also declare: + // + // template<typename T> + // requires Integral<T> + // struct S<T*>; + // + // Here, S<T*> refers to the specialization S<T*> defined + // above. However, we need to differentiate definitions because + // we intend to define a new partial specialization. In this case, + // we rely on the fact that the constraints are different for + // this declaration than that above. + // + // Note that we also get here for injected class names and + // late-parsed template definitions. We must ensure that we + // do not create new type declarations for those cases. + if (flag_concepts && CLASSTYPE_TEMPLATE_SPECIALIZATION (type)) + { + tree tmpl = CLASSTYPE_TI_TEMPLATE (type); + tree args = CLASSTYPE_TI_ARGS (type); + + // If there are no template parameters, this cannot be a new + // partial template specializtion? + if (!current_template_parms) + return NULL_TREE; + + // If the constraints are not the same as those of the primary + // then, we can probably create a new specialization. + tree type_constr = current_template_constraints (); + + if (type == TREE_TYPE (tmpl)) + if (tree main_constr = get_constraints (tmpl)) + if (equivalent_constraints (type_constr, main_constr)) + return NULL_TREE; + + // Also, if there's a pre-existing specialization with matching + // constraints, then this also isn't new. + tree specs = DECL_TEMPLATE_SPECIALIZATIONS (tmpl); + while (specs) + { + tree spec_tmpl = TREE_VALUE (specs); + tree spec_args = TREE_PURPOSE (specs); + tree spec_constr = get_constraints (spec_tmpl); + if (comp_template_args (args, spec_args) + && equivalent_constraints (type_constr, spec_constr)) + return NULL_TREE; + specs = TREE_CHAIN (specs); + } + + // Create a new type node (and corresponding type decl) + // for the newly declared specialization. + tree t = make_class_type (TREE_CODE (type)); + CLASSTYPE_DECLARED_CLASS (t) = CLASSTYPE_DECLARED_CLASS (type); + TYPE_FOR_JAVA (t) = TYPE_FOR_JAVA (type); + SET_TYPE_TEMPLATE_INFO (t, build_template_info (tmpl, args)); + + /* We only need a separate type node for storing the definition of this + partial specialization; uses of S<T*> are unconstrained, so all are + equivalent. So keep TYPE_CANONICAL the same. */ + TYPE_CANONICAL (t) = TYPE_CANONICAL (type); + + // Build the corresponding type decl. + tree d = create_implicit_typedef (DECL_NAME (tmpl), t); + DECL_CONTEXT (d) = TYPE_CONTEXT (t); + DECL_SOURCE_LOCATION (d) = input_location; + + return t; + } + + return NULL_TREE; +} + /* The TYPE is being declared. If it is a template type, that means it is a partial specialization. Do appropriate error-checking. */ @@ -866,19 +969,19 @@ maybe_process_partial_specialization (tree type) Make sure that `C<int>' and `C<T*>' are implicit instantiations. */ - if (CLASSTYPE_IMPLICIT_INSTANTIATION (type) - && !COMPLETE_TYPE_P (type)) + if (tree t = maybe_new_partial_specialization (type)) { - if (!check_specialization_namespace (CLASSTYPE_TI_TEMPLATE (type)) + if (!check_specialization_namespace (CLASSTYPE_TI_TEMPLATE (t)) && !at_namespace_scope_p ()) return error_mark_node; - SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (type); - DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type)) = input_location; + SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (t); + DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (t)) = input_location; if (processing_template_decl) { - if (push_template_decl (TYPE_MAIN_DECL (type)) - == error_mark_node) + tree decl = push_template_decl (TYPE_MAIN_DECL (t)); + if (decl == error_mark_node) return error_mark_node; + return TREE_TYPE (decl); } } else if (CLASSTYPE_TEMPLATE_INSTANTIATION (type)) @@ -1154,7 +1257,7 @@ retrieve_specialization (tree tmpl, tree args, hashval_t hash) /* Like retrieve_specialization, but for local declarations. */ -static tree +tree retrieve_local_specialization (tree tmpl) { if (local_specializations == NULL) @@ -1546,8 +1649,7 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend, return spec; } -/* Returns true iff two spec_entry nodes are equivalent. Only compares the - TMPL and ARGS members, ignores SPEC. */ +/* Returns true iff two spec_entry nodes are equivalent. */ int comparing_specializations; @@ -1559,6 +1661,16 @@ spec_hasher::equal (spec_entry *e1, spec_entry *e2) ++comparing_specializations; equal = (e1->tmpl == e2->tmpl && comp_template_args (e1->args, e2->args)); + if (equal && flag_concepts + && VAR_P (DECL_TEMPLATE_RESULT (e1->tmpl)) + && uses_template_parms (e1->args)) + { + /* Partial specializations of a variable template can be distinguished by + constraints. */ + tree c1 = e1->spec ? get_constraints (e1->spec) : NULL_TREE; + tree c2 = e2->spec ? get_constraints (e2->spec) : NULL_TREE; + equal = equivalent_constraints (c1, c2); + } --comparing_specializations; return equal; @@ -1785,7 +1897,7 @@ reregister_specialization (tree spec, tree tinfo, tree new_spec) /* Like register_specialization, but for local declarations. We are registering SPEC, an instantiation of TMPL. */ -static void +void register_local_specialization (tree spec, tree tmpl) { local_specializations->put (tmpl, spec); @@ -1863,6 +1975,52 @@ print_candidates (tree fns) gcc_assert (str == NULL); } +/* Get a (possibly) constrained template declaration for the + purpose of ordering candidates. */ +static tree +get_template_for_ordering (tree list) +{ + gcc_assert (TREE_CODE (list) == TREE_LIST); + tree f = TREE_VALUE (list); + if (tree ti = DECL_TEMPLATE_INFO (f)) + return TI_TEMPLATE (ti); + return f; +} + +/* Among candidates having the same signature, return the + most constrained or NULL_TREE if there is no best candidate. + If the signatures of candidates vary (e.g., template + specialization vs. member function), then there can be no + most constrained. + + Note that we don't compare constraints on the functions + themselves, but rather those of their templates. */ +static tree +most_constrained_function (tree candidates) +{ + // Try to find the best candidate in a first pass. + tree champ = candidates; + for (tree c = TREE_CHAIN (champ); c; c = TREE_CHAIN (c)) + { + int winner = more_constrained (get_template_for_ordering (champ), + get_template_for_ordering (c)); + if (winner == -1) + champ = c; // The candidate is more constrained + else if (winner == 0) + return NULL_TREE; // Neither is more constrained + } + + // Verify that the champ is better than previous candidates. + for (tree c = candidates; c != champ; c = TREE_CHAIN (c)) { + if (!more_constrained (get_template_for_ordering (champ), + get_template_for_ordering (c))) + return NULL_TREE; + } + + return champ; +} + + /* Returns the template (one of the functions given by TEMPLATE_ID) which can be specialized to match the indicated DECL with the explicit template args given in TEMPLATE_ID. The DECL may be @@ -1899,6 +2057,7 @@ determine_specialization (tree template_id, tree targs; tree explicit_targs; tree candidates = NULL_TREE; + /* A TREE_LIST of templates of which DECL may be a specialization. The TREE_VALUE of each node is a TEMPLATE_DECL. The corresponding TREE_PURPOSE is the set of template arguments that, @@ -1960,7 +2119,8 @@ determine_specialization (tree template_id, targs = coerce_template_parms (parms, explicit_targs, fns, tf_warning_or_error, /*req_all*/true, /*use_defarg*/true); - templates = tree_cons (targs, fns, templates); + if (targs != error_mark_node) + templates = tree_cons (targs, fns, templates); } else for (; fns; fns = OVL_NEXT (fns)) { @@ -2035,7 +2195,11 @@ determine_specialization (tree template_id, /* Function templates cannot be specializations; there are no partial specializations of functions. Therefore, if the type of DECL does not match FN, there is no - match. */ + match. + + Note that it should never be the case that we have both + candidates added here, and for regular member functions + below. */ if (tsk == tsk_template) { if (compparms (fn_arg_types, decl_arg_types)) @@ -2056,7 +2220,12 @@ determine_specialization (tree template_id, specialize TMPL will produce DECL. */ continue; - /* Make sure that the deduced arguments actually work. */ + /* Remove, from the set of candidates, all those functions + whose constraints are not satisfied. */ + if (flag_concepts && !constraints_satisfied_p (fn, targs)) + continue; + + // Then, try to form the new function type. insttype = tsubst (TREE_TYPE (fn), targs, tf_none, NULL_TREE); if (insttype == error_mark_node) continue; @@ -2114,10 +2283,17 @@ determine_specialization (tree template_id, && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) decl_arg_types = TREE_CHAIN (decl_arg_types); - if (compparms (TYPE_ARG_TYPES (TREE_TYPE (fn)), + if (!compparms (TYPE_ARG_TYPES (TREE_TYPE (fn)), decl_arg_types)) - /* They match! */ - candidates = tree_cons (NULL_TREE, fn, candidates); + continue; + + // If the deduced arguments do not satisfy the constraints, + // this is not a candidate. + if (flag_concepts && !constraints_satisfied_p (fn)) + continue; + + // Add the candidate. + candidates = tree_cons (NULL_TREE, fn, candidates); } } @@ -2162,6 +2338,19 @@ determine_specialization (tree template_id, } } + // Concepts allows multiple declarations of member functions + // with the same signature. Like above, we need to rely on + // on the partial ordering of those candidates to determine which + // is the best. + if (flag_concepts && candidates && TREE_CHAIN (candidates)) + { + if (tree cand = most_constrained_function (candidates)) + { + candidates = cand; + TREE_CHAIN (cand) = NULL_TREE; + } + } + if (templates == NULL_TREE && candidates == NULL_TREE) { error ("template-id %qD for %q+D does not match any template " @@ -2190,6 +2379,10 @@ determine_specialization (tree template_id, { tree fn = TREE_VALUE (candidates); *targs_out = copy_node (DECL_TI_ARGS (fn)); + + // Propagate the candidate's constraints to the declaration. + set_constraints (decl, get_constraints (fn)); + /* DECL is a re-declaration or partial instantiation of a template function. */ if (TREE_CODE (fn) == TEMPLATE_DECL) @@ -2448,6 +2641,7 @@ check_explicit_specialization (tree declarator, { int have_def = flags & 2; int is_friend = flags & 4; + bool is_concept = flags & 8; int specialization = 0; int explicit_instantiation = 0; int member_specialization = 0; @@ -2523,6 +2717,9 @@ check_explicit_specialization (tree declarator, /* Fall through. */ case tsk_expl_spec: + if (is_concept) + error ("explicit specialization declared %<concept%>"); + if (VAR_P (decl) && TREE_CODE (declarator) != TEMPLATE_ID_EXPR) /* In cases like template<> constexpr bool v = true; We'll give an error in check_template_variable. */ @@ -2862,6 +3059,14 @@ check_explicit_specialization (tree declarator, tree tmpl_func = DECL_TEMPLATE_RESULT (gen_tmpl); gcc_assert (TREE_CODE (tmpl_func) == FUNCTION_DECL); + /* A concept cannot be specialized. */ + if (DECL_DECLARED_CONCEPT_P (tmpl_func)) + { + error ("explicit specialization of function concept %qD", + gen_tmpl); + return error_mark_node; + } + /* This specialization has the same linkage and visibility as the function template it specializes. */ TREE_PUBLIC (decl) = TREE_PUBLIC (tmpl_func); @@ -2904,9 +3109,12 @@ check_explicit_specialization (tree declarator, else if (VAR_P (decl)) DECL_COMDAT (decl) = false; - /* Register this specialization so that we can find it - again. */ - decl = register_specialization (decl, gen_tmpl, targs, is_friend, 0); + /* If this is a full specialization, register it so that we can find + it again. Partial specializations will be registered in + process_partial_specialization. */ + if (!processing_template_decl) + decl = register_specialization (decl, gen_tmpl, targs, + is_friend, 0); /* A 'structor should already have clones. */ gcc_assert (decl == error_mark_node @@ -3789,11 +3997,11 @@ process_template_parm (tree list, location_t parm_loc, tree parm, bool is_non_type, bool is_parameter_pack) { tree decl = 0; - tree defval; int idx = 0; gcc_assert (TREE_CODE (parm) == TREE_LIST); - defval = TREE_PURPOSE (parm); + tree defval = TREE_PURPOSE (parm); + tree constr = TREE_TYPE (parm); if (list) { @@ -3890,8 +4098,19 @@ process_template_parm (tree list, location_t parm_loc, tree parm, } DECL_ARTIFICIAL (decl) = 1; SET_DECL_TEMPLATE_PARM_P (decl); + + /* Build requirements for the type/template parameter. + This must be done after SET_DECL_TEMPLATE_PARM_P or + process_template_parm could fail. */ + tree reqs = finish_shorthand_constraint (parm, constr); + pushdecl (decl); + + /* Build the parameter node linking the parameter declaration, + its default argument (if any), and its constraints (if any). */ parm = build_tree_list (defval, parm); + TEMPLATE_PARM_CONSTRAINTS (parm) = reqs; + return chainon (list, parm); } @@ -3926,6 +4145,16 @@ end_template_parm_list (tree parms) return saved_parmlist; } +// Explicitly indicate the end of the template parameter list. We assume +// that the current template parameters have been constructed and/or +// managed explicitly, as when creating new template template parameters +// from a shorthand constraint. +void +end_template_parm_list () +{ + --processing_template_parmlist; +} + /* end_template_decl is called after a template declaration is seen. */ void @@ -3948,7 +4177,7 @@ end_template_decl (void) functions. Note that If the TREE_LIST contains an error_mark node, the returned argument is error_mark_node. */ -static tree +tree template_parm_to_arg (tree t) { @@ -4109,10 +4338,10 @@ maybe_update_decl_type (tree orig_type, tree scope) } /* Return a TEMPLATE_DECL corresponding to DECL, using the indicated - template PARMS. If MEMBER_TEMPLATE_P is true, the new template is - a member template. Used by push_template_decl below. */ + template PARMS and constraints, CONSTR. If MEMBER_TEMPLATE_P is true, + the new template is a member template. */ -static tree +tree build_template_decl (tree decl, tree parms, bool member_template_p) { tree tmpl = build_lang_decl (TEMPLATE_DECL, DECL_NAME (decl), NULL_TREE); @@ -4193,6 +4422,13 @@ process_partial_specialization (tree decl) gcc_assert (current_template_parms); + /* A concept cannot be specialized. */ + if (flag_concepts && variable_concept_p (maintmpl)) + { + error ("specialization of variable concept %q#D", maintmpl); + return error_mark_node; + } + inner_parms = INNERMOST_TEMPLATE_PARMS (current_template_parms); ntparms = TREE_VEC_LENGTH (inner_parms); @@ -4266,9 +4502,19 @@ process_partial_specialization (tree decl) the implicit argument list of the primary template. */ tree main_args = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (maintmpl))); - if (comp_template_args (inner_args, INNERMOST_TEMPLATE_ARGS (main_args))) - error ("partial specialization %qD does not specialize " - "any template arguments", decl); + if (comp_template_args (inner_args, INNERMOST_TEMPLATE_ARGS (main_args)) + && (!flag_concepts + || !subsumes_constraints (current_template_constraints (), + get_constraints (maintmpl)))) + { + if (!flag_concepts) + error ("partial specialization %q+D does not specialize " + "any template arguments", decl); + else + error ("partial specialization %q+D does not specialize any " + "template arguments and is not more constrained than", decl); + inform (DECL_SOURCE_LOCATION (maintmpl), "primary template here"); + } /* A partial specialization that replaces multiple parameters of the primary template with a pack expansion is less specialized for those @@ -4411,6 +4657,7 @@ process_partial_specialization (tree decl) if (TREE_CODE (decl) == TYPE_DECL) gcc_assert (!COMPLETE_TYPE_P (type)); + // Build the template decl. tree tmpl = build_template_decl (decl, current_template_parms, DECL_MEMBER_TEMPLATE_P (maintmpl)); TREE_TYPE (tmpl) = type; @@ -4419,6 +4666,11 @@ process_partial_specialization (tree decl) DECL_TEMPLATE_INFO (tmpl) = build_template_info (maintmpl, specargs); DECL_PRIMARY_TEMPLATE (tmpl) = maintmpl; + if (VAR_P (decl)) + /* We didn't register this in check_explicit_specialization so we could + wait until the constraints were set. */ + decl = register_specialization (decl, maintmpl, specargs, false, 0); + DECL_TEMPLATE_SPECIALIZATIONS (maintmpl) = tree_cons (specargs, tmpl, DECL_TEMPLATE_SPECIALIZATIONS (maintmpl)); @@ -4965,7 +5217,8 @@ push_template_decl_real (tree decl, bool is_friend) class-type, we must be redeclaring it here. Make sure that the redeclaration is valid. */ redeclare_class_template (TREE_TYPE (decl), - current_template_parms); + current_template_parms, + current_template_constraints ()); /* We don't need to create a new TEMPLATE_DECL; just use the one we already had. */ tmpl = TYPE_TI_TEMPLATE (TREE_TYPE (decl)); @@ -5212,7 +5465,7 @@ add_inherited_template_parms (tree fn, tree inherited) template <class T> struct S {}; */ bool -redeclare_class_template (tree type, tree parms) +redeclare_class_template (tree type, tree parms, tree cons) { tree tmpl; tree tmpl_parms; @@ -5320,6 +5573,15 @@ redeclare_class_template (tree type, tree parms) } } + // Cannot redeclare a class template with a different set of constraints. + if (!equivalent_constraints (get_constraints (tmpl), cons)) + { + error_at (input_location, "redeclaration %q#D with different " + "constraints", tmpl); + inform (DECL_SOURCE_LOCATION (tmpl), + "original declaration appeared here"); + } + return true; } @@ -6622,6 +6884,51 @@ canonicalize_type_argument (tree arg, tsubst_flags_t complain) return canon; } +// A template declaration can be substituted for a constrained +// template template parameter only when the argument is more +// constrained than the parameter. +static bool +is_compatible_template_arg (tree parm, tree arg) +{ + tree parm_cons = get_constraints (parm); + + /* For now, allow constrained template template arguments + and unconstrained template template parameters. */ + if (parm_cons == NULL_TREE) + return true; + + tree arg_cons = get_constraints (arg); + + // If the template parameter is constrained, we need to rewrite its + // constraints in terms of the ARG's template parameters. This ensures + // that all of the template parameter types will have the same depth. + // + // Note that this is only valid when coerce_template_template_parm is + // true for the innermost template parameters of PARM and ARG. In other + // words, because coercion is successful, this conversion will be valid. + if (parm_cons) + { + tree args = template_parms_to_args (DECL_TEMPLATE_PARMS (arg)); + parm_cons = tsubst_constraint_info (parm_cons, + INNERMOST_TEMPLATE_ARGS (args), + tf_none, NULL_TREE); + if (parm_cons == error_mark_node) + return false; + } + + return subsumes (parm_cons, arg_cons); +} + +// Convert a placeholder argument into a binding to the original +// parameter. The original parameter is saved as the TREE_TYPE of +// ARG. +static inline tree +convert_wildcard_argument (tree parm, tree arg) +{ + TREE_TYPE (arg) = parm; + return arg; +} + /* Convert the indicated template ARG as necessary to match the indicated template PARM. Returns the converted ARG, or error_mark_node if the conversion was unsuccessful. Error and @@ -6644,6 +6951,10 @@ convert_template_argument (tree parm, if (parm == error_mark_node) return error_mark_node; + /* Trivially convert placeholders. */ + if (TREE_CODE (arg) == WILDCARD_DECL) + return convert_wildcard_argument (parm, arg); + if (TREE_CODE (arg) == TREE_LIST && TREE_CODE (TREE_VALUE (arg)) == OFFSET_REF) { @@ -6811,6 +7122,22 @@ convert_template_argument (tree parm, val = error_mark_node; } + + // Check that the constraints are compatible before allowing the + // substitution. + if (val != error_mark_node) + if (!is_compatible_template_arg (parm, arg)) + { + if (in_decl && (complain & tf_error)) + { + error ("constraint mismatch at argument %d in " + "template parameter list for %qD", + i + 1, in_decl); + inform (input_location, " expected %qD but got %qD", + parm, arg); + } + val = error_mark_node; + } } } else @@ -6948,6 +7275,16 @@ coerce_template_parameter_pack (tree parms, packed_args = make_tree_vec (TREE_VEC_LENGTH (packed_parms)); } + /* Check if we have a placeholder pack, which indicates we're + in the context of a introduction list. In that case we want + to match this pack to the single placeholder. */ + else if (arg_idx < nargs + && TREE_CODE (TREE_VEC_ELT (inner_args, arg_idx)) == WILDCARD_DECL + && WILDCARD_PACK_P (TREE_VEC_ELT (inner_args, arg_idx))) + { + nargs = arg_idx + 1; + packed_args = make_tree_vec (1); + } else packed_args = make_tree_vec (nargs - arg_idx); @@ -7133,7 +7470,9 @@ coerce_template_parms (tree parms, } /* We can't pass a pack expansion to a non-pack parameter of an alias template (DR 1430). */ - else if (in_decl && DECL_ALIAS_TEMPLATE_P (in_decl) + else if (in_decl + && (DECL_ALIAS_TEMPLATE_P (in_decl) + || concept_template_p (in_decl)) && variadic_args_p && nargs - variadic_args_p < nparms - variadic_p) { @@ -7147,8 +7486,14 @@ coerce_template_parms (tree parms, if (PACK_EXPANSION_P (arg) && !template_parameter_pack_p (parm)) { - error ("pack expansion argument for non-pack parameter " - "%qD of alias template %qD", parm, in_decl); + if (DECL_ALIAS_TEMPLATE_P (in_decl)) + error_at (location_of (arg), + "pack expansion argument for non-pack parameter " + "%qD of alias template %qD", parm, in_decl); + else + error_at (location_of (arg), + "pack expansion argument for non-pack parameter " + "%qD of concept %qD", parm, in_decl); inform (DECL_SOURCE_LOCATION (parm), "declared here"); goto found; } @@ -7318,6 +7663,30 @@ coerce_template_parms (tree parms, return new_inner_args; } +/* Convert all template arguments to their appropriate types, and + return a vector containing the innermost resulting template + arguments. If any error occurs, return error_mark_node. Error and + warning messages are not issued. + + Note that no function argument deduction is performed, and default + arguments are used to fill in unspecified arguments. */ +tree +coerce_template_parms (tree parms, tree args, tree in_decl) +{ + return coerce_template_parms (parms, args, in_decl, tf_none, true, true); +} + +/* Convert all template arguments to their appropriate type, and + instantiate default arguments as needed. This returns a vector + containing the innermost resulting template arguments, or + error_mark_node if unsuccessful. */ +tree +coerce_template_parms (tree parms, tree args, tree in_decl, + tsubst_flags_t complain) +{ + return coerce_template_parms (parms, args, in_decl, complain, true, true); +} + /* Like coerce_template_parms. If PARMS represents all template parameters levels, this function returns a vector of vectors representing all the resulting argument levels. Note that in this @@ -7887,6 +8256,22 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, if (entry) return entry->spec; + /* If the the template's constraints are not satisfied, + then we cannot form a valid type. + + Note that the check is deferred until after the hash + lookup. This prevents redundant checks on previously + instantiated specializations. */ + if (flag_concepts && !constraints_satisfied_p (gen_tmpl, arglist)) + { + if (complain & tf_error) + { + error ("template constraint failure"); + diagnose_constraints (input_location, gen_tmpl, arglist); + } + return error_mark_node; + } + is_dependent_type = uses_template_parms (arglist); /* If the deduced arguments are invalid, then the binding @@ -8130,6 +8515,7 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, : CLASSTYPE_TI_TEMPLATE (found); } + // Build template info for the new specialization. SET_TYPE_TEMPLATE_INFO (t, build_template_info (found, arglist)); elt.spec = t; @@ -8184,14 +8570,17 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context, return ret; } -/* Return a TEMPLATE_ID_EXPR for the given variable template and ARGLIST. - The type of the expression is the unknown_type_node since the - template-id could refer to an explicit or partial specialization. */ +/* Return a TEMPLATE_ID_EXPR for the given variable template and ARGLIST. */ tree lookup_template_variable (tree templ, tree arglist) { + /* The type of the expression is NULL_TREE since the template-id could refer + to an explicit or partial specialization. */ tree type = NULL_TREE; + if (flag_concepts && variable_concept_p (templ)) + /* Except that concepts are always bool. */ + type = boolean_type_node; return build2 (TEMPLATE_ID_EXPR, type, templ, arglist); } @@ -8201,8 +8590,14 @@ tree finish_template_variable (tree var, tsubst_flags_t complain) { tree templ = TREE_OPERAND (var, 0); - tree arglist = TREE_OPERAND (var, 1); + + /* We never want to return a VAR_DECL for a variable concept, since they + aren't instantiated. In a template, leave the TEMPLATE_ID_EXPR alone. */ + bool concept_p = flag_concepts && variable_concept_p (templ); + if (concept_p && processing_template_decl) + return var; + tree tmpl_args = DECL_TI_ARGS (DECL_TEMPLATE_RESULT (templ)); arglist = add_outermost_template_args (tmpl_args, arglist); @@ -8211,6 +8606,29 @@ finish_template_variable (tree var, tsubst_flags_t complain) /*req_all*/true, /*use_default*/true); + if (flag_concepts && !constraints_satisfied_p (templ, arglist)) + { + if (complain & tf_error) + { + error ("constraints for %qD not satisfied", templ); + diagnose_constraints (location_of (var), templ, arglist); + } + return error_mark_node; + } + + /* If a template-id refers to a specialization of a variable + concept, then the expression is true if and only if the + concept's constraints are satisfied by the given template + arguments. + + NOTE: This is an extension of Concepts Lite TS that + allows constraints to be used in expressions. */ + if (concept_p) + { + tree decl = DECL_TEMPLATE_RESULT (templ); + return evaluate_variable_concept (decl, arglist); + } + return instantiate_template (templ, arglist, complain); } @@ -9013,7 +9431,8 @@ tsubst_friend_class (tree friend_tmpl, tree args) saved_input_location = input_location; input_location = DECL_SOURCE_LOCATION (friend_tmpl); - redeclare_class_template (TREE_TYPE (tmpl), parms); + tree cons = get_constraints (tmpl); + redeclare_class_template (TREE_TYPE (tmpl), parms, cons); input_location = saved_input_location; } @@ -9831,7 +10250,7 @@ tsubst_template_arg (tree t, tree args, tsubst_flags_t complain, tree in_decl) instantiated from it at *SPEC_P, return a NONTYPE_ARGUMENT_PACK of them and set *SPEC_P to point at the next point in the list. */ -static tree +tree extract_fnparm_pack (tree tmpl_parm, tree *spec_p) { /* Collect all of the extra "packed" parameters into an @@ -10044,6 +10463,16 @@ gen_elem_of_pack_expansion_instantiation (tree pattern, /* Expanding a fixed parameter pack from coerce_template_parameter_pack. */ t = tsubst_decl (pattern, args, complain); + else if (pattern == error_mark_node) + t = error_mark_node; + else if (constraint_p (pattern)) + { + if (processing_template_decl) + t = tsubst_constraint (pattern, args, complain, in_decl); + else + t = (constraints_satisfied_p (pattern, args) + ? boolean_true_node : boolean_false_node); + } else if (!TYPE_P (pattern)) t = tsubst_expr (pattern, args, complain, in_decl, /*integral_constant_expression_p=*/false); @@ -10108,7 +10537,11 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, } if (TREE_CODE (parm_pack) == PARM_DECL) { - if (PACK_EXPANSION_LOCAL_P (t)) + /* We know we have correct local_specializations if this + expansion is at function scope, or if we're dealing with a + local parameter in a requires expression; for the latter, + tsubst_requires_expr set it up appropriately. */ + if (PACK_EXPANSION_LOCAL_P (t) || CONSTRAINT_VAR_P (parm_pack)) arg_pack = retrieve_local_specialization (parm_pack); else { @@ -10788,6 +11221,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) gcc_assert (DECL_LANG_SPECIFIC (r) != 0); DECL_CHAIN (r) = NULL_TREE; + // Build new template info linking to the original template decl. DECL_TEMPLATE_INFO (r) = build_template_info (t, args); if (TREE_CODE (decl) == TYPE_DECL @@ -11041,6 +11475,15 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) && !grok_op_properties (r, /*complain=*/false)) RETURN (error_mark_node); + /* When instantiating a constrained member, substitute + into the constraints to create a new constraint. */ + if (tree ci = get_constraints (t)) + if (member) + { + ci = tsubst_constraint_info (ci, argvec, complain, NULL_TREE); + set_constraints (r, ci); + } + /* Set up the DECL_TEMPLATE_INFO for R. There's no need to do this in the special friend case mentioned above where GEN_TMPL is NULL. */ @@ -12098,6 +12541,12 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) int levels; tree arg = NULL_TREE; + /* Early in template argument deduction substitution, we don't + want to reduce the level of 'auto', or it will be confused + with a normal template parm in subsequent deduction. */ + if (is_auto (t) && (complain & tf_partial)) + return t; + r = NULL_TREE; gcc_assert (TREE_VEC_LENGTH (args) > 0); @@ -12238,12 +12687,6 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) about the template parameter in question. */ return t; - /* Early in template argument deduction substitution, we don't - want to reduce the level of 'auto', or it will be confused - with a normal template parm in subsequent deduction. */ - if (is_auto (t) && (complain & tf_partial)) - return t; - /* If we get here, we must have been looking at a parm for a more deeply nested template. Make a new version of this template parameter, but with a lower level. */ @@ -12260,6 +12703,14 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) complain | (code == TEMPLATE_TYPE_PARM ? tf_ignore_bad_quals : 0)); } + else if (TREE_CODE (t) == TEMPLATE_TYPE_PARM + && PLACEHOLDER_TYPE_CONSTRAINTS (t) + && (r = (TEMPLATE_PARM_DESCENDANTS + (TEMPLATE_TYPE_PARM_INDEX (t)))) + && (r = TREE_TYPE (r)) + && !PLACEHOLDER_TYPE_CONSTRAINTS (r)) + /* Break infinite recursion when substituting the constraints + of a constrained placeholder. */; else { r = copy_type (t); @@ -12285,6 +12736,12 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) else TYPE_CANONICAL (r) = canonical_type_parameter (r); + /* Propagate constraints on placeholders. */ + if (TREE_CODE (t) == TEMPLATE_TYPE_PARM) + if (tree constr = PLACEHOLDER_TYPE_CONSTRAINTS (t)) + PLACEHOLDER_TYPE_CONSTRAINTS (r) + = tsubst_constraint (constr, args, complain, in_decl); + if (code == BOUND_TEMPLATE_TEMPLATE_PARM) { tree argvec = tsubst (TYPE_TI_ARGS (t), args, @@ -13934,7 +14391,7 @@ tsubst_omp_for_iterator (tree t, int i, tree declv, tree initv, /* Like tsubst_copy for expressions, etc. but also does semantic processing. */ -static tree +tree tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, bool integral_constant_expression_p) { @@ -15911,6 +16368,9 @@ tsubst_copy_and_build (tree t, complain)); } + case REQUIRES_EXPR: + RETURN (tsubst_requires_expr (t, args, complain, in_decl)); + default: /* Handle Objective-C++ constructs, if appropriate. */ { @@ -19194,6 +19654,16 @@ more_specialized_fn (tree pat1, tree pat2, int len) processing_template_decl--; + /* If both deductions succeed, the partial ordering selects the more + constrained template. */ + if (!lose1 && !lose2) + { + tree c1 = get_constraints (DECL_TEMPLATE_RESULT (pat1)); + tree c2 = get_constraints (DECL_TEMPLATE_RESULT (pat2)); + lose1 = !subsumes_constraints (c1, c2); + lose2 = !subsumes_constraints (c2, c1); + } + /* All things being equal, if the next argument is a pack expansion for one function but not for the other, prefer the non-variadic function. FIXME this is bogus; see c++/41958. */ @@ -19262,6 +19732,11 @@ more_specialized_partial_spec (tree tmpl, tree pat1, tree pat2) } --processing_template_decl; + /* If both deductions succeed, the partial ordering selects the more + constrained template. */ + if (!winner && any_deductions) + return more_constrained (tmpl1, tmpl2); + /* In the case of a tie where at least one of the templates has a parameter pack at the end, the template with the most non-packed parameters wins. */ @@ -19409,6 +19884,34 @@ get_partial_spec_bindings (tree tmpl, tree tparms, tree spec_args, tree args) return deduced_args; } +// Compare two function templates T1 and T2 by deducing bindings +// from one against the other. If both deductions succeed, compare +// constraints to see which is more constrained. +static int +more_specialized_inst (tree t1, tree t2) +{ + int fate = 0; + int count = 0; + + if (get_bindings (t1, DECL_TEMPLATE_RESULT (t2), NULL_TREE, true)) + { + --fate; + ++count; + } + + if (get_bindings (t2, DECL_TEMPLATE_RESULT (t1), NULL_TREE, true)) + { + ++fate; + ++count; + } + + // If both deductions succeed, then one may be more constrained. + if (count == 2 && fate == 0) + fate = more_constrained (t1, t2); + + return fate; +} + /* TEMPLATES is a TREE_LIST. Each TREE_VALUE is a TEMPLATE_DECL. Return the TREE_LIST node with the most specialized template, if any. If there is no most specialized template, the error_mark_node @@ -19430,18 +19933,7 @@ most_specialized_instantiation (tree templates) champ = templates; for (fn = TREE_CHAIN (templates); fn; fn = TREE_CHAIN (fn)) { - int fate = 0; - - if (get_bindings (TREE_VALUE (champ), - DECL_TEMPLATE_RESULT (TREE_VALUE (fn)), - NULL_TREE, /*check_ret=*/true)) - fate--; - - if (get_bindings (TREE_VALUE (fn), - DECL_TEMPLATE_RESULT (TREE_VALUE (champ)), - NULL_TREE, /*check_ret=*/true)) - fate++; - + int fate = more_specialized_inst (TREE_VALUE (champ), TREE_VALUE (fn)); if (fate == -1) champ = fn; else if (!fate) @@ -19458,17 +19950,13 @@ most_specialized_instantiation (tree templates) if (champ) /* Now verify that champ is better than everything earlier in the instantiation list. */ - for (fn = templates; fn != champ; fn = TREE_CHAIN (fn)) - if (get_bindings (TREE_VALUE (champ), - DECL_TEMPLATE_RESULT (TREE_VALUE (fn)), - NULL_TREE, /*check_ret=*/true) - || !get_bindings (TREE_VALUE (fn), - DECL_TEMPLATE_RESULT (TREE_VALUE (champ)), - NULL_TREE, /*check_ret=*/true)) - { - champ = NULL_TREE; - break; - } + for (fn = templates; fn != champ; fn = TREE_CHAIN (fn)) { + if (more_specialized_inst (TREE_VALUE (champ), TREE_VALUE (fn)) != 1) + { + champ = NULL_TREE; + break; + } + } processing_template_decl--; @@ -19629,8 +20117,15 @@ most_specialized_partial_spec (tree target, tsubst_flags_t complain) { if (outer_args) spec_args = add_to_template_args (outer_args, spec_args); - list = tree_cons (spec_args, TREE_VALUE (t), list); - TREE_TYPE (list) = TREE_TYPE (t); + + /* Keep the candidate only if the constraints are satisfied, + or if we're not compiling with concepts. */ + if (!flag_concepts + || constraints_satisfied_p (spec_tmpl, spec_args)) + { + list = tree_cons (spec_args, TREE_VALUE (t), list); + TREE_TYPE (list) = TREE_TYPE (t); + } } } @@ -20308,6 +20803,9 @@ instantiate_decl (tree d, int defer_ok, functions and static member variables. */ gcc_assert (VAR_OR_FUNCTION_DECL_P (d)); + /* A concept is never instantiated. */ + gcc_assert (!DECL_DECLARED_CONCEPT_P (d)); + /* Variables are never deferred; if instantiation is required, they are instantiated right away. That allows for better code in the case that an expression refers to the value of the variable -- @@ -21417,6 +21915,14 @@ value_dependent_expression_p (tree expression) || has_value_dependent_address (op)); } + case REQUIRES_EXPR: + /* Treat all requires-expressions as value-dependent so + we don't try to fold them. */ + return true; + + case TYPE_REQ: + return dependent_type_p (TREE_OPERAND (expression, 0)); + case CALL_EXPR: { tree fn = get_callee_fndecl (expression); @@ -21444,7 +21950,8 @@ value_dependent_expression_p (tree expression) case TEMPLATE_ID_EXPR: /* If a TEMPLATE_ID_EXPR involves a dependent name, it will be type-dependent. */ - return type_dependent_expression_p (expression); + return type_dependent_expression_p (expression) + || variable_concept_p (TREE_OPERAND (expression, 0)); case CONSTRUCTOR: { @@ -21516,7 +22023,9 @@ type_dependent_expression_p (tree expression) return false; /* An unresolved name is always dependent. */ - if (identifier_p (expression) || TREE_CODE (expression) == USING_DECL) + if (identifier_p (expression) + || TREE_CODE (expression) == USING_DECL + || TREE_CODE (expression) == WILDCARD_DECL) return true; /* Some expression forms are never type-dependent. */ @@ -21529,7 +22038,8 @@ type_dependent_expression_p (tree expression) || TREE_CODE (expression) == TYPEID_EXPR || TREE_CODE (expression) == DELETE_EXPR || TREE_CODE (expression) == VEC_DELETE_EXPR - || TREE_CODE (expression) == THROW_EXPR) + || TREE_CODE (expression) == THROW_EXPR + || TREE_CODE (expression) == REQUIRES_EXPR) return false; /* The types of these expressions depends only on the type to which @@ -21779,6 +22289,22 @@ instantiation_dependent_r (tree *tp, int *walk_subtrees, case BIND_EXPR: return *tp; + /* Treat requires-expressions as dependent. */ + case REQUIRES_EXPR: + return *tp; + + case CALL_EXPR: + /* Treat calls to function concepts as dependent. */ + if (function_concept_check_p (*tp)) + return *tp; + break; + + case TEMPLATE_ID_EXPR: + /* And variable concepts. */ + if (variable_concept_p (TREE_OPERAND (*tp, 0))) + return *tp; + break; + default: break; } @@ -22380,6 +22906,20 @@ listify_autos (tree type, tree auto_node) tree do_auto_deduction (tree type, tree init, tree auto_node) { + return do_auto_deduction (type, init, auto_node, + tf_warning_or_error, + adc_unspecified); +} + +/* Replace occurrences of 'auto' in TYPE with the appropriate type deduced + from INIT. AUTO_NODE is the TEMPLATE_TYPE_PARM used for 'auto' in TYPE. + The CONTEXT determines the context in which auto deduction is performed + and is used to control error diagnostics. */ + +tree +do_auto_deduction (tree type, tree init, tree auto_node, + tsubst_flags_t complain, auto_deduction_context context) +{ tree targs; if (init == error_mark_node) @@ -22402,11 +22942,14 @@ do_auto_deduction (tree type, tree init, tree auto_node) init = CONSTRUCTOR_ELT (init, 0)->value; else { - if (permerror (input_location, "direct-list-initialization of " - "%<auto%> requires exactly one element")) - inform (input_location, - "for deduction to %<std::initializer_list%>, use copy-" - "list-initialization (i.e. add %<=%> before the %<{%>)"); + if (complain & tf_warning_or_error) + { + if (permerror (input_location, "direct-list-initialization of " + "%<auto%> requires exactly one element")) + inform (input_location, + "for deduction to %<std::initializer_list%>, use copy-" + "list-initialization (i.e. add %<=%> before the %<{%>)"); + } type = listify_autos (type, auto_node); } } @@ -22422,7 +22965,8 @@ do_auto_deduction (tree type, tree init, tree auto_node) = finish_decltype_type (init, id, tf_warning_or_error); if (type != auto_node) { - error ("%qT as type rather than plain %<decltype(auto)%>", type); + if (complain & tf_error) + error ("%qT as type rather than plain %<decltype(auto)%>", type); return error_mark_node; } } @@ -22442,7 +22986,8 @@ do_auto_deduction (tree type, tree init, tree auto_node) if (processing_template_decl) /* Try again at instantiation time. */ return type; - if (type && type != error_mark_node) + if (type && type != error_mark_node + && (complain & tf_error)) /* If type is error_mark_node a diagnostic must have been emitted by now. Also, having a mention to '<type error>' in the diagnostic is not really useful to the user. */ @@ -22474,11 +23019,45 @@ do_auto_deduction (tree type, tree init, tree auto_node) auto_node, TREE_TYPE (auto_node), TREE_VEC_ELT (targs, 0)); return error_mark_node; } - TREE_TYPE (auto_node) = TREE_VEC_ELT (targs, 0); + if (context != adc_requirement) + TREE_TYPE (auto_node) = TREE_VEC_ELT (targs, 0); + + /* Check any placeholder constraints against the deduced type. */ + if (flag_concepts && !processing_template_decl) + if (tree constr = PLACEHOLDER_TYPE_CONSTRAINTS (auto_node)) + { + /* Use the deduced type to check the associated constraints. */ + if (!constraints_satisfied_p (constr, targs)) + { + if (complain & tf_warning_or_error) + { + switch (context) + { + case adc_unspecified: + error("placeholder constraints not satisfied"); + break; + case adc_variable_type: + error ("deduced initializer does not satisfy " + "placeholder constraints"); + break; + case adc_return_type: + error ("deduced return type does not satisfy " + "placeholder constraints"); + break; + case adc_requirement: + error ("deduced expression type does not saatisy " + "placeholder constraints"); + break; + } + diagnose_constraints (input_location, constr, targs); + } + return error_mark_node; + } + } if (processing_template_decl) targs = add_to_template_args (current_template_args (), targs); - return tsubst (type, targs, tf_warning_or_error, NULL_TREE); + return tsubst (type, targs, complain, NULL_TREE); } /* Substitutes LATE_RETURN_TYPE for 'auto' in TYPE and returns the @@ -22716,6 +23295,108 @@ convert_generic_types_to_packs (tree parm, int start_idx, int end_idx) return tsubst (parm, replacement, tf_none, NULL_TREE); } +/* Entries in the decl_constraint hash table. */ +struct GTY((for_user)) constr_entry +{ + tree decl; + tree ci; +}; + +/* Hashing function and equality for constraint entries. */ +struct constr_hasher : ggc_ptr_hash<constr_entry> +{ + static hashval_t hash (constr_entry *e) + { + return (hashval_t)DECL_UID (e->decl); + } + + static bool equal (constr_entry *e1, constr_entry *e2) + { + return e1->decl == e2->decl; + } +}; + +/* A mapping from declarations to constraint information. Note that + both templates and their underlying declarations are mapped to the + same constraint information. + + FIXME: This is defined in pt.c because garbage collection + code is not being generated for constraint.cc. */ + +static GTY (()) hash_table<constr_hasher> *decl_constraints; + +/* Returns true iff cinfo contains a valid set of constraints. + This is the case when the associated requirements have been + successfully decomposed into lists of atomic constraints. + That is, when the saved assumptions are not error_mark_node. */ + +bool +valid_constraints_p (tree cinfo) +{ + gcc_assert (cinfo); + return CI_ASSUMPTIONS (cinfo) != error_mark_node; +} + +/* Returns the template constraints of declaration T. If T is not + constrained, return NULL_TREE. Note that T must be non-null. */ + +tree +get_constraints (tree t) +{ + gcc_assert (DECL_P (t)); + if (TREE_CODE (t) == TEMPLATE_DECL) + t = DECL_TEMPLATE_RESULT (t); + constr_entry elt = { t, NULL_TREE }; + constr_entry* found = decl_constraints->find (&elt); + if (found) + return found->ci; + else + return NULL_TREE; +} + +/* Associate the given constraint information CI with the declaration + T. If T is a template, then the constraints are associated with + its underlying declaration. Don't build associations if CI is + NULL_TREE. */ + +void +set_constraints (tree t, tree ci) +{ + if (!ci) + return; + gcc_assert (t); + if (TREE_CODE (t) == TEMPLATE_DECL) + t = DECL_TEMPLATE_RESULT (t); + gcc_assert (!get_constraints (t)); + constr_entry elt = {t, ci}; + constr_entry** slot = decl_constraints->find_slot (&elt, INSERT); + constr_entry* entry = ggc_alloc<constr_entry> (); + *entry = elt; + *slot = entry; +} + +/* Remove the associated constraints of the declaration T. */ + +void +remove_constraints (tree t) +{ + gcc_assert (DECL_P (t)); + if (TREE_CODE (t) == TEMPLATE_DECL) + t = DECL_TEMPLATE_RESULT (t); + + constr_entry elt = {t, NULL_TREE}; + constr_entry** slot = decl_constraints->find_slot (&elt, NO_INSERT); + if (slot) + decl_constraints->clear_slot (slot); +} + +/* Set up the hash table for constraint association. */ + +void +init_constraint_processing (void) +{ + decl_constraints = hash_table<constr_hasher>::create_ggc(37); +} /* Set up the hash tables for template instantiations. */ |