From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1888) id 371703858D20; Fri, 20 Oct 2023 15:22:25 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 371703858D20 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1697815345; bh=KLQ6WMJ//gurPt5pciaQkPJfz3SDPH+u1QSTSC3M0Ss=; h=From:To:Subject:Date:From; b=Hqu+ZuRSzr4FB7a4/NjU/mhSc4WuDksa4zcYdKvJsOnGugAcWV1JZ2mcmXfphi4PL DbE7cC8GMxpWxLqA/yWNJYEM5OCKwF9IEbdOMsatGc1H/wNW4nvTXmhHpqKRzC/j99 nXLXM7Swc2ieDg50VM+fSQk2XlIRt7RLISfnyml8= MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Patrick Palka To: gcc-cvs@gcc.gnu.org Subject: [gcc r14-4796] c++: merge tsubst_copy into tsubst_copy_and_build X-Act-Checkin: gcc X-Git-Author: Patrick Palka X-Git-Refname: refs/heads/master X-Git-Oldrev: 909672f02ff75a6a94c88dee4aa41e92edb1d1ed X-Git-Newrev: 3e3d73ed5e85e7f467c366e9ad219d558ef9cb79 Message-Id: <20231020152225.371703858D20@sourceware.org> Date: Fri, 20 Oct 2023 15:22:25 +0000 (GMT) List-Id: https://gcc.gnu.org/g:3e3d73ed5e85e7f467c366e9ad219d558ef9cb79 commit r14-4796-g3e3d73ed5e85e7f467c366e9ad219d558ef9cb79 Author: Patrick Palka Date: Fri Oct 20 11:21:54 2023 -0400 c++: merge tsubst_copy into tsubst_copy_and_build The relationship between tsubst_copy_and_build and tsubst_copy (two of the main template argument substitution routines for expression trees) is rather hazy. The former is mostly a superset of the latter, with some differences. The main apparent difference is their handling of various tree codes, but much of the tree code handling in tsubst_copy appears to be dead code. This is because tsubst_copy mostly gets (directly) called on id-expressions rather than on arbitrary expressions. The interesting tree codes are PARM_DECL, VAR_DECL, BIT_NOT_EXPR, SCOPE_REF, TEMPLATE_ID_EXPR and IDENTIFIER_NODE: * for PARM_DECL and VAR_DECL, tsubst_copy_and_build calls tsubst_copy followed by doing some extra handling of its own * for BIT_NOT_EXPR tsubst_copy implicitly handles unresolved destructor calls (i.e. the first operand is an identifier or a type) * for SCOPE_REF, TEMPLATE_ID_EXPR and IDENTIFIER_NODE tsubst_copy refrains from doing name lookup of the terminal name Other more minor differences are that tsubst_copy exits early when 'args' is null, and it calls maybe_dependent_member_ref, and finally it dispatches to tsubst for type trees.[1] Thus tsubst_copy is similar enough to tsubst_copy_and_build that it makes sense to merge the two functions, with the main difference we want to preserve is tsubst_copy's lack of name lookup for id-expressions. This patch achieves this via a new tsubst flag tf_no_name_lookup which controls name lookup and resolution of a (top-level) id-expression. [1]: Exiting early for null 'args' doesn't seem right since it means we return templated trees even when !processing_template_decl. And dispatching to tsubst for type trees muddles the distinction between type and expressions which makes things less clear at the call site. So these properties of tsubst_copy don't seem worth preserving. N.B. the diff for this patch looks much cleaner when generated using the "patience diff" algorithm via Git's --patience flag. gcc/cp/ChangeLog: * cp-tree.h (enum tsubst_flags): Add tf_no_name_lookup. * pt.cc (tsubst_pack_expansion): Use tsubst for substituting BASES_TYPE. (tsubst_decl) : Use tsubst_name instead of tsubst_copy. (tsubst) : Use tsubst_copy_and_build instead of tsubst_copy for substituting CLASS_PLACEHOLDER_TEMPLATE. : Use tsubst_name instead of tsubst_copy for substituting TYPENAME_TYPE_FULLNAME. (tsubst_name): Define. (tsubst_qualified_id): Use tsubst_name instead of tsubst_copy for substituting the component name of a SCOPE_REF. (tsubst_copy): Remove. (tsubst_copy_and_build): Clear tf_no_name_lookup at the start, and remember if it was set. Call maybe_dependent_member_ref if tf_no_name_lookup was not set. : Don't do name lookup if tf_no_name_lookup was set. : If tf_no_name_lookup was set, use tsubst_name instead of tsubst_copy_and_build to substitute the template and don't finish the template-id. : Handle identifier and type operand (if tf_no_name_lookup was set). : Avoid trying to resolve a SCOPE_REF if tf_no_name_lookup was set by calling build_qualified_name directly instead of tsubst_qualified_id. : Handling of sizeof... copied from tsubst_copy. : Use tsubst_name instead of tsubst_copy to substitute a TEMPLATE_ID_EXPR callee naming an unresolved template. : Likewise to substitute the member. : Copied from tsubst_copy and merged with ... : ... these. Initial handling copied from tsubst_copy. Optimize local variable substitution by trying retrieve_local_specialization before checking uses_template_parms. : Copied from tsubst_copy. : Likewise. : Likewise. : Likewise. : Likewise. : Likewise. : Likewise. : Likewise. : Likewise. : Likewise. : Likewise. : Likewise. : Likewise. : Likewise. : Likewise. : Use tsubst and tsubst_copy_and_build instead of tsubst_copy. : Copied from tsubst_copy. (tsubst_initializer_list): Use tsubst and tsubst_copy_and_build instead of tsubst_copy. Reviewed-by: Jason Merrill Diff: --- gcc/cp/cp-tree.h | 3 + gcc/cp/pt.cc | 1750 ++++++++++++++++++++++-------------------------------- 2 files changed, 727 insertions(+), 1026 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index ff3323bf40c8..d6abd153930f 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5621,6 +5621,9 @@ enum tsubst_flags { tf_qualifying_scope = 1 << 14, /* Substituting the LHS of the :: operator. Affects TYPENAME_TYPE resolution from make_typename_type. */ + tf_no_name_lookup = 1 << 15, /* Don't look up the terminal name of an + outermost id-expression, or resolve its + constituent template-ids or qualified-ids. */ /* Convenient substitution flags combinations. */ tf_warning_or_error = tf_warning | tf_error }; diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index bd84054ae12d..65d637e4488e 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -204,9 +204,9 @@ static void copy_default_args_to_explicit_spec (tree); static bool invalid_nontype_parm_type_p (tree, tsubst_flags_t); static bool dependent_template_arg_p (tree); static bool dependent_type_p_r (tree); -static tree tsubst_copy (tree, tree, tsubst_flags_t, tree); static tree tsubst_decl (tree, tree, tsubst_flags_t, bool = true); static tree tsubst_scope (tree, tree, tsubst_flags_t, tree); +static tree tsubst_name (tree, tree, tsubst_flags_t, tree); static void perform_instantiation_time_access_checks (tree, tree); static tree listify (tree); static tree listify_autos (tree, tree); @@ -13373,15 +13373,11 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, if (TREE_CODE (parm_pack) == BASES) { gcc_assert (parm_pack == pattern); + tree type = tsubst (BASES_TYPE (parm_pack), args, complain, in_decl); if (BASES_DIRECT (parm_pack)) - return calculate_direct_bases (tsubst_expr (BASES_TYPE (parm_pack), - args, complain, - in_decl), - complain); + return calculate_direct_bases (type, complain); else - return calculate_bases (tsubst_expr (BASES_TYPE (parm_pack), - args, complain, in_decl), - complain); + return calculate_bases (type, complain); } else if (builtin_pack_call_p (parm_pack)) { @@ -15171,7 +15167,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain, variadic_p = true; } else - name = tsubst_copy (name, args, complain, in_decl); + name = tsubst_name (name, args, complain, in_decl); int len; if (!variadic_p) @@ -16108,7 +16104,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (template_placeholder_p (t)) { tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (t); - tmpl = tsubst_copy (tmpl, args, complain, in_decl); + tmpl = tsubst_copy_and_build (tmpl, args, complain, in_decl); if (TREE_CODE (tmpl) == TEMPLATE_TEMPLATE_PARM) tmpl = TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (tmpl); @@ -16592,7 +16588,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (ctx == error_mark_node) return error_mark_node; - tree f = tsubst_copy (TYPENAME_TYPE_FULLNAME (t), args, + tree f = tsubst_name (TYPENAME_TYPE_FULLNAME (t), args, complain, in_decl); if (f == error_mark_node) return error_mark_node; @@ -16780,6 +16776,15 @@ tsubst_scope (tree t, tree args, tsubst_flags_t complain, tree in_decl) return tsubst (t, args, complain | tf_qualifying_scope, in_decl); } +/* Convenience wrapper over tsubst for substituting into an id-expression + without resolving its terminal name. */ + +static tree +tsubst_name (tree t, tree args, tsubst_flags_t complain, tree in_decl) +{ + return tsubst_copy_and_build (t, args, complain | tf_no_name_lookup, in_decl); +} + /* OLDFNS is a lookup set of member functions from some class template, and NEWFNS is a lookup set of member functions from NEWTYPE, a specialization of that class template. Return the subset of NEWFNS which are @@ -17045,7 +17050,7 @@ tsubst_qualified_id (tree qualified_id, tree args, if (args) { scope = tsubst_scope (scope, args, complain, in_decl); - expr = tsubst_copy (name, args, complain, in_decl); + expr = tsubst_name (name, args, complain, in_decl); } else expr = name; @@ -17277,878 +17282,177 @@ maybe_dependent_member_ref (tree t, tree args, tsubst_flags_t complain, TREE_CODE (t) == TEMPLATE_DECL); } -/* Like tsubst, but deals with expressions. This function just replaces - template parms; to finish processing the resultant expression, use - tsubst_copy_and_build or tsubst_expr. */ +/* Helper function for tsubst_omp_clauses, used for instantiation of + OMP_CLAUSE_DECL of clauses. */ static tree -tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) +tsubst_omp_clause_decl (tree decl, tree args, tsubst_flags_t complain, + tree in_decl, tree *iterator_cache) { - enum tree_code code; - tree r; - - if (t == NULL_TREE || t == error_mark_node || args == NULL_TREE) - return t; - - if (TYPE_P (t)) - return tsubst (t, args, complain, in_decl); - - if (tree d = maybe_dependent_member_ref (t, args, complain, in_decl)) - return d; - - code = TREE_CODE (t); + if (decl == NULL_TREE || decl == ridpointers[RID_OMP_ALL_MEMORY]) + return decl; - switch (code) + /* Handle OpenMP iterators. */ + if (TREE_CODE (decl) == TREE_LIST + && TREE_PURPOSE (decl) + && TREE_CODE (TREE_PURPOSE (decl)) == TREE_VEC) { - case PARM_DECL: - r = retrieve_local_specialization (t); - - if (r == NULL_TREE) + tree ret; + if (iterator_cache[0] == TREE_PURPOSE (decl)) + ret = iterator_cache[1]; + else { - /* We get here for a use of 'this' in an NSDMI. */ - if (DECL_NAME (t) == this_identifier && current_class_ptr) - return current_class_ptr; - - /* This can happen for a parameter name used later in a function - declaration (such as in a late-specified return type). Just - make a dummy decl, since it's only used for its type. */ - gcc_assert (cp_unevaluated_operand); - r = tsubst_decl (t, args, complain); - /* Give it the template pattern as its context; its true context - hasn't been instantiated yet and this is good enough for - mangling. */ - DECL_CONTEXT (r) = DECL_CONTEXT (t); + tree *tp = &ret; + begin_scope (sk_omp, NULL); + for (tree it = TREE_PURPOSE (decl); it; it = TREE_CHAIN (it)) + { + *tp = copy_node (it); + TREE_VEC_ELT (*tp, 0) + = tsubst_decl (TREE_VEC_ELT (it, 0), args, complain); + DECL_CONTEXT (TREE_VEC_ELT (*tp, 0)) = current_function_decl; + pushdecl (TREE_VEC_ELT (*tp, 0)); + TREE_VEC_ELT (*tp, 1) + = tsubst_expr (TREE_VEC_ELT (it, 1), args, complain, in_decl); + TREE_VEC_ELT (*tp, 2) + = tsubst_expr (TREE_VEC_ELT (it, 2), args, complain, in_decl); + TREE_VEC_ELT (*tp, 3) + = tsubst_expr (TREE_VEC_ELT (it, 3), args, complain, in_decl); + TREE_CHAIN (*tp) = NULL_TREE; + tp = &TREE_CHAIN (*tp); + } + TREE_VEC_ELT (ret, 5) = poplevel (1, 1, 0); + iterator_cache[0] = TREE_PURPOSE (decl); + iterator_cache[1] = ret; } + return build_tree_list (ret, tsubst_omp_clause_decl (TREE_VALUE (decl), + args, complain, + in_decl, NULL)); + } - if (TREE_CODE (r) == ARGUMENT_PACK_SELECT) - r = argument_pack_select_arg (r); - if (!mark_used (r, complain) && !(complain & tf_error)) - return error_mark_node; - return r; - - case CONST_DECL: - { - tree enum_type; - tree v; - - if (DECL_TEMPLATE_PARM_P (t)) - return tsubst_copy (DECL_INITIAL (t), args, complain, in_decl); - if (!uses_template_parms (DECL_CONTEXT (t))) - 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 (DECL_CONTEXT (t), args, complain, 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. */ - gcc_unreachable (); - } - return t; + /* Handle an OpenMP array section represented as a TREE_LIST (or + OMP_CLAUSE_DOACROSS_KIND). An OMP_CLAUSE_DOACROSS (with a depend + kind of OMP_CLAUSE_DOACROSS_SINK) can also be represented as a + TREE_LIST. We can handle it exactly the same as an array section + (purpose, value, and a chain), even though the nomenclature + (low_bound, length, etc) is different. */ + if (TREE_CODE (decl) == TREE_LIST) + { + tree low_bound + = tsubst_expr (TREE_PURPOSE (decl), args, complain, in_decl); + tree length = tsubst_expr (TREE_VALUE (decl), args, complain, in_decl); + tree chain = tsubst_omp_clause_decl (TREE_CHAIN (decl), args, complain, + in_decl, NULL); + if (TREE_PURPOSE (decl) == low_bound + && TREE_VALUE (decl) == length + && TREE_CHAIN (decl) == chain) + return decl; + tree ret = tree_cons (low_bound, length, chain); + OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (ret) + = OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (decl); + return ret; + } + tree ret = tsubst_expr (decl, args, complain, in_decl); + /* Undo convert_from_reference tsubst_expr could have called. */ + if (decl + && REFERENCE_REF_P (ret) + && !REFERENCE_REF_P (decl)) + ret = TREE_OPERAND (ret, 0); + return ret; +} - case FIELD_DECL: - if (DECL_CONTEXT (t)) - { - tree ctx; +/* Like tsubst_copy, but specifically for OpenMP clauses. */ - ctx = tsubst_aggr_type (DECL_CONTEXT (t), args, complain, in_decl, - /*entering_scope=*/1); - if (ctx != DECL_CONTEXT (t)) - { - tree r = lookup_field (ctx, DECL_NAME (t), 0, false); - if (!r) - { - if (complain & tf_error) - error ("using invalid field %qD", t); - return error_mark_node; - } - return r; - } - } +static tree +tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort, + tree args, tsubst_flags_t complain, tree in_decl) +{ + tree new_clauses = NULL_TREE, nc, oc; + tree linear_no_step = NULL_TREE; + tree iterator_cache[2] = { NULL_TREE, NULL_TREE }; - return t; + for (oc = clauses; oc ; oc = OMP_CLAUSE_CHAIN (oc)) + { + nc = copy_node (oc); + OMP_CLAUSE_CHAIN (nc) = new_clauses; + new_clauses = nc; - case VAR_DECL: - case FUNCTION_DECL: - if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t)) - r = tsubst (t, args, complain, in_decl); - else if (DECL_LOCAL_DECL_P (t)) + switch (OMP_CLAUSE_CODE (nc)) { - /* Local specialization will usually have been created when - we instantiated the DECL_EXPR_DECL. */ - r = retrieve_local_specialization (t); - if (!r) + case OMP_CLAUSE_LASTPRIVATE: + if (OMP_CLAUSE_LASTPRIVATE_STMT (oc)) { - /* We're in a generic lambda referencing a local extern - from an outer block-scope of a non-template. */ - gcc_checking_assert (LAMBDA_FUNCTION_P (current_function_decl)); - r = t; + OMP_CLAUSE_LASTPRIVATE_STMT (nc) = push_stmt_list (); + tsubst_expr (OMP_CLAUSE_LASTPRIVATE_STMT (oc), args, + complain, in_decl); + OMP_CLAUSE_LASTPRIVATE_STMT (nc) + = pop_stmt_list (OMP_CLAUSE_LASTPRIVATE_STMT (nc)); } - } - else if (local_variable_p (t) - && uses_template_parms (DECL_CONTEXT (t))) - { - r = retrieve_local_specialization (t); - if (r == NULL_TREE) + /* FALLTHRU */ + case OMP_CLAUSE_PRIVATE: + case OMP_CLAUSE_SHARED: + case OMP_CLAUSE_FIRSTPRIVATE: + case OMP_CLAUSE_COPYIN: + case OMP_CLAUSE_COPYPRIVATE: + case OMP_CLAUSE_UNIFORM: + case OMP_CLAUSE_DEPEND: + case OMP_CLAUSE_DOACROSS: + case OMP_CLAUSE_AFFINITY: + case OMP_CLAUSE_FROM: + case OMP_CLAUSE_TO: + case OMP_CLAUSE_MAP: + case OMP_CLAUSE__CACHE_: + case OMP_CLAUSE_NONTEMPORAL: + case OMP_CLAUSE_USE_DEVICE_PTR: + case OMP_CLAUSE_USE_DEVICE_ADDR: + case OMP_CLAUSE_IS_DEVICE_PTR: + case OMP_CLAUSE_HAS_DEVICE_ADDR: + case OMP_CLAUSE_INCLUSIVE: + case OMP_CLAUSE_EXCLUSIVE: + OMP_CLAUSE_DECL (nc) + = tsubst_omp_clause_decl (OMP_CLAUSE_DECL (oc), args, complain, + in_decl, iterator_cache); + break; + case OMP_CLAUSE_NUM_TEAMS: + if (OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (oc)) + OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (nc) + = tsubst_expr (OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (oc), args, + complain, in_decl); + /* FALLTHRU */ + case OMP_CLAUSE_TILE: + case OMP_CLAUSE_IF: + case OMP_CLAUSE_NUM_THREADS: + case OMP_CLAUSE_SCHEDULE: + case OMP_CLAUSE_COLLAPSE: + case OMP_CLAUSE_FINAL: + case OMP_CLAUSE_DEVICE: + case OMP_CLAUSE_DIST_SCHEDULE: + case OMP_CLAUSE_THREAD_LIMIT: + case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_SIMDLEN: + case OMP_CLAUSE_NUM_TASKS: + case OMP_CLAUSE_GRAINSIZE: + case OMP_CLAUSE_PRIORITY: + case OMP_CLAUSE_ORDERED: + case OMP_CLAUSE_HINT: + case OMP_CLAUSE_FILTER: + case OMP_CLAUSE_NUM_GANGS: + case OMP_CLAUSE_NUM_WORKERS: + case OMP_CLAUSE_VECTOR_LENGTH: + case OMP_CLAUSE_WORKER: + case OMP_CLAUSE_VECTOR: + case OMP_CLAUSE_ASYNC: + case OMP_CLAUSE_WAIT: + case OMP_CLAUSE_DETACH: + OMP_CLAUSE_OPERAND (nc, 0) + = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain, in_decl); + break; + case OMP_CLAUSE_REDUCTION: + case OMP_CLAUSE_IN_REDUCTION: + case OMP_CLAUSE_TASK_REDUCTION: + if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (oc)) { - /* First try name lookup to find the instantiation. */ - r = lookup_name (DECL_NAME (t)); - if (r) - { - if (!VAR_P (r)) - { - /* During error-recovery we may find a non-variable, - even an OVERLOAD: just bail out and avoid ICEs and - duplicate diagnostics (c++/62207). */ - gcc_assert (seen_error ()); - return error_mark_node; - } - if (!is_capture_proxy (r)) - { - /* Make sure the one we found is the one we want. */ - tree ctx = enclosing_instantiation_of (DECL_CONTEXT (t)); - if (ctx != DECL_CONTEXT (r)) - r = NULL_TREE; - } - } - - if (r) - /* OK */; - else - { - /* This can happen for a variable used in a - late-specified return type of a local lambda, or for a - local static or constant. Building a new VAR_DECL - should be OK in all those cases. */ - r = tsubst_decl (t, args, complain); - if (local_specializations) - /* Avoid infinite recursion (79640). */ - register_local_specialization (r, t); - if (decl_maybe_constant_var_p (r)) - { - /* We can't call cp_finish_decl, so handle the - initializer by hand. */ - tree init = tsubst_init (DECL_INITIAL (t), r, args, - complain, in_decl); - if (!processing_template_decl) - init = maybe_constant_init (init); - if (processing_template_decl - ? potential_constant_expression (init) - : reduced_constant_expression_p (init)) - DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (r) - = TREE_CONSTANT (r) = true; - DECL_INITIAL (r) = init; - if (tree auto_node = type_uses_auto (TREE_TYPE (r))) - TREE_TYPE (r) - = do_auto_deduction (TREE_TYPE (r), init, auto_node, - complain, adc_variable_type); - } - gcc_assert (cp_unevaluated_operand - || processing_contract_condition - || TREE_STATIC (r) - || decl_constant_var_p (r) - || seen_error ()); - if (!processing_template_decl - && !TREE_STATIC (r)) - r = process_outer_var_ref (r, complain); - } - /* Remember this for subsequent uses. */ - if (local_specializations) - register_local_specialization (r, t); - } - if (TREE_CODE (r) == ARGUMENT_PACK_SELECT) - r = argument_pack_select_arg (r); - } - else - r = t; - if (!mark_used (r, complain)) - return error_mark_node; - return r; - - case NAMESPACE_DECL: - return t; - - case OVERLOAD: - return t; - - case BASELINK: - return tsubst_baselink (t, current_nonlambda_class_type (), - args, complain, in_decl); - - case TEMPLATE_DECL: - if (DECL_TEMPLATE_TEMPLATE_PARM_P (t)) - return tsubst (TREE_TYPE (DECL_TEMPLATE_RESULT (t)), - args, complain, in_decl); - else if (DECL_FUNCTION_TEMPLATE_P (t) && DECL_MEMBER_TEMPLATE_P (t)) - return tsubst (t, args, complain, in_decl); - else if (DECL_CLASS_SCOPE_P (t) - && uses_template_parms (DECL_CONTEXT (t))) - { - /* Template template argument like the following example need - special treatment: - - template