public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r14-4796] c++: merge tsubst_copy into tsubst_copy_and_build
@ 2023-10-20 15:22 Patrick Palka
  0 siblings, 0 replies; only message in thread
From: Patrick Palka @ 2023-10-20 15:22 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:3e3d73ed5e85e7f467c366e9ad219d558ef9cb79

commit r14-4796-g3e3d73ed5e85e7f467c366e9ad219d558ef9cb79
Author: Patrick Palka <ppalka@redhat.com>
Date:   Fri Oct 20 11:21:54 2023 -0400

    c++: merge tsubst_copy into tsubst_copy_and_build
    
    The relationship between tsubst_copy_and_build and tsubst_copy (two of
    the main template argument substitution routines for expression trees)
    is rather hazy.  The former is mostly a superset of the latter, with
    some differences.
    
    The main apparent difference is their handling of various tree codes,
    but much of the tree code handling in tsubst_copy appears to be dead
    code.  This is because tsubst_copy mostly gets (directly) called on
    id-expressions rather than on arbitrary expressions.  The interesting
    tree codes are PARM_DECL, VAR_DECL, BIT_NOT_EXPR, SCOPE_REF,
    TEMPLATE_ID_EXPR and IDENTIFIER_NODE:
    
     * for PARM_DECL and VAR_DECL, tsubst_copy_and_build calls tsubst_copy
       followed by doing some extra handling of its own
     * for BIT_NOT_EXPR tsubst_copy implicitly handles unresolved destructor
       calls (i.e. the first operand is an identifier or a type)
     * for SCOPE_REF, TEMPLATE_ID_EXPR and IDENTIFIER_NODE tsubst_copy
       refrains from doing name lookup of the terminal name
    
    Other more minor differences are that tsubst_copy exits early when
    'args' is null, and it calls maybe_dependent_member_ref, and finally
    it dispatches to tsubst for type trees.[1]
    
    Thus tsubst_copy is similar enough to tsubst_copy_and_build that it
    makes sense to merge the two functions, with the main difference we
    want to preserve is tsubst_copy's lack of name lookup for id-expressions.
    This patch achieves this via a new tsubst flag tf_no_name_lookup which
    controls name lookup and resolution of a (top-level) id-expression.
    
    [1]: Exiting early for null 'args' doesn't seem right since it means we
    return templated trees even when !processing_template_decl.  And
    dispatching to tsubst for type trees muddles the distinction between
    type and expressions which makes things less clear at the call site.
    So these properties of tsubst_copy don't seem worth preserving.
    
    N.B. the diff for this patch looks much cleaner when generated using
    the "patience diff" algorithm via Git's --patience flag.
    
    gcc/cp/ChangeLog:
    
            * cp-tree.h (enum tsubst_flags): Add tf_no_name_lookup.
            * pt.cc (tsubst_pack_expansion): Use tsubst for substituting
            BASES_TYPE.
            (tsubst_decl) <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.
    
    Reviewed-by: Jason Merrill <jason@redhat.com>

Diff:
---
 gcc/cp/cp-tree.h |    3 +
 gcc/cp/pt.cc     | 1750 ++++++++++++++++++++++--------------------------------
 2 files changed, 727 insertions(+), 1026 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ff3323bf40c8..d6abd153930f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5621,6 +5621,9 @@ enum tsubst_flags {
   tf_qualifying_scope = 1 << 14, /* Substituting the LHS of the :: operator.
 				    Affects TYPENAME_TYPE resolution from
 				    make_typename_type.  */
+  tf_no_name_lookup = 1 << 15, /* Don't look up the terminal name of an
+				  outermost id-expression, or resolve its
+				  constituent template-ids or qualified-ids.  */
   /* Convenient substitution flags combinations.  */
   tf_warning_or_error = tf_warning | tf_error
 };
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index bd84054ae12d..65d637e4488e 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -204,9 +204,9 @@ static void copy_default_args_to_explicit_spec (tree);
 static bool invalid_nontype_parm_type_p (tree, tsubst_flags_t);
 static bool dependent_template_arg_p (tree);
 static bool dependent_type_p_r (tree);
-static tree tsubst_copy	(tree, tree, tsubst_flags_t, tree);
 static tree tsubst_decl (tree, tree, tsubst_flags_t, bool = true);
 static tree tsubst_scope (tree, tree, tsubst_flags_t, tree);
+static tree tsubst_name (tree, tree, tsubst_flags_t, tree);
 static void perform_instantiation_time_access_checks (tree, tree);
 static tree listify (tree);
 static tree listify_autos (tree, tree);
@@ -13373,15 +13373,11 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
       if (TREE_CODE (parm_pack) == BASES)
 	{
 	  gcc_assert (parm_pack == pattern);
+	  tree type = tsubst (BASES_TYPE (parm_pack), args, complain, in_decl);
 	  if (BASES_DIRECT (parm_pack))
-	    return calculate_direct_bases (tsubst_expr (BASES_TYPE (parm_pack),
-							args, complain,
-							in_decl),
-					   complain);
+	    return calculate_direct_bases (type, complain);
 	  else
-	    return calculate_bases (tsubst_expr (BASES_TYPE (parm_pack),
-						 args, complain, in_decl),
-				    complain);
+	    return calculate_bases (type, complain);
 	}
       else if (builtin_pack_call_p (parm_pack))
 	{
@@ -15171,7 +15167,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain,
 	      variadic_p = true;
 	    }
 	  else
-	    name = tsubst_copy (name, args, complain, in_decl);
+	    name = tsubst_name (name, args, complain, in_decl);
 
 	  int len;
 	  if (!variadic_p)
@@ -16108,7 +16104,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       if (template_placeholder_p (t))
 	{
 	  tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (t);
-	  tmpl = tsubst_copy (tmpl, args, complain, in_decl);
+	  tmpl = tsubst_copy_and_build (tmpl, args, complain, in_decl);
 	  if (TREE_CODE (tmpl) == TEMPLATE_TEMPLATE_PARM)
 	    tmpl = TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (tmpl);
 
@@ -16592,7 +16588,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	if (ctx == error_mark_node)
 	  return error_mark_node;
 
-	tree f = tsubst_copy (TYPENAME_TYPE_FULLNAME (t), args,
+	tree f = tsubst_name (TYPENAME_TYPE_FULLNAME (t), args,
 			      complain, in_decl);
 	if (f == error_mark_node)
 	  return error_mark_node;
@@ -16780,6 +16776,15 @@ tsubst_scope (tree t, tree args, tsubst_flags_t complain, tree in_decl)
   return tsubst (t, args, complain | tf_qualifying_scope, in_decl);
 }
 
+/* Convenience wrapper over tsubst for substituting into an id-expression
+   without resolving its terminal name.  */
+
+static tree
+tsubst_name (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+{
+  return tsubst_copy_and_build (t, args, complain | tf_no_name_lookup, in_decl);
+}
+
 /* OLDFNS is a lookup set of member functions from some class template, and
    NEWFNS is a lookup set of member functions from NEWTYPE, a specialization
    of that class template.  Return the subset of NEWFNS which are
@@ -17045,7 +17050,7 @@ tsubst_qualified_id (tree qualified_id, tree args,
   if (args)
     {
       scope = tsubst_scope (scope, args, complain, in_decl);
-      expr = tsubst_copy (name, args, complain, in_decl);
+      expr = tsubst_name (name, args, complain, in_decl);
     }
   else
     expr = name;
@@ -17277,878 +17282,177 @@ maybe_dependent_member_ref (tree t, tree args, tsubst_flags_t complain,
 				 TREE_CODE (t) == TEMPLATE_DECL);
 }
 
-/* Like tsubst, but deals with expressions.  This function just replaces
-   template parms; to finish processing the resultant expression, use
-   tsubst_copy_and_build or tsubst_expr.  */
+/* Helper function for tsubst_omp_clauses, used for instantiation of
+   OMP_CLAUSE_DECL of clauses.  */
 
 static tree
-tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+tsubst_omp_clause_decl (tree decl, tree args, tsubst_flags_t complain,
+			tree in_decl, tree *iterator_cache)
 {
-  enum tree_code code;
-  tree r;
-
-  if (t == NULL_TREE || t == error_mark_node || args == NULL_TREE)
-    return t;
-
-  if (TYPE_P (t))
-    return tsubst (t, args, complain, in_decl);
-
-  if (tree d = maybe_dependent_member_ref (t, args, complain, in_decl))
-    return d;
-
-  code = TREE_CODE (t);
+  if (decl == NULL_TREE || decl == ridpointers[RID_OMP_ALL_MEMORY])
+    return decl;
 
-  switch (code)
+  /* Handle OpenMP iterators.  */
+  if (TREE_CODE (decl) == TREE_LIST
+      && TREE_PURPOSE (decl)
+      && TREE_CODE (TREE_PURPOSE (decl)) == TREE_VEC)
     {
-    case PARM_DECL:
-      r = retrieve_local_specialization (t);
-
-      if (r == NULL_TREE)
+      tree ret;
+      if (iterator_cache[0] == TREE_PURPOSE (decl))
+	ret = iterator_cache[1];
+      else
 	{
-	  /* We get here for a use of 'this' in an NSDMI.  */
-	  if (DECL_NAME (t) == this_identifier && current_class_ptr)
-	    return current_class_ptr;
-
-	  /* This can happen for a parameter name used later in a function
-	     declaration (such as in a late-specified return type).  Just
-	     make a dummy decl, since it's only used for its type.  */
-	  gcc_assert (cp_unevaluated_operand);
-	  r = tsubst_decl (t, args, complain);
-	  /* Give it the template pattern as its context; its true context
-	     hasn't been instantiated yet and this is good enough for
-	     mangling.  */
-	  DECL_CONTEXT (r) = DECL_CONTEXT (t);
+	  tree *tp = &ret;
+	  begin_scope (sk_omp, NULL);
+	  for (tree it = TREE_PURPOSE (decl); it; it = TREE_CHAIN (it))
+	    {
+	      *tp = copy_node (it);
+	      TREE_VEC_ELT (*tp, 0)
+		= tsubst_decl (TREE_VEC_ELT (it, 0), args, complain);
+	      DECL_CONTEXT (TREE_VEC_ELT (*tp, 0)) = current_function_decl;
+	      pushdecl (TREE_VEC_ELT (*tp, 0));
+	      TREE_VEC_ELT (*tp, 1)
+		= tsubst_expr (TREE_VEC_ELT (it, 1), args, complain, in_decl);
+	      TREE_VEC_ELT (*tp, 2)
+		= tsubst_expr (TREE_VEC_ELT (it, 2), args, complain, in_decl);
+	      TREE_VEC_ELT (*tp, 3)
+		= tsubst_expr (TREE_VEC_ELT (it, 3), args, complain, in_decl);
+	      TREE_CHAIN (*tp) = NULL_TREE;
+	      tp = &TREE_CHAIN (*tp);
+	    }
+	  TREE_VEC_ELT (ret, 5) = poplevel (1, 1, 0);
+	  iterator_cache[0] = TREE_PURPOSE (decl);
+	  iterator_cache[1] = ret;
 	}
+      return build_tree_list (ret, tsubst_omp_clause_decl (TREE_VALUE (decl),
+							   args, complain,
+							   in_decl, NULL));
+    }
 
-      if (TREE_CODE (r) == ARGUMENT_PACK_SELECT)
-	r = argument_pack_select_arg (r);
-      if (!mark_used (r, complain) && !(complain & tf_error))
-	return error_mark_node;
-      return r;
-
-    case CONST_DECL:
-      {
-	tree enum_type;
-	tree v;
-
-	if (DECL_TEMPLATE_PARM_P (t))
-	  return tsubst_copy (DECL_INITIAL (t), args, complain, in_decl);
-	if (!uses_template_parms (DECL_CONTEXT (t)))
-	  return t;
-
-	/* Unfortunately, we cannot just call lookup_name here.
-	   Consider:
-
-	     template <int 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 +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 (),
@@ -20798,26 +20143,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 +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);
 
@@ -21556,154 +20952,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 +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))

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-10-20 15:22 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-10-20 15:22 [gcc r14-4796] c++: merge tsubst_copy into tsubst_copy_and_build Patrick Palka

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).