c++: merge tsubst_copy into tsubst_copy_and_build
Checks
Commit Message
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.
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(-)
Comments
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
>
>
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.
>> and finally it dispatches to tsubst for type trees.
And it looks like you fix the callers to avoid that?
>> 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?
Can we also merge in tsubst_expr and use that name instead of the
unwieldy tsubst_copy_and_build?
Jason
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))
On 10/4/23 12:08, Patrick Palka wrote:
> 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:
OK.
@@ -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
};
@@ -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))