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, and finally > it dispatches to tsubst for type trees. > > 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 > > 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_copy_and_build with > tf_no_name_lookup 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_copy_and_build with > tf_no_name_lookup instead of tsubst_copy for substituting > TYPENAME_TYPE_FULLNAME. > (tsubst_qualified_id): Likewise 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. > <case IDENTIFIER_NODE>: Don't do name lookup if tf_no_name_lookup > was set. > <case TEMLPATE_ID_EXPR>: Don't finish a template-id if > tf_no_name_lookup was set. > <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 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_copy_and_build with > tf_no_name_lookup 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 | 1742 +++++++++++++++++++--------------------------- > 2 files changed, 719 insertions(+), 1026 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..e1fb20994e3 100644 > --- a/gcc/cp/pt.cc > +++ b/gcc/cp/pt.cc > @@ -204,7 +204,6 @@ 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 void perform_instantiation_time_access_checks (tree, tree); > @@ -13373,15 +13372,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 +15166,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t > complain, > variadic_p = true; > } > else > - name = tsubst_copy (name, args, complain, in_decl); > + name = tsubst_copy_and_build (name, args, > + complain | tf_no_name_lookup, > 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,8 +16588,8 @@ 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, > - complain, in_decl); > + tree f = tsubst_copy_and_build (TYPENAME_TYPE_FULLNAME (t), args, > + complain | tf_no_name_lookup, in_decl); > if (f == error_mark_node) > return error_mark_node; > > @@ -17045,7 +17041,8 @@ 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_copy_and_build (name, args, > + complain | tf_no_name_lookup, in_decl); > } > else > expr = name; > @@ -17277,878 +17274,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 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; > + /* 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 <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. */ > - > -static tree > -tsubst_omp_clause_decl (tree decl, tree args, tsubst_flags_t complain, > - tree in_decl, tree *iterator_cache) > -{ > - if (decl == NULL_TREE || decl == ridpointers[RID_OMP_ALL_MEMORY]) > - return decl; > - > - /* Handle OpenMP iterators. */ > - if (TREE_CODE (decl) == TREE_LIST > - && TREE_PURPOSE (decl) > - && TREE_CODE (TREE_PURPOSE (decl)) == TREE_VEC) > - { > - tree ret; > - if (iterator_cache[0] == TREE_PURPOSE (decl)) > - ret = iterator_cache[1]; > - else > - { > - 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)); > - } > - > - /* 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; > -} > - > -/* Like tsubst_copy, but specifically for OpenMP clauses. */ > - > -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 }; > - > - for (oc = clauses; oc ; oc = OMP_CLAUSE_CHAIN (oc)) > - { > - nc = copy_node (oc); > - OMP_CLAUSE_CHAIN (nc) = new_clauses; > - new_clauses = nc; > - > - switch (OMP_CLAUSE_CODE (nc)) > - { > - case OMP_CLAUSE_LASTPRIVATE: > - if (OMP_CLAUSE_LASTPRIVATE_STMT (oc)) > - { > - 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)); > - } > - /* 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)) > - { > - tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (oc); > - if (TREE_CODE (placeholder) == SCOPE_REF) > + tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (oc); > + if (TREE_CODE (placeholder) == SCOPE_REF) > { > tree scope = tsubst (TREE_OPERAND (placeholder, 0), args, > complain, in_decl); > @@ -20420,6 +19716,13 @@ 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. */ > + tsubst_flags_t no_name_lookup_flag = (complain & tf_no_name_lookup); > + complain &= ~tf_no_name_lookup; > + > + if (tree d = maybe_dependent_member_ref (t, args, complain, in_decl)) > + return d; > + > switch (TREE_CODE (t)) > { > case USING_DECL: > @@ -20437,6 +19740,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); > > @@ -20471,7 +19777,8 @@ tsubst_copy_and_build (tree t, > { > tree object; > tree templ = tsubst_copy_and_build (TREE_OPERAND (t, 0), args, > - complain, in_decl); > + complain | no_name_lookup_flag, > + in_decl); > tree targs = TREE_OPERAND (t, 1); > > if (targs) > @@ -20505,6 +19812,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 +19836,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 +19971,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 +20103,18 @@ 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_copy_and_build (TREE_OPERAND (t, 1), args, > + complain | no_name_lookup_flag, > + 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 (), > @@ -20798,26 +20132,80 @@ tsubst_copy_and_build (tree t, > tsubst_copy_and_build_call_args (c, args, complain, in_decl, > index_exp_list); > > - tree r; > - if (vec_safe_length (index_exp_list) == 1 > - && !PACK_EXPANSION_P (index_exp_list[0])) > - r = grok_array_decl (EXPR_LOCATION (t), op1, > - index_exp_list[0], NULL, > - complain | decltype_flag); > + tree r; > + if (vec_safe_length (index_exp_list) == 1 > + && !PACK_EXPANSION_P (index_exp_list[0])) > + r = grok_array_decl (EXPR_LOCATION (t), op1, > + index_exp_list[0], NULL, > + complain | decltype_flag); > + else > + r = grok_array_decl (EXPR_LOCATION (t), op1, > + NULL_TREE, &index_exp_list, > + complain | decltype_flag); > + RETURN (r); > + } > + RETURN (build_x_array_ref (EXPR_LOCATION (t), op1, > + RECUR (TREE_OPERAND (t, 1)), > + complain|decltype_flag)); > + > + 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 > - r = grok_array_decl (EXPR_LOCATION (t), op1, > - NULL_TREE, &index_exp_list, > - complain | decltype_flag); > - RETURN (r); > + RETURN (build_int_cst (size_type_node, len)); > } > - RETURN (build_x_array_ref (EXPR_LOCATION (t), op1, > - RECUR (TREE_OPERAND (t, 1)), > - complain|decltype_flag)); > - > - 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)); > /* Fall through */ > > case ALIGNOF_EXPR: > @@ -21072,10 +20460,9 @@ 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_copy_and_build (function, args, > + complain | tf_no_name_lookup, > + in_decl); > } > else > { > @@ -21473,7 +20860,8 @@ 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_copy_and_build (member, args, > + complain | tf_no_name_lookup, > in_decl); > if (member == error_mark_node) > RETURN (error_mark_node); > > @@ -21556,154 +20944,446 @@ tsubst_copy_and_build (tree t, > RETURN (error_mark_node); > } > > - r = finish_class_member_access_expr (object, member, > - /*template_p=*/false, > - complain); > - if (REF_PARENTHESIZED_P (t)) > - r = force_paren_expr (r); > - RETURN (r); > + r = finish_class_member_access_expr (object, member, > + /*template_p=*/false, > + complain); > + if (REF_PARENTHESIZED_P (t)) > + r = force_paren_expr (r); > + RETURN (r); > + } > + > + case THROW_EXPR: > + RETURN (build_throw > + (input_location, RECUR (TREE_OPERAND (t, 0)))); > + > + case CONSTRUCTOR: > + { > + vec<constructor_elt, va_gc> *n; > + constructor_elt *ce; > + unsigned HOST_WIDE_INT idx; > + bool process_index_p; > + int newlen; > + bool need_copy_p = false; > + tree r; > + > + tsubst_flags_t tcomplain = complain; > + if (COMPOUND_LITERAL_P (t)) > + tcomplain |= tf_tst_ok; > + tree type = tsubst (TREE_TYPE (t), args, tcomplain, in_decl); > + if (type == error_mark_node) > + RETURN (error_mark_node); > + > + /* We do not want to process the index of aggregate > + initializers as they are identifier nodes which will be > + looked up by digest_init. */ > + process_index_p = !(type && MAYBE_CLASS_TYPE_P (type)); > + > + if (null_member_pointer_value_p (t)) > + { > + gcc_assert (same_type_p (type, TREE_TYPE (t))); > + RETURN (t); > + } > + > + n = vec_safe_copy (CONSTRUCTOR_ELTS (t)); > + newlen = vec_safe_length (n); > + FOR_EACH_VEC_SAFE_ELT (n, idx, ce) > + { > + if (ce->index && process_index_p > + /* An identifier index is looked up in the type > + being initialized, not the current scope. */ > + && TREE_CODE (ce->index) != IDENTIFIER_NODE) > + ce->index = RECUR (ce->index); > + > + if (PACK_EXPANSION_P (ce->value)) > + { > + /* Substitute into the pack expansion. */ > + ce->value = tsubst_pack_expansion (ce->value, args, complain, > + in_decl); > + > + if (ce->value == error_mark_node > + || PACK_EXPANSION_P (ce->value)) > + ; > + else if (TREE_VEC_LENGTH (ce->value) == 1) > + /* Just move the argument into place. */ > + ce->value = TREE_VEC_ELT (ce->value, 0); > + else > + { > + /* Update the length of the final CONSTRUCTOR > + arguments vector, and note that we will need to > + copy.*/ > + newlen = newlen + TREE_VEC_LENGTH (ce->value) - 1; > + need_copy_p = true; > + } > + } > + else > + ce->value = RECUR (ce->value); > + } > + > + if (need_copy_p) > + { > + vec<constructor_elt, va_gc> *old_n = n; > + > + vec_alloc (n, newlen); > + FOR_EACH_VEC_ELT (*old_n, idx, ce) > + { > + if (TREE_CODE (ce->value) == TREE_VEC) > + { > + int i, len = TREE_VEC_LENGTH (ce->value); > + for (i = 0; i < len; ++i) > + CONSTRUCTOR_APPEND_ELT (n, 0, > + TREE_VEC_ELT (ce->value, i)); > + } > + else > + CONSTRUCTOR_APPEND_ELT (n, 0, ce->value); > + } > + } > + > + r = build_constructor (init_list_type_node, n); > + CONSTRUCTOR_IS_DIRECT_INIT (r) = CONSTRUCTOR_IS_DIRECT_INIT (t); > + CONSTRUCTOR_IS_DESIGNATED_INIT (r) > + = CONSTRUCTOR_IS_DESIGNATED_INIT (t); > + > + if (TREE_HAS_CONSTRUCTOR (t)) > + { > + fcl_t cl = fcl_functional; > + if (CONSTRUCTOR_C99_COMPOUND_LITERAL (t)) > + cl = fcl_c99; > + RETURN (finish_compound_literal (type, r, complain, cl)); > + } > + > + TREE_TYPE (r) = type; > + RETURN (r); > + } > + > + case TYPEID_EXPR: > + { > + tree operand_0 = TREE_OPERAND (t, 0); > + if (TYPE_P (operand_0)) > + { > + operand_0 = tsubst (operand_0, args, complain, in_decl); > + RETURN (get_typeid (operand_0, complain)); > + } > + else > + { > + operand_0 = RECUR (operand_0); > + RETURN (build_typeid (operand_0, complain)); > + } > + } > + > + case FUNCTION_DECL: > + case PARM_DECL: > + case VAR_DECL: > + if (!args) > + RETURN (t); > + 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); > + > + /* 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 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 THROW_EXPR: > - RETURN (build_throw > - (input_location, RECUR (TREE_OPERAND (t, 0)))); > + case FIELD_DECL: > + if (DECL_CONTEXT (t)) > + { > + tree ctx; > > - case CONSTRUCTOR: > - { > - vec<constructor_elt, va_gc> *n; > - constructor_elt *ce; > - unsigned HOST_WIDE_INT idx; > - bool process_index_p; > - int newlen; > - bool need_copy_p = false; > - tree r; > + 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); > > - tsubst_flags_t tcomplain = complain; > - if (COMPOUND_LITERAL_P (t)) > - tcomplain |= tf_tst_ok; > - tree type = tsubst (TREE_TYPE (t), args, tcomplain, in_decl); > - if (type == error_mark_node) > - RETURN (error_mark_node); > + case NAMESPACE_DECL: > + case OVERLOAD: > + RETURN (t); > > - /* We do not want to process the index of aggregate > - initializers as they are identifier nodes which will be > - looked up by digest_init. */ > - process_index_p = !(type && MAYBE_CLASS_TYPE_P (type)); > + 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: > > - if (null_member_pointer_value_p (t)) > - { > - gcc_assert (same_type_p (type, TREE_TYPE (t))); > - RETURN (t); > - } > + 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 > > - n = vec_safe_copy (CONSTRUCTOR_ELTS (t)); > - newlen = vec_safe_length (n); > - FOR_EACH_VEC_SAFE_ELT (n, idx, ce) > - { > - if (ce->index && process_index_p > - /* An identifier index is looked up in the type > - being initialized, not the current scope. */ > - && TREE_CODE (ce->index) != IDENTIFIER_NODE) > - ce->index = RECUR (ce->index); > + 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>'. */ > > - if (PACK_EXPANSION_P (ce->value)) > - { > - /* Substitute into the pack expansion. */ > - ce->value = tsubst_pack_expansion (ce->value, args, complain, > - in_decl); > + 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); > > - if (ce->value == error_mark_node > - || PACK_EXPANSION_P (ce->value)) > - ; > - else if (TREE_VEC_LENGTH (ce->value) == 1) > - /* Just move the argument into place. */ > - ce->value = TREE_VEC_ELT (ce->value, 0); > - else > - { > - /* Update the length of the final CONSTRUCTOR > - arguments vector, and note that we will need to > - copy.*/ > - newlen = newlen + TREE_VEC_LENGTH (ce->value) - 1; > - need_copy_p = true; > - } > - } > - else > - ce->value = RECUR (ce->value); > - } > + case TEMPLATE_PARM_INDEX: > + case TYPE_DECL: > + RETURN (tsubst (t, args, complain, in_decl)); > > - if (need_copy_p) > - { > - vec<constructor_elt, va_gc> *old_n = n; > + 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 (); > > - vec_alloc (n, newlen); > - FOR_EACH_VEC_ELT (*old_n, idx, ce) > - { > - if (TREE_CODE (ce->value) == TREE_VEC) > - { > - int i, len = TREE_VEC_LENGTH (ce->value); > - for (i = 0; i < len; ++i) > - CONSTRUCTOR_APPEND_ELT (n, 0, > - TREE_VEC_ELT (ce->value, i)); > - } > - else > - CONSTRUCTOR_APPEND_ELT (n, 0, ce->value); > - } > - } > + 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); > + } > > - r = build_constructor (init_list_type_node, n); > - CONSTRUCTOR_IS_DIRECT_INIT (r) = CONSTRUCTOR_IS_DIRECT_INIT (t); > - CONSTRUCTOR_IS_DESIGNATED_INIT (r) > - = CONSTRUCTOR_IS_DESIGNATED_INIT (t); > + case EXPR_PACK_EXPANSION: > + error ("invalid use of pack expansion expression"); > + RETURN (error_mark_node); > > - if (TREE_HAS_CONSTRUCTOR (t)) > - { > - fcl_t cl = fcl_functional; > - if (CONSTRUCTOR_C99_COMPOUND_LITERAL (t)) > - cl = fcl_c99; > - RETURN (finish_compound_literal (type, r, complain, cl)); > - } > + case NONTYPE_ARGUMENT_PACK: > + error ("use %<...%> to expand argument pack"); > + RETURN (error_mark_node); > > - TREE_TYPE (r) = type; > + 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 TYPEID_EXPR: > + case STRING_CST: > { > - tree operand_0 = TREE_OPERAND (t, 0); > - if (TYPE_P (operand_0)) > - { > - operand_0 = tsubst (operand_0, args, complain, in_decl); > - RETURN (get_typeid (operand_0, complain)); > - } > - else > + tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); > + r = t; > + if (type != TREE_TYPE (t)) > { > - operand_0 = RECUR (operand_0); > - RETURN (build_typeid (operand_0, complain)); > + r = copy_node (t); > + TREE_TYPE (r) = type; > } > + RETURN (r); > } > > - case VAR_DECL: > - if (!args) > - RETURN (t); > - /* Fall through */ > + 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 PARM_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); > - RETURN (r); > - } > + 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: > { > @@ -21728,8 +21408,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 +21539,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 +27266,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.296.g493f462273 > >