On Tue, 3 Oct 2023, Jason Merrill wrote: > On 10/3/23 08:41, Patrick Palka wrote: > > On Mon, 2 Oct 2023, Patrick Palka wrote: > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look > > > OK for trunk? > > > > > > -- >8 -- > > > > > > 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 difference is that they handle many tree codes differently, but > > > much of the tree code handling in tsubst_copy appears to be dead code[1]. > > > This is because tsubst_copy only gets directly called in a few places > > > and mostly on id-expressions. The interesting exceptions 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 > > That's curious, since what that function does seems like name lookup; I > wouldn't think we would want to call it when tf_no_name_lookup.
Ah, that makes sense I think. > > > > and finally it dispatches to tsubst for type trees. > > And it looks like you fix the callers to avoid that? Yes, I'll make a note of that in the commit message. > > > > Thus tsubst_copy is (at this point) similar enough to > > > tsubst_copy_and_build > > > that it makes sense to merge the two functions, with the main difference > > > being the name lookup behavior[2]. So this patch merges tsubst_copy into > > > tsubst_copy_and_build via a new tsubst tf_no_name_lookup which controls > > > name lookup and resolution of a (top-level) id-expression. > > > > > > [1]: http://thrifty.mooo.com:8008/gcc-lcov/gcc/cp/pt.cc.gcov.html#17231 > > > [2]: I don't know the history of tsubst_copy but I would guess it was > > > added before we settled on using processing_template_decl to control > > > whether our AST building routines perform semantic checking and return > > > non-templated trees, and so we needed a separate tsubst routine that > > > avoids semantic checking and always returns a templated tree for e.g. > > > partial substitution. > > > > Oops, this is wrong -- tsubst_copy_and_build came after tsubst_copy, > > and was introduced as an optimization with the intent of getting rid > > of tsubst_copy eventually: > > https://gcc.gnu.org/pipermail/gcc-patches/2003-January/093659.html > > I wonder if we want to add a small tsubst_name wrapper to call > tsubst_copy_and_build with tf_no_name_lookup? Good idea, that'll complement tsubst_scope nicely. > > Can we also merge in tsubst_expr and use that name instead of the unwieldy > tsubst_copy_and_build? That'd be nice. Another idea would be to rename tsubst_expr to tsubst_stmt and make it disjoint from tsubst_copy_and_build, and then rename tsubst_copy_and_build to tsubst_expr, to draw a distinction between statement-like trees (the substitution of which typically has side effects like calling add_stmt) and expression-like trees (which don't usually have such side effects). I can work on that as a follow-up patch. Here's v2 which guards the call to maybe_dependent_member_ref and adds tsubst_name, bootstrapped and regtested on x86_64-pc-linux-gnu: -- >8 -- Subject: [PATCH] c++: merge tsubst_copy into tsubst_copy_and_build gcc/cp/ChangeLog: * cp-tree.h (enum tsubst_flags): Add tf_no_name_lookup. * pt.cc (tsubst_copy): (tsubst_pack_expansion): Use tsubst for substituting BASES_TYPE. (tsubst_decl) <case USING_DECL>: Use tsubst_name instead of tsubst_copy. (tsubst) <case TEMPLATE_TYPE_PARM>: Use tsubst_copy_and_build instead of tsubst_copy for substituting CLASS_PLACEHOLDER_TEMPLATE. <case TYPENAME_TYPE>: 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. <case IDENTIFIER_NODE>: Don't do name lookup if tf_no_name_lookup was set. <case TEMPLATE_ID_EXPR>: 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. <case BIT_NOT_EXPR>: Handle identifier and type operand (if tf_no_name_lookup was set). <case SCOPE_REF>: 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. <case SIZEOF_EXPR>: Handling of sizeof... copied from tsubst_copy. <case CALL_EXPR>: Use tsubst_name instead of tsubst_copy to substitute a TEMPLATE_ID_EXPR callee naming an unresolved template. <case COMPONENT_REF>: Likewise to substitute the member. <case FUNCTION_DECL>: Copied from tsubst_copy and merged with ... <case VAR_DECL, PARM_DECL>: ... these. Initial handling copied from tsubst_copy. Optimize local variable substitution by trying retrieve_local_specialization before checking uses_template_parms. <case CONST_DECL>: Copied from tsubst_copy. <case FIELD_DECL>: Likewise. <case NAMESPACE_DECL>: Likewise. <case OVERLOAD>: Likewise. <case TEMPLATE_DECL>: Likewise. <case TEMPLATE_PARM_INDEX>: Likewise. <case TYPE_DECL>: Likewise. <case CLEANUP_POINT_EXPR>: Likewise. <case OFFSET_REF>: Likewise. <case EXPR_PACK_EXPANSION>: Likewise. <case NONTYPE_ARGUMENT_PACK>: Likewise. <case *_CST>: Likewise. <case *_*_FOLD_EXPR>: Likewise. <case DEBUG_BEGIN_STMT>: Likewise. <case CO_AWAIT_EXPR>: Likewise. <case TRAIT_EXPR>: Use tsubst and tsubst_copy_and_build instead of tsubst_copy. <default>: Copied from tsubst_copy. (tsubst_initializer_list): Use tsubst and tsubst_copy_and_build instead of tsubst_copy. --- gcc/cp/cp-tree.h | 3 + gcc/cp/pt.cc | 1186 +++++++++++++++++----------------------------- 2 files changed, 445 insertions(+), 744 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8b9a7d58462..919eab34803 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5619,6 +5619,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 4400d429b6f..e801a224d1b 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,707 +17282,6 @@ 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. */ - -static tree -tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) -{ - 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); - - switch (code) - { - case PARM_DECL: - r = retrieve_local_specialization (t); - - if (r == NULL_TREE) - { - /* 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); - } - - 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 I> 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; - - case FIELD_DECL: - if (DECL_CONTEXT (t)) - { - tree ctx; - - 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; - } - } - - return t; - - 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)) - { - /* Local specialization will usually have been created when - we instantiated the DECL_EXPR_DECL. */ - r = retrieve_local_specialization (t); - if (!r) - { - /* 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; - } - } - else if (local_variable_p (t) - && uses_template_parms (DECL_CONTEXT (t))) - { - r = retrieve_local_specialization (t); - if (r == NULL_TREE) - { - /* 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 <template <class> class TT> struct C {}; - template <class T> struct D { - template <class U> struct E {}; - C<E> c; // #1 - }; - D<int> d; // #2 - - We are processing the template argument `E' in #1 for - the template instantiation #2. Originally, `E' is a - TEMPLATE_DECL with `D<T>' as its DECL_CONTEXT. Now we - have to substitute this with one having context `D<int>'. */ - - tree context = tsubst_aggr_type (DECL_CONTEXT (t), args, complain, - in_decl, /*entering_scope=*/true); - return lookup_field (context, DECL_NAME(t), 0, false); - } - else - /* Ordinary template template argument. */ - return t; - - case NON_LVALUE_EXPR: - case VIEW_CONVERT_EXPR: - { - /* Handle location wrappers by substituting the wrapped node - first, *then* reusing the resulting type. Doing the type - first ensures that we handle template parameters and - parameter pack expansions. */ - if (location_wrapper_p (t)) - { - tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, - complain, in_decl); - return maybe_wrap_with_location (op0, EXPR_LOCATION (t)); - } - tree op = TREE_OPERAND (t, 0); - /* force_paren_expr can also create a VIEW_CONVERT_EXPR. */ - if (code == VIEW_CONVERT_EXPR && REF_PARENTHESIZED_P (t)) - { - op = tsubst_copy (op, args, complain, in_decl); - op = build1 (code, TREE_TYPE (op), op); - REF_PARENTHESIZED_P (op) = true; - return op; - } - /* We shouldn't see any other uses of these in templates - (tsubst_copy_and_build handles C++20 tparm object wrappers). */ - gcc_unreachable (); - } - - case CAST_EXPR: - case REINTERPRET_CAST_EXPR: - case CONST_CAST_EXPR: - case STATIC_CAST_EXPR: - case DYNAMIC_CAST_EXPR: - case IMPLICIT_CONV_EXPR: - CASE_CONVERT: - { - tsubst_flags_t tcomplain = complain; - if (code == CAST_EXPR) - tcomplain |= tf_tst_ok; - tree type = tsubst (TREE_TYPE (t), args, tcomplain, in_decl); - tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl); - return build1 (code, type, op0); - } - - case BIT_CAST_EXPR: - { - tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); - tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl); - r = build_min (BIT_CAST_EXPR, type, op0); - SET_EXPR_LOCATION (r, EXPR_LOCATION (t)); - return r; - } - - case SIZEOF_EXPR: - if (PACK_EXPANSION_P (TREE_OPERAND (t, 0)) - || ARGUMENT_PACK_P (TREE_OPERAND (t, 0))) - { - tree expanded, op = TREE_OPERAND (t, 0); - int len = 0; - - if (SIZEOF_EXPR_TYPE_P (t)) - op = TREE_TYPE (op); - - ++cp_unevaluated_operand; - ++c_inhibit_evaluation_warnings; - /* We only want to compute the number of arguments. */ - if (PACK_EXPANSION_P (op)) - expanded = tsubst_pack_expansion (op, args, complain, in_decl); - else - expanded = tsubst_template_args (ARGUMENT_PACK_ARGS (op), - args, complain, in_decl); - --cp_unevaluated_operand; - --c_inhibit_evaluation_warnings; - - if (TREE_CODE (expanded) == TREE_VEC) - { - len = TREE_VEC_LENGTH (expanded); - /* Set TREE_USED for the benefit of -Wunused. */ - for (int i = 0; i < len; i++) - if (DECL_P (TREE_VEC_ELT (expanded, i))) - TREE_USED (TREE_VEC_ELT (expanded, i)) = true; - } - - if (expanded == error_mark_node) - return error_mark_node; - else if (PACK_EXPANSION_P (expanded) - || (TREE_CODE (expanded) == TREE_VEC - && pack_expansion_args_count (expanded))) - - { - if (PACK_EXPANSION_P (expanded)) - /* OK. */; - else if (TREE_VEC_LENGTH (expanded) == 1) - expanded = TREE_VEC_ELT (expanded, 0); - else - expanded = make_argument_pack (expanded); - - if (TYPE_P (expanded)) - return cxx_sizeof_or_alignof_type (input_location, - expanded, SIZEOF_EXPR, - false, - complain & tf_error); - else - return cxx_sizeof_or_alignof_expr (input_location, - expanded, SIZEOF_EXPR, - false, - complain & tf_error); - } - else - return build_int_cst (size_type_node, len); - } - if (SIZEOF_EXPR_TYPE_P (t)) - { - r = tsubst (TREE_TYPE (TREE_OPERAND (t, 0)), - args, complain, in_decl); - r = build1 (NOP_EXPR, r, error_mark_node); - r = build1 (SIZEOF_EXPR, - tsubst (TREE_TYPE (t), args, complain, in_decl), r); - SIZEOF_EXPR_TYPE_P (r) = 1; - return r; - } - /* Fall through */ - - case INDIRECT_REF: - case NEGATE_EXPR: - case TRUTH_NOT_EXPR: - case BIT_NOT_EXPR: - case ADDR_EXPR: - case UNARY_PLUS_EXPR: /* Unary + */ - case ALIGNOF_EXPR: - case AT_ENCODE_EXPR: - case ARROW_EXPR: - case THROW_EXPR: - case TYPEID_EXPR: - case REALPART_EXPR: - case IMAGPART_EXPR: - case PAREN_EXPR: - { - tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); - tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl); - r = build1_loc (EXPR_LOCATION (t), code, type, op0); - if (code == ALIGNOF_EXPR) - ALIGNOF_EXPR_STD_P (r) = ALIGNOF_EXPR_STD_P (t); - /* For addresses of immediate functions ensure we have EXPR_LOCATION - set for possible later diagnostics. */ - if (code == ADDR_EXPR - && EXPR_LOCATION (r) == UNKNOWN_LOCATION - && TREE_CODE (op0) == FUNCTION_DECL - && DECL_IMMEDIATE_FUNCTION_P (op0)) - SET_EXPR_LOCATION (r, input_location); - return r; - } - - case EXCESS_PRECISION_EXPR: - { - tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); - tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl); - if (TREE_CODE (op0) == EXCESS_PRECISION_EXPR) - { - gcc_checking_assert (same_type_p (type, TREE_TYPE (op0))); - return op0; - } - return build1_loc (EXPR_LOCATION (t), code, type, op0); - } - - case COMPONENT_REF: - { - tree object; - tree name; - - object = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl); - name = TREE_OPERAND (t, 1); - if (TREE_CODE (name) == BIT_NOT_EXPR) - { - name = tsubst_copy (TREE_OPERAND (name, 0), args, - complain, in_decl); - name = build1 (BIT_NOT_EXPR, NULL_TREE, name); - } - else if (TREE_CODE (name) == SCOPE_REF - && TREE_CODE (TREE_OPERAND (name, 1)) == BIT_NOT_EXPR) - { - tree base = tsubst_copy (TREE_OPERAND (name, 0), args, - complain, in_decl); - name = TREE_OPERAND (name, 1); - name = tsubst_copy (TREE_OPERAND (name, 0), args, - complain, in_decl); - name = build1 (BIT_NOT_EXPR, NULL_TREE, name); - name = build_qualified_name (/*type=*/NULL_TREE, - base, name, - /*template_p=*/false); - } - else if (BASELINK_P (name)) - name = tsubst_baselink (name, - non_reference (TREE_TYPE (object)), - args, complain, - in_decl); - else - name = tsubst_copy (name, args, complain, in_decl); - return build_nt (COMPONENT_REF, object, name, NULL_TREE); - } - - case PLUS_EXPR: - case MINUS_EXPR: - case MULT_EXPR: - case TRUNC_DIV_EXPR: - case CEIL_DIV_EXPR: - case FLOOR_DIV_EXPR: - case ROUND_DIV_EXPR: - case EXACT_DIV_EXPR: - case BIT_AND_EXPR: - case BIT_IOR_EXPR: - case BIT_XOR_EXPR: - case TRUNC_MOD_EXPR: - case FLOOR_MOD_EXPR: - case TRUTH_ANDIF_EXPR: - case TRUTH_ORIF_EXPR: - case TRUTH_AND_EXPR: - case TRUTH_OR_EXPR: - case RSHIFT_EXPR: - case LSHIFT_EXPR: - case EQ_EXPR: - case NE_EXPR: - case MAX_EXPR: - case MIN_EXPR: - case LE_EXPR: - case GE_EXPR: - case LT_EXPR: - case GT_EXPR: - case COMPOUND_EXPR: - case DOTSTAR_EXPR: - case MEMBER_REF: - case PREDECREMENT_EXPR: - case PREINCREMENT_EXPR: - case POSTDECREMENT_EXPR: - case POSTINCREMENT_EXPR: - { - tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl); - tree op1 = tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl); - return build_nt (code, op0, op1); - } - - case SCOPE_REF: - { - tree op0 = tsubst_scope (TREE_OPERAND (t, 0), args, complain, in_decl); - tree op1 = tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl); - return build_qualified_name (/*type=*/NULL_TREE, op0, op1, - QUALIFIED_NAME_IS_TEMPLATE (t)); - } - - case ARRAY_REF: - { - tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl); - tree op1 = tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl); - return build_nt (ARRAY_REF, op0, op1, NULL_TREE, NULL_TREE); - } - - case CALL_EXPR: - { - int n = VL_EXP_OPERAND_LENGTH (t); - tree result = build_vl_exp (CALL_EXPR, n); - int i; - for (i = 0; i < n; i++) - TREE_OPERAND (t, i) = tsubst_copy (TREE_OPERAND (t, i), args, - complain, in_decl); - return result; - } - - case COND_EXPR: - case MODOP_EXPR: - case PSEUDO_DTOR_EXPR: - case VEC_PERM_EXPR: - { - tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl); - tree op1 = tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl); - tree op2 = tsubst_copy (TREE_OPERAND (t, 2), args, complain, in_decl); - r = build_nt (code, op0, op1, op2); - copy_warning (r, t); - return r; - } - - case NEW_EXPR: - { - tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl); - tree op1 = tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl); - tree op2 = tsubst_copy (TREE_OPERAND (t, 2), args, complain, in_decl); - r = build_nt (code, op0, op1, op2); - NEW_EXPR_USE_GLOBAL (r) = NEW_EXPR_USE_GLOBAL (t); - return r; - } - - case DELETE_EXPR: - { - tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl); - tree op1 = tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl); - r = build_nt (code, op0, op1); - DELETE_EXPR_USE_GLOBAL (r) = DELETE_EXPR_USE_GLOBAL (t); - DELETE_EXPR_USE_VEC (r) = DELETE_EXPR_USE_VEC (t); - return r; - } - - case TEMPLATE_ID_EXPR: - { - /* Substituted template arguments */ - tree tmpl = TREE_OPERAND (t, 0); - tree targs = TREE_OPERAND (t, 1); - - tmpl = tsubst_copy (tmpl, args, complain, in_decl); - if (targs) - targs = tsubst_template_args (targs, args, complain, in_decl); - - if (variable_template_p (tmpl)) - return lookup_template_variable (tmpl, targs, complain); - else - return lookup_template_function (tmpl, targs); - } - - case TREE_LIST: - { - tree purpose, value, chain; - - if (t == void_list_node) - return t; - - purpose = TREE_PURPOSE (t); - if (purpose) - purpose = tsubst_copy (purpose, args, complain, in_decl); - value = TREE_VALUE (t); - if (value) - value = tsubst_copy (value, args, complain, in_decl); - chain = TREE_CHAIN (t); - if (chain && chain != void_type_node) - chain = tsubst_copy (chain, args, complain, in_decl); - if (purpose == TREE_PURPOSE (t) - && value == TREE_VALUE (t) - && chain == TREE_CHAIN (t)) - return t; - return tree_cons (purpose, value, chain); - } - - case TEMPLATE_PARM_INDEX: - case TYPE_DECL: - return tsubst (t, args, complain, in_decl); - - case USING_DECL: - t = DECL_NAME (t); - /* Fall through. */ - case IDENTIFIER_NODE: - if (IDENTIFIER_CONV_OP_P (t)) - { - tree new_type = tsubst (TREE_TYPE (t), args, complain, in_decl); - return make_conv_op_name (new_type); - } - else - return t; - - case CONSTRUCTOR: - /* This is handled by tsubst_copy_and_build. */ - gcc_unreachable (); - - case VA_ARG_EXPR: - { - tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl); - tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); - return build_x_va_arg (EXPR_LOCATION (t), op0, type); - } - - case CLEANUP_POINT_EXPR: - /* We shouldn't have built any of these during initial template - generation. Instead, they should be built during instantiation - in response to the saved STMT_IS_FULL_EXPR_P setting. */ - gcc_unreachable (); - - case OFFSET_REF: - { - tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); - tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl); - tree op1 = tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl); - r = build2 (code, type, op0, op1); - PTRMEM_OK_P (r) = PTRMEM_OK_P (t); - if (!mark_used (TREE_OPERAND (r, 1), complain) - && !(complain & tf_error)) - return error_mark_node; - return r; - } - - case EXPR_PACK_EXPANSION: - error ("invalid use of pack expansion expression"); - return error_mark_node; - - case NONTYPE_ARGUMENT_PACK: - error ("use %<...%> to expand argument pack"); - return error_mark_node; - - case VOID_CST: - gcc_checking_assert (t == void_node && VOID_TYPE_P (TREE_TYPE (t))); - return t; - - case INTEGER_CST: - case REAL_CST: - case COMPLEX_CST: - case VECTOR_CST: - { - /* Instantiate any typedefs in the type. */ - tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); - r = fold_convert (type, t); - gcc_assert (TREE_CODE (r) == code); - return r; - } - - case STRING_CST: - { - tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); - r = t; - if (type != TREE_TYPE (t)) - { - r = copy_node (t); - TREE_TYPE (r) = type; - } - return r; - } - - case PTRMEM_CST: - /* These can sometimes show up in a partial instantiation, but never - involve template parms. */ - gcc_assert (!uses_template_parms (t)); - return t; - - case UNARY_LEFT_FOLD_EXPR: - return tsubst_unary_left_fold (t, args, complain, in_decl); - case UNARY_RIGHT_FOLD_EXPR: - return tsubst_unary_right_fold (t, args, complain, in_decl); - case BINARY_LEFT_FOLD_EXPR: - return tsubst_binary_left_fold (t, args, complain, in_decl); - case BINARY_RIGHT_FOLD_EXPR: - return tsubst_binary_right_fold (t, args, complain, in_decl); - case PREDICT_EXPR: - return t; - - case DEBUG_BEGIN_STMT: - /* ??? There's no point in copying it for now, but maybe some - day it will contain more information, such as a pointer back - to the containing function, inlined copy or so. */ - return t; - - case CO_AWAIT_EXPR: - return tsubst_expr (t, args, complain, in_decl); - - default: - /* We shouldn't get here, but keep going if !flag_checking. */ - if (flag_checking) - gcc_unreachable (); - return t; - } -} - /* Helper function for tsubst_omp_clauses, used for instantiation of OMP_CLAUSE_DECL of clauses. */ @@ -20420,6 +19724,15 @@ tsubst_copy_and_build (tree t, tsubst_flags_t decltype_flag = (complain & tf_decltype); complain &= ~tf_decltype; + /* This flag only applies to id-expressions at the top level, and + controls resolution thereof. */ + tsubst_flags_t no_name_lookup_flag = (complain & tf_no_name_lookup); + complain &= ~tf_no_name_lookup; + + if (!no_name_lookup_flag) + if (tree d = maybe_dependent_member_ref (t, args, complain, in_decl)) + return d; + switch (TREE_CODE (t)) { case USING_DECL: @@ -20437,6 +19750,9 @@ tsubst_copy_and_build (tree t, t = make_conv_op_name (new_type); } + if (no_name_lookup_flag) + RETURN (t); + /* Look up the name. */ decl = lookup_name (t); @@ -20470,10 +19786,14 @@ tsubst_copy_and_build (tree t, case TEMPLATE_ID_EXPR: { tree object; - tree templ = tsubst_copy_and_build (TREE_OPERAND (t, 0), args, - complain, in_decl); + tree templ = TREE_OPERAND (t, 0); tree targs = TREE_OPERAND (t, 1); + if (no_name_lookup_flag) + templ = tsubst_name (templ, args, complain, in_decl); + else + templ = tsubst_copy_and_build (templ, args, complain, in_decl); + if (targs) targs = tsubst_template_args (targs, args, complain, in_decl); if (targs == error_mark_node) @@ -20505,6 +19825,9 @@ tsubst_copy_and_build (tree t, if (variable_template_p (templ)) { + if (no_name_lookup_flag) + RETURN (lookup_template_variable (templ, targs, complain)); + tree r = lookup_and_finish_template_variable (templ, targs, complain); r = convert_from_reference (r); @@ -20526,6 +19849,8 @@ tsubst_copy_and_build (tree t, if (object) RETURN (build3 (COMPONENT_REF, TREE_TYPE (tid), object, tid, NULL_TREE)); + else if (no_name_lookup_flag) + RETURN (tid); else if (identifier_p (templ)) { /* C++20 P0846: we can encounter an IDENTIFIER_NODE here when @@ -20659,10 +19984,22 @@ tsubst_copy_and_build (tree t, templated_operator_saved_lookups (t), complain|decltype_flag)); + case BIT_NOT_EXPR: + if (identifier_p (TREE_OPERAND (t, 0))) + { + gcc_checking_assert (no_name_lookup_flag); + RETURN (t); + } + else if (TYPE_P (TREE_OPERAND (t, 0))) + { + gcc_checking_assert (no_name_lookup_flag); + tree op0 = tsubst (TREE_OPERAND (t, 0), args, complain, in_decl); + RETURN (build_min_nt_loc (EXPR_LOCATION (t), BIT_NOT_EXPR, op0)); + } + /* Fall through. */ case PREDECREMENT_EXPR: case PREINCREMENT_EXPR: case NEGATE_EXPR: - case BIT_NOT_EXPR: case ABS_EXPR: case TRUTH_NOT_EXPR: case UNARY_PLUS_EXPR: /* Unary + */ @@ -20779,8 +20116,16 @@ tsubst_copy_and_build (tree t, } case SCOPE_REF: - RETURN (tsubst_qualified_id (t, args, complain, in_decl, /*done=*/true, - /*address_p=*/false)); + if (no_name_lookup_flag) + { + tree op0 = tsubst_scope (TREE_OPERAND (t, 0), args, complain, in_decl); + tree op1 = tsubst_name (TREE_OPERAND (t, 1), args, complain, in_decl); + RETURN (build_qualified_name (/*type=*/NULL_TREE, op0, op1, + QUALIFIED_NAME_IS_TEMPLATE (t))); + } + else + RETURN (tsubst_qualified_id (t, args, complain, in_decl, /*done=*/true, + /*address_p=*/false)); case BASELINK: RETURN (tsubst_baselink (t, current_nonlambda_class_type (), @@ -20817,7 +20162,61 @@ tsubst_copy_and_build (tree t, case SIZEOF_EXPR: if (PACK_EXPANSION_P (TREE_OPERAND (t, 0)) || ARGUMENT_PACK_P (TREE_OPERAND (t, 0))) - RETURN (tsubst_copy (t, args, complain, in_decl)); + { + tree expanded, op = TREE_OPERAND (t, 0); + int len = 0; + + if (SIZEOF_EXPR_TYPE_P (t)) + op = TREE_TYPE (op); + + ++cp_unevaluated_operand; + ++c_inhibit_evaluation_warnings; + /* We only want to compute the number of arguments. */ + if (PACK_EXPANSION_P (op)) + expanded = tsubst_pack_expansion (op, args, complain, in_decl); + else + expanded = tsubst_template_args (ARGUMENT_PACK_ARGS (op), + args, complain, in_decl); + --cp_unevaluated_operand; + --c_inhibit_evaluation_warnings; + + if (TREE_CODE (expanded) == TREE_VEC) + { + len = TREE_VEC_LENGTH (expanded); + /* Set TREE_USED for the benefit of -Wunused. */ + for (int i = 0; i < len; i++) + if (DECL_P (TREE_VEC_ELT (expanded, i))) + TREE_USED (TREE_VEC_ELT (expanded, i)) = true; + } + + if (expanded == error_mark_node) + RETURN (error_mark_node); + else if (PACK_EXPANSION_P (expanded) + || (TREE_CODE (expanded) == TREE_VEC + && pack_expansion_args_count (expanded))) + + { + if (PACK_EXPANSION_P (expanded)) + /* OK. */; + else if (TREE_VEC_LENGTH (expanded) == 1) + expanded = TREE_VEC_ELT (expanded, 0); + else + expanded = make_argument_pack (expanded); + + if (TYPE_P (expanded)) + RETURN (cxx_sizeof_or_alignof_type (input_location, + expanded, SIZEOF_EXPR, + false, + complain & tf_error)); + else + RETURN (cxx_sizeof_or_alignof_expr (input_location, + expanded, SIZEOF_EXPR, + false, + complain & tf_error)); + } + else + RETURN (build_int_cst (size_type_node, len)); + } /* Fall through */ case ALIGNOF_EXPR: @@ -21072,10 +20471,7 @@ tsubst_copy_and_build (tree t, qualified_p = false; if (TREE_CODE (function) == TEMPLATE_ID_EXPR) - /* Use tsubst_copy to substitute through the template arguments - of the template-id without performing unqualified lookup of - the template name. */ - function = tsubst_copy (function, args, complain, in_decl); + function = tsubst_name (function, args, complain, in_decl); } else { @@ -21473,7 +20869,7 @@ tsubst_copy_and_build (tree t, non_reference (TREE_TYPE (object)), args, complain, in_decl); else - member = tsubst_copy (member, args, complain, in_decl); + member = tsubst_name (member, args, complain, in_decl); if (member == error_mark_node) RETURN (error_mark_node); @@ -21682,29 +21078,321 @@ tsubst_copy_and_build (tree t, } } + case FUNCTION_DECL: + case PARM_DECL: case VAR_DECL: if (!args) RETURN (t); - /* Fall through */ + tree r; + if (VAR_OR_FUNCTION_DECL_P (t) + && DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t)) + r = tsubst_decl (t, args, complain); + else if (VAR_OR_FUNCTION_DECL_P (t) && DECL_LOCAL_DECL_P (t)) + { + /* Local specialization will usually have been created when + we instantiated the DECL_EXPR_DECL. */ + r = retrieve_local_specialization (t); + if (!r) + { + /* 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; + } + } + else if (local_variable_p (t) + && ((r = retrieve_local_specialization (t)) + || TREE_CODE (t) == PARM_DECL + || uses_template_parms (DECL_CONTEXT (t)))) + { + if (r == NULL_TREE && TREE_CODE (t) == PARM_DECL) + { + /* We get here for a use of 'this' in an NSDMI. */ + if (DECL_NAME (t) == this_identifier && current_class_ptr) + RETURN (current_class_ptr); - case PARM_DECL: + /* 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); + } + else if (r == NULL_TREE) + { + /* 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); + + if (!no_name_lookup_flag + && (TREE_CODE (t) == PARM_DECL || TREE_CODE (t) == VAR_DECL)) + { + /* ??? We're doing a subset of finish_id_expression here. */ + if (tree wrap = maybe_get_tls_wrapper_call (r)) + /* Replace an evaluated use of the thread_local variable with + a call to its wrapper. */ + r = wrap; + else if (outer_automatic_var_p (r)) + r = process_outer_var_ref (r, complain); + + if (!TYPE_REF_P (TREE_TYPE (t))) + /* If the original type was a reference, we'll be wrapped in + the appropriate INDIRECT_REF. */ + r = convert_from_reference (r); + } + RETURN (r); + + case CONST_DECL: { - tree r = tsubst_copy (t, args, complain, in_decl); - /* ??? We're doing a subset of finish_id_expression here. */ - if (tree wrap = maybe_get_tls_wrapper_call (r)) - /* Replace an evaluated use of the thread_local variable with - a call to its wrapper. */ - r = wrap; - else if (outer_automatic_var_p (r)) - r = process_outer_var_ref (r, complain); - - if (!TYPE_REF_P (TREE_TYPE (t))) - /* If the original type was a reference, we'll be wrapped in - the appropriate INDIRECT_REF. */ - r = convert_from_reference (r); + tree enum_type; + tree v; + + if (DECL_TEMPLATE_PARM_P (t)) + RETURN (RECUR (DECL_INITIAL (t))); + if (!uses_template_parms (DECL_CONTEXT (t))) + RETURN (t); + + /* Unfortunately, we cannot just call lookup_name here. + Consider: + + template <int I> 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); + } + + case FIELD_DECL: + if (DECL_CONTEXT (t)) + { + tree ctx; + + 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); + } + } + RETURN (t); + + case NAMESPACE_DECL: + case OVERLOAD: + RETURN (t); + + 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 <template <class> class TT> struct C {}; + template <class T> struct D { + template <class U> struct E {}; + C<E> c; // #1 + }; + D<int> d; // #2 + + We are processing the template argument `E' in #1 for + the template instantiation #2. Originally, `E' is a + TEMPLATE_DECL with `D<T>' as its DECL_CONTEXT. Now we + have to substitute this with one having context `D<int>'. */ + + tree context = tsubst_aggr_type (DECL_CONTEXT (t), args, complain, + in_decl, /*entering_scope=*/true); + RETURN (lookup_field (context, DECL_NAME(t), 0, false)); + } + else + /* Ordinary template template argument. */ + RETURN (t); + + case TEMPLATE_PARM_INDEX: + case TYPE_DECL: + RETURN (tsubst (t, args, complain, in_decl)); + + case CLEANUP_POINT_EXPR: + /* We shouldn't have built any of these during initial template + generation. Instead, they should be built during instantiation + in response to the saved STMT_IS_FULL_EXPR_P setting. */ + gcc_unreachable (); + + case OFFSET_REF: + { + tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); + tree op0 = RECUR (TREE_OPERAND (t, 0)); + tree op1 = RECUR (TREE_OPERAND (t, 1)); + r = build2 (OFFSET_REF, type, op0, op1); + PTRMEM_OK_P (r) = PTRMEM_OK_P (t); + if (!mark_used (TREE_OPERAND (r, 1), complain) + && !(complain & tf_error)) + RETURN (error_mark_node); + RETURN (r); + } + + case EXPR_PACK_EXPANSION: + error ("invalid use of pack expansion expression"); + RETURN (error_mark_node); + + case NONTYPE_ARGUMENT_PACK: + error ("use %<...%> to expand argument pack"); + RETURN (error_mark_node); + + case VOID_CST: + gcc_checking_assert (t == void_node && VOID_TYPE_P (TREE_TYPE (t))); + RETURN (t); + + case INTEGER_CST: + case REAL_CST: + case COMPLEX_CST: + case VECTOR_CST: + { + /* Instantiate any typedefs in the type. */ + tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); + r = fold_convert (type, t); + gcc_assert (TREE_CODE (r) == TREE_CODE (t)); + RETURN (r); + } + + case STRING_CST: + { + tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); + r = t; + if (type != TREE_TYPE (t)) + { + r = copy_node (t); + TREE_TYPE (r) = type; + } RETURN (r); } + case PTRMEM_CST: + /* These can sometimes show up in a partial instantiation, but never + involve template parms. */ + gcc_assert (!uses_template_parms (t)); + RETURN (t); + + case UNARY_LEFT_FOLD_EXPR: + RETURN (tsubst_unary_left_fold (t, args, complain, in_decl)); + case UNARY_RIGHT_FOLD_EXPR: + RETURN (tsubst_unary_right_fold (t, args, complain, in_decl)); + case BINARY_LEFT_FOLD_EXPR: + RETURN (tsubst_binary_left_fold (t, args, complain, in_decl)); + case BINARY_RIGHT_FOLD_EXPR: + RETURN (tsubst_binary_right_fold (t, args, complain, in_decl)); + case PREDICT_EXPR: + RETURN (t); + + case DEBUG_BEGIN_STMT: + /* ??? There's no point in copying it for now, but maybe some + day it will contain more information, such as a pointer back + to the containing function, inlined copy or so. */ + RETURN (t); + + case CO_AWAIT_EXPR: + RETURN (tsubst_expr (t, args, complain, in_decl)); + case VA_ARG_EXPR: { tree op0 = RECUR (TREE_OPERAND (t, 0)); @@ -21728,8 +21416,11 @@ tsubst_copy_and_build (tree t, case TRAIT_EXPR: { - tree type1 = tsubst_copy (TRAIT_EXPR_TYPE1 (t), args, - complain, in_decl); + tree type1 = TRAIT_EXPR_TYPE1 (t); + if (TYPE_P (type1)) + type1 = tsubst (type1, args, complain, in_decl); + else + type1 = tsubst_copy_and_build (type1, args, complain, in_decl); tree type2 = tsubst (TRAIT_EXPR_TYPE2 (t), args, complain, in_decl); RETURN (finish_trait_expr (TRAIT_EXPR_LOCATION (t), @@ -21856,7 +21547,10 @@ tsubst_copy_and_build (tree t, if (subst) RETURN (subst); } - RETURN (tsubst_copy (t, args, complain, in_decl)); + /* We shouldn't get here, but keep going if !flag_checking. */ + if (flag_checking) + gcc_unreachable (); + RETURN (t); } #undef RECUR @@ -27580,8 +27274,12 @@ tsubst_initializer_list (tree t, tree argvec) else { tree tmp; - decl = tsubst_copy (TREE_PURPOSE (t), argvec, - tf_warning_or_error, NULL_TREE); + if (TYPE_P (TREE_PURPOSE (t))) + decl = tsubst (TREE_PURPOSE (t), argvec, + tf_warning_or_error, NULL_TREE); + else + decl = tsubst_copy_and_build (TREE_PURPOSE (t), argvec, + tf_warning_or_error, NULL_TREE); decl = expand_member_init (decl); if (decl && !DECL_P (decl)) -- 2.42.0.307.gd0e8084c65