public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 1/2] c++: remove NON_DEPENDENT_EXPR, part 1
@ 2023-09-25 20:43 Patrick Palka
  2023-09-25 20:43 ` [PATCH 2/2] c++: remove NON_DEPENDENT_EXPR, part 2 Patrick Palka
  2023-09-26 23:18 ` [PATCH 1/2] c++: remove NON_DEPENDENT_EXPR, part 1 Jason Merrill
  0 siblings, 2 replies; 13+ messages in thread
From: Patrick Palka @ 2023-09-25 20:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: jason, Patrick Palka

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
for trunk?

-- >8 --

This tree code dates all the way back to r69130[1] which implemented
typing of non-dependent expressions.  Its motivation was never clear (to
me at least) since the documentation for it in e.g. cp-tree.def doesn't
seem accurate anymore.  build_non_dependent_expr has since gained
a bunch of edge cases about whether (or how) to wrap certain templated
trees, making it hard to reason about in general.

So this patch removes this tree code, and temporarily turns
build_non_dependent_expr into the identity function.  The subsequent
patch will remove build_non_dependent_expr and adjust its callers
appropriately.

We now need to gracefully handle templated (sub)trees in a couple of
places, places which previously didn't see templated trees since they
didn't look through NON_DEPENDENT_EXPR.

[1]: https://gcc.gnu.org/pipermail/gcc-patches/2003-July/109355.html

gcc/c-family/ChangeLog:

	* c-warn.cc (check_address_or_pointer_of_packed_member): Handle
	templated CALL_EXPR naming a local extern function.

gcc/cp/ChangeLog:

	* class.cc (instantiate_type): Remove NON_DEPENDENT_EXPR
	handling.
	* constexpr.cc (cxx_eval_constant_expression): Likewise.
	(potential_constant_expression_1): Likewise.
	* coroutines.cc (coro_validate_builtin_call): Don't
	expect ALIGNOF_EXPR to be wrapped in NON_DEPENDENT_EXPR.
	* cp-objcp-common.cc (cp_common_init_ts): Remove
	NON_DEPENDENT_EXPR handling.
	* cp-tree.def (NON_DEPENDENT_EXPR): Remove.
	* cp-tree.h (build_non_dependent_expr): Temporarily redefine as
	the identity function.
	* cvt.cc (maybe_warn_nodiscard): Handle templated CALL_EXPR
	naming a local extern function.
	* cxx-pretty-print.cc (cxx_pretty_printer::expression): Remove
	NON_DEPENDENT_EXPR handling.
	* error.cc (dump_decl): Likewise.
	(dump_expr): Likewise.
	* expr.cc (mark_use): Likewise.
	(mark_exp_read): Likewise.
	* pt.cc (build_non_dependent_expr): Remove.
	* tree.cc (lvalue_kind): Remove NON_DEPENDENT_EXPR handling.
	(cp_stabilize_reference): Likewise.
	* typeck.cc (warn_for_null_address): Likewise.
	(cp_build_binary_op): Handle type-dependent SIZEOF_EXPR operands.
	(cp_build_unary_op) <case TRUTH_NOT_EXPR>: Don't fold inside a
	template.

gcc/testsuite/ChangeLog:

	* g++.dg/concepts/var-concept3.C: Adjust expected diagnostic
	for attempting to call a variable concept.
---
 gcc/c-family/c-warn.cc                       |  2 +-
 gcc/cp/class.cc                              |  9 --
 gcc/cp/constexpr.cc                          |  9 --
 gcc/cp/coroutines.cc                         |  3 +-
 gcc/cp/cp-objcp-common.cc                    |  1 -
 gcc/cp/cp-tree.def                           | 11 ---
 gcc/cp/cp-tree.h                             |  2 +-
 gcc/cp/cvt.cc                                |  4 +-
 gcc/cp/cxx-pretty-print.cc                   |  1 -
 gcc/cp/error.cc                              |  8 --
 gcc/cp/expr.cc                               |  2 -
 gcc/cp/pt.cc                                 | 92 --------------------
 gcc/cp/tree.cc                               |  5 --
 gcc/cp/typeck.cc                             | 13 +--
 gcc/testsuite/g++.dg/concepts/var-concept3.C |  2 +-
 15 files changed, 15 insertions(+), 149 deletions(-)

diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc
index e67dd87a773..c07770394bf 100644
--- a/gcc/c-family/c-warn.cc
+++ b/gcc/c-family/c-warn.cc
@@ -3029,7 +3029,7 @@ check_address_or_pointer_of_packed_member (tree type, tree rhs)
       if (TREE_CODE (rhs) == CALL_EXPR)
 	{
 	  rhs = CALL_EXPR_FN (rhs);	/* Pointer expression.  */
-	  if (rhs == NULL_TREE)
+	  if (rhs == NULL_TREE || TREE_CODE (rhs) == IDENTIFIER_NODE)
 	    return NULL_TREE;
 	  rhs = TREE_TYPE (rhs);	/* Pointer type.  */
 	  /* We could be called while processing a template and RHS could be
diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index b71333af1f8..10de0437242 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -8843,15 +8843,6 @@ instantiate_type (tree lhstype, tree rhs, tsubst_flags_t complain)
       rhs = BASELINK_FUNCTIONS (rhs);
     }
 
-  /* If we are in a template, and have a NON_DEPENDENT_EXPR, we cannot
-     deduce any type information.  */
-  if (TREE_CODE (rhs) == NON_DEPENDENT_EXPR)
-    {
-      if (complain & tf_error)
-	error ("not enough type information");
-      return error_mark_node;
-    }
-
   /* There are only a few kinds of expressions that may have a type
      dependent on overload resolution.  */
   gcc_assert (TREE_CODE (rhs) == ADDR_EXPR
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 2a6601c0cbc..8c9abeeec1b 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -8054,7 +8054,6 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case MODOP_EXPR:
       /* GCC internal stuff.  */
     case VA_ARG_EXPR:
-    case NON_DEPENDENT_EXPR:
     case BASELINK:
     case OFFSET_REF:
       if (!ctx->quiet)
@@ -9922,14 +9921,6 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
     case BIND_EXPR:
       return RECUR (BIND_EXPR_BODY (t), want_rval);
 
-    case NON_DEPENDENT_EXPR:
-      /* Treat NON_DEPENDENT_EXPR as non-constant: it's not handled by
-	 constexpr evaluation or tsubst, so fold_non_dependent_expr can't
-	 do anything useful with it.  And we shouldn't see it in a context
-	 where a constant expression is strictly required, hence the assert.  */
-      gcc_checking_assert (!(flags & tf_error));
-      return false;
-
     case CLEANUP_POINT_EXPR:
     case MUST_NOT_THROW_EXPR:
     case TRY_CATCH_EXPR:
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 3493d3c6ed3..df3cc820797 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -1421,8 +1421,7 @@ coro_validate_builtin_call (tree call, tsubst_flags_t)
 	location_t loc = EXPR_LOCATION (arg);
 
 	/* We expect alignof expressions in templates.  */
-	if (TREE_CODE (arg) == NON_DEPENDENT_EXPR
-	    && TREE_CODE (TREE_OPERAND (arg, 0)) == ALIGNOF_EXPR)
+	if (TREE_CODE (arg) == ALIGNOF_EXPR)
 	  ;
 	else if (!TREE_CONSTANT (arg))
 	  {
diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
index 93b027b80ce..2093ae02466 100644
--- a/gcc/cp/cp-objcp-common.cc
+++ b/gcc/cp/cp-objcp-common.cc
@@ -525,7 +525,6 @@ cp_common_init_ts (void)
   MARK_TS_EXP (MUST_NOT_THROW_EXPR);
   MARK_TS_EXP (NEW_EXPR);
   MARK_TS_EXP (NOEXCEPT_EXPR);
-  MARK_TS_EXP (NON_DEPENDENT_EXPR);
   MARK_TS_EXP (OFFSETOF_EXPR);
   MARK_TS_EXP (OFFSET_REF);
   MARK_TS_EXP (PSEUDO_DTOR_EXPR);
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index 0e66ca70e00..d78005e50b9 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -262,17 +262,6 @@ DEFTREECODE (TYPEID_EXPR, "typeid_expr", tcc_expression, 1)
 DEFTREECODE (NOEXCEPT_EXPR, "noexcept_expr", tcc_unary, 1)
 DEFTREECODE (SPACESHIP_EXPR, "spaceship_expr", tcc_expression, 2)
 
-/* A placeholder for an expression that is not type-dependent, but
-   does occur in a template.  When an expression that is not
-   type-dependent appears in a larger expression, we must compute the
-   type of that larger expression.  That computation would normally
-   modify the original expression, which would change the mangling of
-   that expression if it appeared in a template argument list.  In
-   that situation, we create a NON_DEPENDENT_EXPR to take the place of
-   the original expression.  The expression is the only operand -- it
-   is only needed for diagnostics.  */
-DEFTREECODE (NON_DEPENDENT_EXPR, "non_dependent_expr", tcc_expression, 1)
-
 /* CTOR_INITIALIZER is a placeholder in template code for a call to
    setup_vtbl_pointer (and appears in all functions, not just ctors).  */
 DEFTREECODE (CTOR_INITIALIZER, "ctor_initializer", tcc_expression, 1)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 6e34952da99..66b9a9c4b9a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7488,7 +7488,7 @@ extern bool any_value_dependent_elements_p      (const_tree);
 extern bool dependent_omp_for_p			(tree, tree, tree, tree);
 extern tree resolve_typename_type		(tree, bool);
 extern tree template_for_substitution		(tree);
-extern tree build_non_dependent_expr		(tree);
+inline tree build_non_dependent_expr		(tree t) { return t; } // XXX remove
 extern void make_args_non_dependent		(vec<tree, va_gc> *);
 extern bool reregister_specialization		(tree, tree, tree);
 extern tree instantiate_non_dependent_expr	(tree, tsubst_flags_t = tf_error);
diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc
index 96abfae7725..fdd34c8562e 100644
--- a/gcc/cp/cvt.cc
+++ b/gcc/cp/cvt.cc
@@ -1048,7 +1048,7 @@ maybe_warn_nodiscard (tree expr, impl_conv_void implicit)
     call = TARGET_EXPR_INITIAL (expr);
   location_t loc = cp_expr_loc_or_input_loc (call);
   tree callee = cp_get_callee (call);
-  if (!callee)
+  if (!callee || identifier_p (callee))
     return;
 
   tree type = TREE_TYPE (callee);
@@ -1056,6 +1056,8 @@ maybe_warn_nodiscard (tree expr, impl_conv_void implicit)
     type = TYPE_PTRMEMFUNC_FN_TYPE (type);
   if (INDIRECT_TYPE_P (type))
     type = TREE_TYPE (type);
+  if (!FUNC_OR_METHOD_TYPE_P (type))
+    return;
 
   tree rettype = TREE_TYPE (type);
   tree fn = cp_get_fndecl_from_callee (callee);
diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc
index eb16e63425f..6a82358f370 100644
--- a/gcc/cp/cxx-pretty-print.cc
+++ b/gcc/cp/cxx-pretty-print.cc
@@ -1207,7 +1207,6 @@ cxx_pretty_printer::expression (tree t)
       assignment_expression (t);
       break;
 
-    case NON_DEPENDENT_EXPR:
     case MUST_NOT_THROW_EXPR:
       expression (TREE_OPERAND (t, 0));
       break;
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index 8a5219a68a1..49476a57ead 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -1510,10 +1510,6 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags)
       dump_decl (pp, BASELINK_FUNCTIONS (t), flags);
       break;
 
-    case NON_DEPENDENT_EXPR:
-      dump_expr (pp, t, flags);
-      break;
-
     case TEMPLATE_TYPE_PARM:
       if (flags & TFF_DECL_SPECIFIERS)
 	pp->declaration (t);
@@ -2942,10 +2938,6 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
       pp_cxx_right_paren (pp);
       break;
 
-    case NON_DEPENDENT_EXPR:
-      dump_expr (pp, TREE_OPERAND (t, 0), flags);
-      break;
-
     case ARGUMENT_PACK_SELECT:
       dump_template_argument (pp, ARGUMENT_PACK_SELECT_FROM_PACK (t), flags);
       break;
diff --git a/gcc/cp/expr.cc b/gcc/cp/expr.cc
index cdd29c15fc3..8371a245d95 100644
--- a/gcc/cp/expr.cc
+++ b/gcc/cp/expr.cc
@@ -147,7 +147,6 @@ mark_use (tree expr, bool rvalue_p, bool read_p,
 	}
       break;
     case COMPONENT_REF:
-    case NON_DEPENDENT_EXPR:
       recurse_op[0] = true;
       break;
     case COMPOUND_EXPR:
@@ -371,7 +370,6 @@ mark_exp_read (tree exp)
     case ADDR_EXPR:
     case INDIRECT_REF:
     case FLOAT_EXPR:
-    case NON_DEPENDENT_EXPR:
     case VIEW_CONVERT_EXPR:
       mark_exp_read (TREE_OPERAND (exp, 0));
       break;
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 73ac1cb597c..e565c0538b7 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -29294,98 +29294,6 @@ resolve_typename_type (tree type, bool only_current_p)
   return result;
 }
 
-/* EXPR is an expression which is not type-dependent.  Return a proxy
-   for EXPR that can be used to compute the types of larger
-   expressions containing EXPR.  */
-
-tree
-build_non_dependent_expr (tree expr)
-{
-  tree orig_expr = expr;
-  tree inner_expr;
-
-  /* When checking, try to get a constant value for all non-dependent
-     expressions in order to expose bugs in *_dependent_expression_p
-     and constexpr.  This can affect code generation, see PR70704, so
-     only do this for -fchecking=2.  */
-  if (flag_checking > 1
-      && cxx_dialect >= cxx11
-      /* Don't do this during nsdmi parsing as it can lead to
-	 unexpected recursive instantiations.  */
-      && !parsing_nsdmi ()
-      /* Don't do this during concept processing either and for
-         the same reason.  */
-      && !processing_constraint_expression_p ())
-    fold_non_dependent_expr (expr, tf_none);
-
-  STRIP_ANY_LOCATION_WRAPPER (expr);
-
-  /* Preserve OVERLOADs; the functions must be available to resolve
-     types.  */
-  inner_expr = expr;
-  if (TREE_CODE (inner_expr) == STMT_EXPR)
-    inner_expr = stmt_expr_value_expr (inner_expr);
-  if (TREE_CODE (inner_expr) == ADDR_EXPR)
-    inner_expr = TREE_OPERAND (inner_expr, 0);
-  if (TREE_CODE (inner_expr) == COMPONENT_REF)
-    inner_expr = TREE_OPERAND (inner_expr, 1);
-  if (is_overloaded_fn (inner_expr)
-      || TREE_CODE (inner_expr) == OFFSET_REF)
-    return orig_expr;
-  /* There is no need to return a proxy for a variable, parameter
-     or enumerator.  */
-  if (VAR_P (expr) || TREE_CODE (expr) == PARM_DECL
-      || TREE_CODE (expr) == CONST_DECL)
-    return orig_expr;
-  /* Preserve string constants; conversions from string constants to
-     "char *" are allowed, even though normally a "const char *"
-     cannot be used to initialize a "char *".  */
-  if (TREE_CODE (expr) == STRING_CST)
-    return orig_expr;
-  /* Preserve void and arithmetic constants, as an optimization -- there is no
-     reason to create a new node.  */
-  if (TREE_CODE (expr) == VOID_CST
-      || TREE_CODE (expr) == INTEGER_CST
-      || TREE_CODE (expr) == REAL_CST)
-    return orig_expr;
-  /* Preserve THROW_EXPRs -- all throw-expressions have type "void".
-     There is at least one place where we want to know that a
-     particular expression is a throw-expression: when checking a ?:
-     expression, there are special rules if the second or third
-     argument is a throw-expression.  */
-  if (TREE_CODE (expr) == THROW_EXPR)
-    return orig_expr;
-
-  /* Don't wrap an initializer list, we need to be able to look inside.  */
-  if (BRACE_ENCLOSED_INITIALIZER_P (expr))
-    return orig_expr;
-
-  /* Don't wrap a dummy object, we need to be able to test for it.  */
-  if (is_dummy_object (expr))
-    return orig_expr;
-
-  if (TREE_CODE (expr) == COND_EXPR)
-    return build3 (COND_EXPR,
-		   TREE_TYPE (expr),
-		   build_non_dependent_expr (TREE_OPERAND (expr, 0)),
-		   (TREE_OPERAND (expr, 1)
-		    ? build_non_dependent_expr (TREE_OPERAND (expr, 1))
-		    : build_non_dependent_expr (TREE_OPERAND (expr, 0))),
-		   build_non_dependent_expr (TREE_OPERAND (expr, 2)));
-  if (TREE_CODE (expr) == COMPOUND_EXPR)
-    return build2 (COMPOUND_EXPR,
-		   TREE_TYPE (expr),
-		   TREE_OPERAND (expr, 0),
-		   build_non_dependent_expr (TREE_OPERAND (expr, 1)));
-
-  /* If the type is unknown, it can't really be non-dependent */
-  gcc_assert (TREE_TYPE (expr) != unknown_type_node);
-
-  /* Otherwise, build a NON_DEPENDENT_EXPR.  */
-  return build1_loc (EXPR_LOCATION (orig_expr), NON_DEPENDENT_EXPR,
-		     TREE_TYPE (expr), expr);
-}
-
 /* ARGS is a vector of expressions as arguments to a function call.
    Replace the arguments with equivalent non-dependent expressions.
    This modifies ARGS in place.  */
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index eaf882f8854..a3d61d3e7c9 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -308,7 +308,6 @@ lvalue_kind (const_tree ref)
 	 its argument unmodified and we assign it to a const_tree.  */
       return lvalue_kind (BASELINK_FUNCTIONS (CONST_CAST_TREE (ref)));
 
-    case NON_DEPENDENT_EXPR:
     case PAREN_EXPR:
       return lvalue_kind (TREE_OPERAND (ref, 0));
 
@@ -412,10 +411,6 @@ cp_stabilize_reference (tree ref)
   STRIP_ANY_LOCATION_WRAPPER (ref);
   switch (TREE_CODE (ref))
     {
-    case NON_DEPENDENT_EXPR:
-      /* We aren't actually evaluating this.  */
-      return ref;
-
     /* We need to treat specially anything stabilize_reference doesn't
        handle specifically.  */
     case VAR_DECL:
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 8132bd7fccc..2cfa3c8a935 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -4844,9 +4844,6 @@ warn_for_null_address (location_t location, tree op, tsubst_flags_t complain)
       || warning_suppressed_p (op, OPT_Waddress))
     return;
 
-  if (TREE_CODE (op) == NON_DEPENDENT_EXPR)
-    op = TREE_OPERAND (op, 0);
-
   tree cop = fold_for_warn (op);
 
   if (TREE_CODE (cop) == NON_LVALUE_EXPR)
@@ -5405,7 +5402,9 @@ cp_build_binary_op (const op_location_t &location,
 	    type0 = TREE_TYPE (type0);
 	  if (!TYPE_P (type1))
 	    type1 = TREE_TYPE (type1);
-	  if (INDIRECT_TYPE_P (type0) && same_type_p (TREE_TYPE (type0), type1))
+	  if (type0
+	      && INDIRECT_TYPE_P (type0)
+	      && same_type_p (TREE_TYPE (type0), type1))
 	    {
 	      if (!(TREE_CODE (first_arg) == PARM_DECL
 		    && DECL_ARRAY_PARAMETER_P (first_arg)
@@ -5422,7 +5421,9 @@ cp_build_binary_op (const op_location_t &location,
 			      "first %<sizeof%> operand was declared here");
 		}
 	    }
-	  else if (TREE_CODE (type0) == ARRAY_TYPE
+	  else if (!dependent_type_p (type0)
+		   && !dependent_type_p (type1)
+		   && TREE_CODE (type0) == ARRAY_TYPE
 		   && !char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type0)))
 		   /* Set by finish_parenthesized_expr.  */
 		   && !warning_suppressed_p (op1, OPT_Wsizeof_array_div)
@@ -7399,6 +7400,8 @@ cp_build_unary_op (enum tree_code code, tree xarg, bool noconvert,
 					 complain);
       if (arg != error_mark_node)
 	{
+	  if (processing_template_decl)
+	    return build1_loc (location, TRUTH_NOT_EXPR, boolean_type_node, arg);
 	  val = invert_truthvalue_loc (location, arg);
 	  if (obvalue_p (val))
 	    val = non_lvalue_loc (location, val);
diff --git a/gcc/testsuite/g++.dg/concepts/var-concept3.C b/gcc/testsuite/g++.dg/concepts/var-concept3.C
index 6fd96a5042e..b4483ebca89 100644
--- a/gcc/testsuite/g++.dg/concepts/var-concept3.C
+++ b/gcc/testsuite/g++.dg/concepts/var-concept3.C
@@ -12,7 +12,7 @@ template<typename T>
 
 
 template<typename U>
-  requires C1<U>() // { dg-error "cannot be used as a function" }
+  requires C1<U>() // { dg-error "cannot call a concept" }
   void f1(U) { }
 
 template<typename U>
-- 
2.42.0.270.gbcb6cae296


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 2/2] c++: remove NON_DEPENDENT_EXPR, part 2
  2023-09-25 20:43 [PATCH 1/2] c++: remove NON_DEPENDENT_EXPR, part 1 Patrick Palka
@ 2023-09-25 20:43 ` Patrick Palka
  2023-10-02 19:37   ` [PATCH] c++: merge tsubst_copy into tsubst_copy_and_build Patrick Palka
                     ` (2 more replies)
  2023-09-26 23:18 ` [PATCH 1/2] c++: remove NON_DEPENDENT_EXPR, part 1 Jason Merrill
  1 sibling, 3 replies; 13+ messages in thread
From: Patrick Palka @ 2023-09-25 20:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: jason, Patrick Palka

This much more mechanical patch removes build_non_dependent_expr
(and make_args_non_dependent) and adjusts callers accordingly,
no functional change.

gcc/cp/ChangeLog:

	* call.cc (build_new_method_call): Remove calls to
	build_non_dependent_expr and/or make_args_non_dependent.
	* coroutines.cc (finish_co_return_stmt): Likewise.
	* cp-tree.h (build_non_dependent_expr): Remove.
	(make_args_non_dependent): Remove.
	* decl2.cc (grok_array_decl): Remove calls to
	build_non_dependent_expr and/or make_args_non_dependent.
	(build_offset_ref_call_from_tree): Likewise.
	* init.cc (build_new): Likewise.
	* pt.cc (make_args_non_dependent): Remove.
	(test_build_non_dependent_expr): Remove.
	(cp_pt_cc_tests): Adjust.
	* semantics.cc (finish_expr_stmt): Remove calls to
	build_non_dependent_expr and/or make_args_non_dependent.
	(finish_for_expr): Likewise.
	(finish_call_expr): Likewise.
	(finish_omp_atomic): Likewise.
	* typeck.cc (finish_class_member_access_expr): Likewise.
	(build_x_indirect_ref): Likewise.
	(build_x_binary_op): Likewise.
	(build_x_array_ref): Likewise.
	(build_x_vec_perm_expr): Likewise.
	(build_x_shufflevector): Likewise.
	(build_x_unary_op): Likewise.
	(cp_build_addressof): Likewise.
	(build_x_conditional_expr):
	(build_x_compound_expr): Likewise.
	(build_static_cast): Likewise.
	(build_x_modify_expr): Likewise.
	(check_return_expr): Likewise.
	* typeck2.cc (build_x_arrow): Likewise.
---
 gcc/cp/call.cc       |  7 +------
 gcc/cp/coroutines.cc |  3 ---
 gcc/cp/cp-tree.h     |  2 --
 gcc/cp/decl2.cc      | 17 +++-------------
 gcc/cp/init.cc       |  5 -----
 gcc/cp/pt.cc         | 46 --------------------------------------------
 gcc/cp/semantics.cc  | 25 ++----------------------
 gcc/cp/typeck.cc     | 31 -----------------------------
 gcc/cp/typeck2.cc    |  1 -
 9 files changed, 6 insertions(+), 131 deletions(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index e8dafbd8ba6..15079ddf6dc 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -11430,12 +11430,7 @@ build_new_method_call (tree instance, tree fns, vec<tree, va_gc> **args,
     }
 
   if (processing_template_decl)
-    {
-      orig_args = args == NULL ? NULL : make_tree_vector_copy (*args);
-      instance = build_non_dependent_expr (instance);
-      if (args != NULL)
-	make_args_non_dependent (*args);
-    }
+    orig_args = args == NULL ? NULL : make_tree_vector_copy (*args);
 
   /* Process the argument list.  */
   if (args != NULL && *args != NULL)
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index df3cc820797..a5464becf7f 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -1351,9 +1351,6 @@ finish_co_return_stmt (location_t kw, tree expr)
 	 to undo it so we can try to treat it as an rvalue below.  */
       expr = maybe_undo_parenthesized_ref (expr);
 
-      if (processing_template_decl)
-	expr = build_non_dependent_expr (expr);
-
       if (error_operand_p (expr))
 	return error_mark_node;
     }
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 66b9a9c4b9a..8b9a7d58462 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7488,8 +7488,6 @@ extern bool any_value_dependent_elements_p      (const_tree);
 extern bool dependent_omp_for_p			(tree, tree, tree, tree);
 extern tree resolve_typename_type		(tree, bool);
 extern tree template_for_substitution		(tree);
-inline tree build_non_dependent_expr		(tree t) { return t; } // XXX remove
-extern void make_args_non_dependent		(vec<tree, va_gc> *);
 extern bool reregister_specialization		(tree, tree, tree);
 extern tree instantiate_non_dependent_expr	(tree, tsubst_flags_t = tf_error);
 extern tree instantiate_non_dependent_expr_internal (tree, tsubst_flags_t);
diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index 344e19ec98b..0aa1e355972 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -427,14 +427,8 @@ grok_array_decl (location_t loc, tree array_expr, tree index_exp,
 	  return build_min_nt_loc (loc, ARRAY_REF, array_expr, index_exp,
 				   NULL_TREE, NULL_TREE);
 	}
-      array_expr = build_non_dependent_expr (array_expr);
-      if (index_exp)
-	index_exp = build_non_dependent_expr (index_exp);
-      else
-	{
-	  orig_index_exp_list = make_tree_vector_copy (*index_exp_list);
-	  make_args_non_dependent (*index_exp_list);
-	}
+      if (!index_exp)
+	orig_index_exp_list = make_tree_vector_copy (*index_exp_list);
     }
 
   type = TREE_TYPE (array_expr);
@@ -5435,18 +5429,13 @@ build_offset_ref_call_from_tree (tree fn, vec<tree, va_gc> **args,
       orig_args = make_tree_vector_copy (*args);
 
       /* Transform the arguments and add the implicit "this"
-	 parameter.  That must be done before the FN is transformed
-	 because we depend on the form of FN.  */
-      make_args_non_dependent (*args);
-      object = build_non_dependent_expr (object);
+	 parameter.  */
       if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
 	{
 	  if (TREE_CODE (fn) == DOTSTAR_EXPR)
 	    object = cp_build_addr_expr (object, complain);
 	  vec_safe_insert (*args, 0, object);
 	}
-      /* Now that the arguments are done, transform FN.  */
-      fn = build_non_dependent_expr (fn);
     }
 
   /* A qualified name corresponding to a bound pointer-to-member is
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index c5830297b93..d1bae3b155f 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -3920,11 +3920,6 @@ build_new (location_t loc, vec<tree, va_gc> **placement, tree type,
 		(**init)[i] = copy_node (e);
 	    }
 	}
-
-      make_args_non_dependent (*placement);
-      if (nelts)
-	nelts = build_non_dependent_expr (nelts);
-      make_args_non_dependent (*init);
     }
 
   if (nelts)
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index e565c0538b7..382db4dd01d 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -29294,24 +29294,6 @@ resolve_typename_type (tree type, bool only_current_p)
   return result;
 }
 
-/* ARGS is a vector of expressions as arguments to a function call.
-   Replace the arguments with equivalent non-dependent expressions.
-   This modifies ARGS in place.  */
-
-void
-make_args_non_dependent (vec<tree, va_gc> *args)
-{
-  unsigned int ix;
-  tree arg;
-
-  FOR_EACH_VEC_SAFE_ELT (args, ix, arg)
-    {
-      tree newarg = build_non_dependent_expr (arg);
-      if (newarg != arg)
-	(*args)[ix] = newarg;
-    }
-}
-
 /* Returns a type which represents 'auto' or 'decltype(auto)'.  We use a
    TEMPLATE_TYPE_PARM with a level one deeper than the actual template parms,
    by default.  If set_canonical is true, we set TYPE_CANONICAL on it.  */
@@ -31523,33 +31505,6 @@ print_template_statistics (void)
 
 namespace selftest {
 
-/* Verify that build_non_dependent_expr () works, for various expressions,
-   and that location wrappers don't affect the results.  */
-
-static void
-test_build_non_dependent_expr ()
-{
-  location_t loc = BUILTINS_LOCATION;
-
-  /* Verify constants, without and with location wrappers.  */
-  tree int_cst = build_int_cst (integer_type_node, 42);
-  ASSERT_EQ (int_cst, build_non_dependent_expr (int_cst));
-
-  tree wrapped_int_cst = maybe_wrap_with_location (int_cst, loc);
-  ASSERT_TRUE (location_wrapper_p (wrapped_int_cst));
-  ASSERT_EQ (wrapped_int_cst, build_non_dependent_expr (wrapped_int_cst));
-
-  tree string_lit = build_string (4, "foo");
-  TREE_TYPE (string_lit) = char_array_type_node;
-  string_lit = fix_string_type (string_lit);
-  ASSERT_EQ (string_lit, build_non_dependent_expr (string_lit));
-
-  tree wrapped_string_lit = maybe_wrap_with_location (string_lit, loc);
-  ASSERT_TRUE (location_wrapper_p (wrapped_string_lit));
-  ASSERT_EQ (wrapped_string_lit,
-	     build_non_dependent_expr (wrapped_string_lit));
-}
-
 /* Verify that type_dependent_expression_p () works correctly, even
    in the presence of location wrapper nodes.  */
 
@@ -31590,7 +31545,6 @@ test_type_dependent_expression_p ()
 void
 cp_pt_cc_tests ()
 {
-  test_build_non_dependent_expr ();
   test_type_dependent_expression_p ();
 }
 
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 80ef1364e33..1d478f0781f 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -916,8 +916,7 @@ finish_expr_stmt (tree expr)
 	  expr = convert_to_void (expr, ICV_STATEMENT, tf_warning_or_error);
 	}
       else if (!type_dependent_expression_p (expr))
-	convert_to_void (build_non_dependent_expr (expr), ICV_STATEMENT,
-                         tf_warning_or_error);
+	convert_to_void (expr, ICV_STATEMENT, tf_warning_or_error);
 
       if (check_for_bare_parameter_packs (expr))
         expr = error_mark_node;
@@ -1396,8 +1395,7 @@ finish_for_expr (tree expr, tree for_stmt)
                               tf_warning_or_error);
     }
   else if (!type_dependent_expression_p (expr))
-    convert_to_void (build_non_dependent_expr (expr), ICV_THIRD_IN_FOR,
-                     tf_warning_or_error);
+    convert_to_void (expr, ICV_THIRD_IN_FOR, tf_warning_or_error);
   expr = maybe_cleanup_point_expr_void (expr);
   if (check_for_bare_parameter_packs (expr))
     expr = error_mark_node;
@@ -2819,11 +2817,6 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
 	  return result;
 	}
       orig_args = make_tree_vector_copy (*args);
-      if (!BASELINK_P (fn)
-	  && TREE_CODE (fn) != PSEUDO_DTOR_EXPR
-	  && TREE_TYPE (fn) != unknown_type_node)
-	fn = build_non_dependent_expr (fn);
-      make_args_non_dependent (*args);
     }
 
   if (TREE_CODE (fn) == COMPONENT_REF)
@@ -11034,20 +11027,6 @@ finish_omp_atomic (location_t loc, enum tree_code code, enum tree_code opcode,
 	      || TREE_CODE (OMP_CLAUSE_HINT_EXPR (clauses)) != INTEGER_CST)
 	    dependent_p = true;
 	}
-      if (!dependent_p)
-	{
-	  lhs = build_non_dependent_expr (lhs);
-	  if (rhs)
-	    rhs = build_non_dependent_expr (rhs);
-	  if (v)
-	    v = build_non_dependent_expr (v);
-	  if (lhs1)
-	    lhs1 = build_non_dependent_expr (lhs1);
-	  if (rhs1)
-	    rhs1 = build_non_dependent_expr (rhs1);
-	  if (r && r != void_list_node)
-	    r = build_non_dependent_expr (r);
-	}
     }
   if (!dependent_p)
     {
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 2cfa3c8a935..f3dc80c40cf 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -3385,7 +3385,6 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
 	  return build_min_nt_loc (UNKNOWN_LOCATION, COMPONENT_REF,
 				   orig_object, orig_name, NULL_TREE);
 	}
-      object = build_non_dependent_expr (object);
     }
   else if (c_dialect_objc ()
 	   && identifier_p (name)
@@ -3743,7 +3742,6 @@ build_x_indirect_ref (location_t loc, tree expr, ref_operator errorstring,
 	    = build_dependent_operator_type (lookups, INDIRECT_REF, false);
 	  return expr;
 	}
-      expr = build_non_dependent_expr (expr);
     }
 
   rval = build_new_op (loc, INDIRECT_REF, LOOKUP_NORMAL, expr,
@@ -4712,8 +4710,6 @@ build_x_binary_op (const op_location_t &loc, enum tree_code code, tree arg1,
 	    = build_dependent_operator_type (lookups, code, false);
 	  return expr;
 	}
-      arg1 = build_non_dependent_expr (arg1);
-      arg2 = build_non_dependent_expr (arg2);
     }
 
   if (code == DOTSTAR_EXPR)
@@ -4767,8 +4763,6 @@ build_x_array_ref (location_t loc, tree arg1, tree arg2,
 	  || type_dependent_expression_p (arg2))
 	return build_min_nt_loc (loc, ARRAY_REF, arg1, arg2,
 				 NULL_TREE, NULL_TREE);
-      arg1 = build_non_dependent_expr (arg1);
-      arg2 = build_non_dependent_expr (arg2);
     }
 
   expr = build_new_op (loc, ARRAY_REF, LOOKUP_NORMAL, arg1, arg2,
@@ -6601,10 +6595,6 @@ build_x_vec_perm_expr (location_t loc,
 	  || type_dependent_expression_p (arg1)
 	  || type_dependent_expression_p (arg2))
 	return build_min_nt_loc (loc, VEC_PERM_EXPR, arg0, arg1, arg2);
-      arg0 = build_non_dependent_expr (arg0);
-      if (arg1)
-	arg1 = build_non_dependent_expr (arg1);
-      arg2 = build_non_dependent_expr (arg2);
     }
   tree exp = c_build_vec_perm_expr (loc, arg0, arg1, arg2, complain & tf_error);
   if (processing_template_decl && exp != error_mark_node)
@@ -6632,9 +6622,6 @@ build_x_shufflevector (location_t loc, vec<tree, va_gc> *args,
 	    CALL_EXPR_IFN (exp) = IFN_SHUFFLEVECTOR;
 	    return exp;
 	  }
-      arg0 = build_non_dependent_expr (arg0);
-      arg1 = build_non_dependent_expr (arg1);
-      /* ???  Nothing needed for the index arguments?  */
     }
   auto_vec<tree, 16> mask;
   for (unsigned i = 2; i < args->length (); ++i)
@@ -6804,8 +6791,6 @@ build_x_unary_op (location_t loc, enum tree_code code, cp_expr xarg,
 	  TREE_TYPE (e) = build_dependent_operator_type (lookups, code, false);
 	  return e;
 	}
-
-      xarg = build_non_dependent_expr (xarg);
     }
 
   exp = NULL_TREE;
@@ -6923,8 +6908,6 @@ cp_build_addressof (location_t loc, tree arg, tsubst_flags_t complain)
     {
       if (type_dependent_expression_p (arg))
 	return build_min_nt_loc (loc, ADDRESSOF_EXPR, arg, NULL_TREE);
-
-      arg = build_non_dependent_expr (arg);
     }
 
   tree exp = cp_build_addr_expr_strict (arg, complain);
@@ -7859,10 +7842,6 @@ build_x_conditional_expr (location_t loc, tree ifexp, tree op1, tree op2,
 	  || (op1 && type_dependent_expression_p (op1))
 	  || type_dependent_expression_p (op2))
 	return build_min_nt_loc (loc, COND_EXPR, ifexp, op1, op2);
-      ifexp = build_non_dependent_expr (ifexp);
-      if (op1)
-	op1 = build_non_dependent_expr (op1);
-      op2 = build_non_dependent_expr (op2);
     }
 
   expr = build_conditional_expr (loc, ifexp, op1, op2, complain);
@@ -7983,8 +7962,6 @@ build_x_compound_expr (location_t loc, tree op1, tree op2,
 	    = build_dependent_operator_type (lookups, COMPOUND_EXPR, false);
 	  return result;
 	}
-      op1 = build_non_dependent_expr (op1);
-      op2 = build_non_dependent_expr (op2);
     }
 
   result = build_new_op (loc, COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2,
@@ -8556,8 +8533,6 @@ build_static_cast (location_t loc, tree type, tree oexpr,
       protected_set_expr_location (result, loc);
       return result;
     }
-  else if (processing_template_decl)
-    expr = build_non_dependent_expr (expr);
 
   /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
      Strip such NOP_EXPRs if VALUE is being used in non-lvalue context.  */
@@ -9737,9 +9712,6 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
 	      = build_dependent_operator_type (lookups, modifycode, true);
 	  return rval;
 	}
-
-      lhs = build_non_dependent_expr (lhs);
-      rhs = build_non_dependent_expr (rhs);
     }
 
   tree rval;
@@ -11230,9 +11202,6 @@ check_return_expr (tree retval, bool *no_warning, bool *dangling)
       if (VOID_TYPE_P (functype))
 	return error_mark_node;
 
-      if (processing_template_decl)
-	retval = build_non_dependent_expr (retval);
-
       /* Under C++11 [12.8/32 class.copy], a returned lvalue is sometimes
 	 treated as an rvalue for the purposes of overload resolution to
 	 favor move constructors over copy constructors.
diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index cd1ea045720..5ac8d3d08e9 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -2218,7 +2218,6 @@ build_x_arrow (location_t loc, tree expr, tsubst_flags_t complain)
 	  TREE_TYPE (expr) = ttype;
 	  return expr;
 	}
-      expr = build_non_dependent_expr (expr);
     }
 
   if (MAYBE_CLASS_TYPE_P (type))
-- 
2.42.0.270.gbcb6cae296


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 1/2] c++: remove NON_DEPENDENT_EXPR, part 1
  2023-09-25 20:43 [PATCH 1/2] c++: remove NON_DEPENDENT_EXPR, part 1 Patrick Palka
  2023-09-25 20:43 ` [PATCH 2/2] c++: remove NON_DEPENDENT_EXPR, part 2 Patrick Palka
@ 2023-09-26 23:18 ` Jason Merrill
  2023-09-27 11:54   ` Patrick Palka
  1 sibling, 1 reply; 13+ messages in thread
From: Jason Merrill @ 2023-09-26 23:18 UTC (permalink / raw)
  To: Patrick Palka, gcc-patches

On 9/25/23 16:43, Patrick Palka wrote:
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
> for trunk?
> 
> -- >8 --
> 
> This tree code dates all the way back to r69130[1] which implemented
> typing of non-dependent expressions.  Its motivation was never clear (to
> me at least) since the documentation for it in e.g. cp-tree.def doesn't
> seem accurate anymore.  build_non_dependent_expr has since gained
> a bunch of edge cases about whether (or how) to wrap certain templated
> trees, making it hard to reason about in general.
> 
> So this patch removes this tree code, and temporarily turns
> build_non_dependent_expr into the identity function.  The subsequent
> patch will remove build_non_dependent_expr and adjust its callers
> appropriately.
> 
> We now need to gracefully handle templated (sub)trees in a couple of
> places, places which previously didn't see templated trees since they
> didn't look through NON_DEPENDENT_EXPR.
> 
> [1]: https://gcc.gnu.org/pipermail/gcc-patches/2003-July/109355.html
> 
> gcc/c-family/ChangeLog:
> 
> 	* c-warn.cc (check_address_or_pointer_of_packed_member): Handle
> 	templated CALL_EXPR naming a local extern function.
> 
> gcc/cp/ChangeLog:
> 
> 	* class.cc (instantiate_type): Remove NON_DEPENDENT_EXPR
> 	handling.
> 	* constexpr.cc (cxx_eval_constant_expression): Likewise.
> 	(potential_constant_expression_1): Likewise.
> 	* coroutines.cc (coro_validate_builtin_call): Don't
> 	expect ALIGNOF_EXPR to be wrapped in NON_DEPENDENT_EXPR.
> 	* cp-objcp-common.cc (cp_common_init_ts): Remove
> 	NON_DEPENDENT_EXPR handling.
> 	* cp-tree.def (NON_DEPENDENT_EXPR): Remove.
> 	* cp-tree.h (build_non_dependent_expr): Temporarily redefine as
> 	the identity function.
> 	* cvt.cc (maybe_warn_nodiscard): Handle templated CALL_EXPR
> 	naming a local extern function.
> 	* cxx-pretty-print.cc (cxx_pretty_printer::expression): Remove
> 	NON_DEPENDENT_EXPR handling.
> 	* error.cc (dump_decl): Likewise.
> 	(dump_expr): Likewise.
> 	* expr.cc (mark_use): Likewise.
> 	(mark_exp_read): Likewise.
> 	* pt.cc (build_non_dependent_expr): Remove.
> 	* tree.cc (lvalue_kind): Remove NON_DEPENDENT_EXPR handling.
> 	(cp_stabilize_reference): Likewise.
> 	* typeck.cc (warn_for_null_address): Likewise.
> 	(cp_build_binary_op): Handle type-dependent SIZEOF_EXPR operands.
> 	(cp_build_unary_op) <case TRUTH_NOT_EXPR>: Don't fold inside a
> 	template.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/concepts/var-concept3.C: Adjust expected diagnostic
> 	for attempting to call a variable concept.
> ---
>   gcc/c-family/c-warn.cc                       |  2 +-
>   gcc/cp/class.cc                              |  9 --
>   gcc/cp/constexpr.cc                          |  9 --
>   gcc/cp/coroutines.cc                         |  3 +-
>   gcc/cp/cp-objcp-common.cc                    |  1 -
>   gcc/cp/cp-tree.def                           | 11 ---
>   gcc/cp/cp-tree.h                             |  2 +-
>   gcc/cp/cvt.cc                                |  4 +-
>   gcc/cp/cxx-pretty-print.cc                   |  1 -
>   gcc/cp/error.cc                              |  8 --
>   gcc/cp/expr.cc                               |  2 -
>   gcc/cp/pt.cc                                 | 92 --------------------
>   gcc/cp/tree.cc                               |  5 --
>   gcc/cp/typeck.cc                             | 13 +--
>   gcc/testsuite/g++.dg/concepts/var-concept3.C |  2 +-
>   15 files changed, 15 insertions(+), 149 deletions(-)
> 
> diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc
> index e67dd87a773..c07770394bf 100644
> --- a/gcc/c-family/c-warn.cc
> +++ b/gcc/c-family/c-warn.cc
> @@ -3029,7 +3029,7 @@ check_address_or_pointer_of_packed_member (tree type, tree rhs)
>         if (TREE_CODE (rhs) == CALL_EXPR)
>   	{
>   	  rhs = CALL_EXPR_FN (rhs);	/* Pointer expression.  */
> -	  if (rhs == NULL_TREE)
> +	  if (rhs == NULL_TREE || TREE_CODE (rhs) == IDENTIFIER_NODE)
>   	    return NULL_TREE;
>   	  rhs = TREE_TYPE (rhs);	/* Pointer type.  */
>   	  /* We could be called while processing a template and RHS could be
>              a functor.  In that case it's a class, not a pointer.  */
>           if (!POINTER_TYPE_P (rhs))

How about adding !rhs to this condition instead of checking specifically 
for IDENTIFIER_NODE above?

>             return NULL_TREE;

> @@ -1048,7 +1048,7 @@ maybe_warn_nodiscard (tree expr, impl_conv_void implicit)
>       call = TARGET_EXPR_INITIAL (expr);
>     location_t loc = cp_expr_loc_or_input_loc (call);
>     tree callee = cp_get_callee (call);
> -  if (!callee)
> +  if (!callee || identifier_p (callee))
>       return;

And similarly handling null type here?

> @@ -5405,7 +5402,9 @@ cp_build_binary_op (const op_location_t &location,
>   	    type0 = TREE_TYPE (type0);
>   	  if (!TYPE_P (type1))
>   	    type1 = TREE_TYPE (type1);
> -	  if (INDIRECT_TYPE_P (type0) && same_type_p (TREE_TYPE (type0), type1))
> +	  if (type0
> +	      && INDIRECT_TYPE_P (type0)
> +	      && same_type_p (TREE_TYPE (type0), type1))

If type0 were null here, wouldn't we have crashed when checking TYPE_P 
(type0) a few lines above?

Jason


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 1/2] c++: remove NON_DEPENDENT_EXPR, part 1
  2023-09-26 23:18 ` [PATCH 1/2] c++: remove NON_DEPENDENT_EXPR, part 1 Jason Merrill
@ 2023-09-27 11:54   ` Patrick Palka
  0 siblings, 0 replies; 13+ messages in thread
From: Patrick Palka @ 2023-09-27 11:54 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Patrick Palka, gcc-patches

On Tue, 26 Sep 2023, Jason Merrill wrote:

> On 9/25/23 16:43, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
> > for trunk?
> > 
> > -- >8 --
> > 
> > This tree code dates all the way back to r69130[1] which implemented
> > typing of non-dependent expressions.  Its motivation was never clear (to
> > me at least) since the documentation for it in e.g. cp-tree.def doesn't
> > seem accurate anymore.  build_non_dependent_expr has since gained
> > a bunch of edge cases about whether (or how) to wrap certain templated
> > trees, making it hard to reason about in general.
> > 
> > So this patch removes this tree code, and temporarily turns
> > build_non_dependent_expr into the identity function.  The subsequent
> > patch will remove build_non_dependent_expr and adjust its callers
> > appropriately.
> > 
> > We now need to gracefully handle templated (sub)trees in a couple of
> > places, places which previously didn't see templated trees since they
> > didn't look through NON_DEPENDENT_EXPR.
> > 
> > [1]: https://gcc.gnu.org/pipermail/gcc-patches/2003-July/109355.html
> > 
> > gcc/c-family/ChangeLog:
> > 
> > 	* c-warn.cc (check_address_or_pointer_of_packed_member): Handle
> > 	templated CALL_EXPR naming a local extern function.
> > 
> > gcc/cp/ChangeLog:
> > 
> > 	* class.cc (instantiate_type): Remove NON_DEPENDENT_EXPR
> > 	handling.
> > 	* constexpr.cc (cxx_eval_constant_expression): Likewise.
> > 	(potential_constant_expression_1): Likewise.
> > 	* coroutines.cc (coro_validate_builtin_call): Don't
> > 	expect ALIGNOF_EXPR to be wrapped in NON_DEPENDENT_EXPR.
> > 	* cp-objcp-common.cc (cp_common_init_ts): Remove
> > 	NON_DEPENDENT_EXPR handling.
> > 	* cp-tree.def (NON_DEPENDENT_EXPR): Remove.
> > 	* cp-tree.h (build_non_dependent_expr): Temporarily redefine as
> > 	the identity function.
> > 	* cvt.cc (maybe_warn_nodiscard): Handle templated CALL_EXPR
> > 	naming a local extern function.
> > 	* cxx-pretty-print.cc (cxx_pretty_printer::expression): Remove
> > 	NON_DEPENDENT_EXPR handling.
> > 	* error.cc (dump_decl): Likewise.
> > 	(dump_expr): Likewise.
> > 	* expr.cc (mark_use): Likewise.
> > 	(mark_exp_read): Likewise.
> > 	* pt.cc (build_non_dependent_expr): Remove.
> > 	* tree.cc (lvalue_kind): Remove NON_DEPENDENT_EXPR handling.
> > 	(cp_stabilize_reference): Likewise.
> > 	* typeck.cc (warn_for_null_address): Likewise.
> > 	(cp_build_binary_op): Handle type-dependent SIZEOF_EXPR operands.
> > 	(cp_build_unary_op) <case TRUTH_NOT_EXPR>: Don't fold inside a
> > 	template.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > 	* g++.dg/concepts/var-concept3.C: Adjust expected diagnostic
> > 	for attempting to call a variable concept.
> > ---
> >   gcc/c-family/c-warn.cc                       |  2 +-
> >   gcc/cp/class.cc                              |  9 --
> >   gcc/cp/constexpr.cc                          |  9 --
> >   gcc/cp/coroutines.cc                         |  3 +-
> >   gcc/cp/cp-objcp-common.cc                    |  1 -
> >   gcc/cp/cp-tree.def                           | 11 ---
> >   gcc/cp/cp-tree.h                             |  2 +-
> >   gcc/cp/cvt.cc                                |  4 +-
> >   gcc/cp/cxx-pretty-print.cc                   |  1 -
> >   gcc/cp/error.cc                              |  8 --
> >   gcc/cp/expr.cc                               |  2 -
> >   gcc/cp/pt.cc                                 | 92 --------------------
> >   gcc/cp/tree.cc                               |  5 --
> >   gcc/cp/typeck.cc                             | 13 +--
> >   gcc/testsuite/g++.dg/concepts/var-concept3.C |  2 +-
> >   15 files changed, 15 insertions(+), 149 deletions(-)
> > 
> > diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc
> > index e67dd87a773..c07770394bf 100644
> > --- a/gcc/c-family/c-warn.cc
> > +++ b/gcc/c-family/c-warn.cc
> > @@ -3029,7 +3029,7 @@ check_address_or_pointer_of_packed_member (tree type,
> > tree rhs)
> >         if (TREE_CODE (rhs) == CALL_EXPR)
> >   	{
> >   	  rhs = CALL_EXPR_FN (rhs);	/* Pointer expression.  */
> > -	  if (rhs == NULL_TREE)
> > +	  if (rhs == NULL_TREE || TREE_CODE (rhs) == IDENTIFIER_NODE)
> >   	    return NULL_TREE;
> >   	  rhs = TREE_TYPE (rhs);	/* Pointer type.  */
> >   	  /* We could be called while processing a template and RHS could be
> >              a functor.  In that case it's a class, not a pointer.  */
> >           if (!POINTER_TYPE_P (rhs))
> 
> How about adding !rhs to this condition instead of checking specifically for
> IDENTIFIER_NODE above?

Done.

> 
> >             return NULL_TREE;
> 
> > @@ -1048,7 +1048,7 @@ maybe_warn_nodiscard (tree expr, impl_conv_void
> > implicit)
> >       call = TARGET_EXPR_INITIAL (expr);
> >     location_t loc = cp_expr_loc_or_input_loc (call);
> >     tree callee = cp_get_callee (call);
> > -  if (!callee)
> > +  if (!callee || identifier_p (callee))
> >       return;
> 
> And similarly handling null type here?

Done.

> 
> > @@ -5405,7 +5402,9 @@ cp_build_binary_op (const op_location_t &location,
> >   	    type0 = TREE_TYPE (type0);
> >   	  if (!TYPE_P (type1))
> >   	    type1 = TREE_TYPE (type1);
> > -	  if (INDIRECT_TYPE_P (type0) && same_type_p (TREE_TYPE (type0),
> > type1))
> > +	  if (type0
> > +	      && INDIRECT_TYPE_P (type0)
> > +	      && same_type_p (TREE_TYPE (type0), type1))
> 
> If type0 were null here, wouldn't we have crashed when checking TYPE_P (type0)
> a few lines above?

In this case type0 was originally a type-dependent expression and became
null after 'type0 = TREE_TYPE (type0)'.

Here's an updated patch with the above changes made, bootstrapped and
regtested on x86_64-pc-linux-gnu.

-- >8 --

Subject: [PATCH] c++: remove NON_DEPENDENT_EXPR, part 1

This tree code dates all the way back to r69130[1] which implemented
typing of non-dependent expressions.  Its motivation was never clear (to
me at least) since the documentation for it e.g. in cp-tree.def doesn't
seem accurate anymore.  build_non_dependent_expr has since gained
a bunch of edge cases about whether (or how) to wrap certain templated
trees, making it hard to reason about in general.

So this patch removes this tree code, and temporarily turns
build_non_dependent_expr into the identity function.  The subsequent
patch will remove build_non_dependent_expr and adjust its callers
appropriately.

We now need to more thoroughly handle templated (sub)trees in a couple
of places which previously didn't need to since they didn't look through
NON_DEPENDENT_EXPR.

[1]: https://gcc.gnu.org/pipermail/gcc-patches/2003-July/109355.html

gcc/c-family/ChangeLog:

	* c-warn.cc (check_address_or_pointer_of_packed_member): Handle
	type-dependent callee of CALL_EXPR.

gcc/cp/ChangeLog:

	* class.cc (instantiate_type): Remove NON_DEPENDENT_EXPR
	handling.
	* constexpr.cc (cxx_eval_constant_expression): Likewise.
	(potential_constant_expression_1): Likewise.
	* coroutines.cc (coro_validate_builtin_call): Don't
	expect ALIGNOF_EXPR to be wrapped in NON_DEPENDENT_EXPR.
	* cp-objcp-common.cc (cp_common_init_ts): Remove
	NON_DEPENDENT_EXPR handling.
	* cp-tree.def (NON_DEPENDENT_EXPR): Remove.
	* cp-tree.h (build_non_dependent_expr): Temporarily redefine as
	the identity function.
	* cvt.cc (maybe_warn_nodiscard): Handle type-dependent and
	variable callee of CALL_EXPR.
	* cxx-pretty-print.cc (cxx_pretty_printer::expression): Remove
	NON_DEPENDENT_EXPR handling.
	* error.cc (dump_decl): Likewise.
	(dump_expr): Likewise.
	* expr.cc (mark_use): Likewise.
	(mark_exp_read): Likewise.
	* pt.cc (build_non_dependent_expr): Remove.
	* tree.cc (lvalue_kind): Remove NON_DEPENDENT_EXPR handling.
	(cp_stabilize_reference): Likewise.
	* typeck.cc (warn_for_null_address): Likewise.
	(cp_build_binary_op): Handle type-dependent SIZEOF_EXPR operands.
	(cp_build_unary_op) <case TRUTH_NOT_EXPR>: Don't fold inside a
	template.

gcc/testsuite/ChangeLog:

	* g++.dg/concepts/var-concept3.C: Adjust expected diagnostic
	for attempting to call a variable concept.
---
 gcc/c-family/c-warn.cc                       |  2 +-
 gcc/cp/class.cc                              |  9 --
 gcc/cp/constexpr.cc                          |  9 --
 gcc/cp/coroutines.cc                         |  3 +-
 gcc/cp/cp-objcp-common.cc                    |  1 -
 gcc/cp/cp-tree.def                           | 11 ---
 gcc/cp/cp-tree.h                             |  2 +-
 gcc/cp/cvt.cc                                |  4 +-
 gcc/cp/cxx-pretty-print.cc                   |  1 -
 gcc/cp/error.cc                              |  8 --
 gcc/cp/expr.cc                               |  2 -
 gcc/cp/pt.cc                                 | 92 --------------------
 gcc/cp/tree.cc                               |  5 --
 gcc/cp/typeck.cc                             | 13 +--
 gcc/testsuite/g++.dg/concepts/var-concept3.C |  2 +-
 15 files changed, 15 insertions(+), 149 deletions(-)

diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc
index e67dd87a773..a0650ec3637 100644
--- a/gcc/c-family/c-warn.cc
+++ b/gcc/c-family/c-warn.cc
@@ -3034,7 +3034,7 @@ check_address_or_pointer_of_packed_member (tree type, tree rhs)
 	  rhs = TREE_TYPE (rhs);	/* Pointer type.  */
 	  /* We could be called while processing a template and RHS could be
 	     a functor.  In that case it's a class, not a pointer.  */
-	  if (!POINTER_TYPE_P (rhs))
+	  if (!rhs || !POINTER_TYPE_P (rhs))
 	    return NULL_TREE;
 	  rhs = TREE_TYPE (rhs);	/* Function type.  */
 	  rhstype = TREE_TYPE (rhs);
diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index b71333af1f8..10de0437242 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -8843,15 +8843,6 @@ instantiate_type (tree lhstype, tree rhs, tsubst_flags_t complain)
       rhs = BASELINK_FUNCTIONS (rhs);
     }
 
-  /* If we are in a template, and have a NON_DEPENDENT_EXPR, we cannot
-     deduce any type information.  */
-  if (TREE_CODE (rhs) == NON_DEPENDENT_EXPR)
-    {
-      if (complain & tf_error)
-	error ("not enough type information");
-      return error_mark_node;
-    }
-
   /* There are only a few kinds of expressions that may have a type
      dependent on overload resolution.  */
   gcc_assert (TREE_CODE (rhs) == ADDR_EXPR
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 2a6601c0cbc..8c9abeeec1b 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -8054,7 +8054,6 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case MODOP_EXPR:
       /* GCC internal stuff.  */
     case VA_ARG_EXPR:
-    case NON_DEPENDENT_EXPR:
     case BASELINK:
     case OFFSET_REF:
       if (!ctx->quiet)
@@ -9922,14 +9921,6 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
     case BIND_EXPR:
       return RECUR (BIND_EXPR_BODY (t), want_rval);
 
-    case NON_DEPENDENT_EXPR:
-      /* Treat NON_DEPENDENT_EXPR as non-constant: it's not handled by
-	 constexpr evaluation or tsubst, so fold_non_dependent_expr can't
-	 do anything useful with it.  And we shouldn't see it in a context
-	 where a constant expression is strictly required, hence the assert.  */
-      gcc_checking_assert (!(flags & tf_error));
-      return false;
-
     case CLEANUP_POINT_EXPR:
     case MUST_NOT_THROW_EXPR:
     case TRY_CATCH_EXPR:
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 3493d3c6ed3..df3cc820797 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -1421,8 +1421,7 @@ coro_validate_builtin_call (tree call, tsubst_flags_t)
 	location_t loc = EXPR_LOCATION (arg);
 
 	/* We expect alignof expressions in templates.  */
-	if (TREE_CODE (arg) == NON_DEPENDENT_EXPR
-	    && TREE_CODE (TREE_OPERAND (arg, 0)) == ALIGNOF_EXPR)
+	if (TREE_CODE (arg) == ALIGNOF_EXPR)
 	  ;
 	else if (!TREE_CONSTANT (arg))
 	  {
diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
index 93b027b80ce..2093ae02466 100644
--- a/gcc/cp/cp-objcp-common.cc
+++ b/gcc/cp/cp-objcp-common.cc
@@ -525,7 +525,6 @@ cp_common_init_ts (void)
   MARK_TS_EXP (MUST_NOT_THROW_EXPR);
   MARK_TS_EXP (NEW_EXPR);
   MARK_TS_EXP (NOEXCEPT_EXPR);
-  MARK_TS_EXP (NON_DEPENDENT_EXPR);
   MARK_TS_EXP (OFFSETOF_EXPR);
   MARK_TS_EXP (OFFSET_REF);
   MARK_TS_EXP (PSEUDO_DTOR_EXPR);
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index 0e66ca70e00..d78005e50b9 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -262,17 +262,6 @@ DEFTREECODE (TYPEID_EXPR, "typeid_expr", tcc_expression, 1)
 DEFTREECODE (NOEXCEPT_EXPR, "noexcept_expr", tcc_unary, 1)
 DEFTREECODE (SPACESHIP_EXPR, "spaceship_expr", tcc_expression, 2)
 
-/* A placeholder for an expression that is not type-dependent, but
-   does occur in a template.  When an expression that is not
-   type-dependent appears in a larger expression, we must compute the
-   type of that larger expression.  That computation would normally
-   modify the original expression, which would change the mangling of
-   that expression if it appeared in a template argument list.  In
-   that situation, we create a NON_DEPENDENT_EXPR to take the place of
-   the original expression.  The expression is the only operand -- it
-   is only needed for diagnostics.  */
-DEFTREECODE (NON_DEPENDENT_EXPR, "non_dependent_expr", tcc_expression, 1)
-
 /* CTOR_INITIALIZER is a placeholder in template code for a call to
    setup_vtbl_pointer (and appears in all functions, not just ctors).  */
 DEFTREECODE (CTOR_INITIALIZER, "ctor_initializer", tcc_expression, 1)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 6e34952da99..66b9a9c4b9a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7488,7 +7488,7 @@ extern bool any_value_dependent_elements_p      (const_tree);
 extern bool dependent_omp_for_p			(tree, tree, tree, tree);
 extern tree resolve_typename_type		(tree, bool);
 extern tree template_for_substitution		(tree);
-extern tree build_non_dependent_expr		(tree);
+inline tree build_non_dependent_expr		(tree t) { return t; } // XXX remove
 extern void make_args_non_dependent		(vec<tree, va_gc> *);
 extern bool reregister_specialization		(tree, tree, tree);
 extern tree instantiate_non_dependent_expr	(tree, tsubst_flags_t = tf_error);
diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc
index 96abfae7725..4dfb39fb60b 100644
--- a/gcc/cp/cvt.cc
+++ b/gcc/cp/cvt.cc
@@ -1048,7 +1048,7 @@ maybe_warn_nodiscard (tree expr, impl_conv_void implicit)
     call = TARGET_EXPR_INITIAL (expr);
   location_t loc = cp_expr_loc_or_input_loc (call);
   tree callee = cp_get_callee (call);
-  if (!callee)
+  if (!callee || !TREE_TYPE (callee))
     return;
 
   tree type = TREE_TYPE (callee);
@@ -1056,6 +1056,8 @@ maybe_warn_nodiscard (tree expr, impl_conv_void implicit)
     type = TYPE_PTRMEMFUNC_FN_TYPE (type);
   if (INDIRECT_TYPE_P (type))
     type = TREE_TYPE (type);
+  if (!FUNC_OR_METHOD_TYPE_P (type))
+    return;
 
   tree rettype = TREE_TYPE (type);
   tree fn = cp_get_fndecl_from_callee (callee);
diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc
index eb16e63425f..6a82358f370 100644
--- a/gcc/cp/cxx-pretty-print.cc
+++ b/gcc/cp/cxx-pretty-print.cc
@@ -1207,7 +1207,6 @@ cxx_pretty_printer::expression (tree t)
       assignment_expression (t);
       break;
 
-    case NON_DEPENDENT_EXPR:
     case MUST_NOT_THROW_EXPR:
       expression (TREE_OPERAND (t, 0));
       break;
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index 8a5219a68a1..49476a57ead 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -1510,10 +1510,6 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags)
       dump_decl (pp, BASELINK_FUNCTIONS (t), flags);
       break;
 
-    case NON_DEPENDENT_EXPR:
-      dump_expr (pp, t, flags);
-      break;
-
     case TEMPLATE_TYPE_PARM:
       if (flags & TFF_DECL_SPECIFIERS)
 	pp->declaration (t);
@@ -2942,10 +2938,6 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
       pp_cxx_right_paren (pp);
       break;
 
-    case NON_DEPENDENT_EXPR:
-      dump_expr (pp, TREE_OPERAND (t, 0), flags);
-      break;
-
     case ARGUMENT_PACK_SELECT:
       dump_template_argument (pp, ARGUMENT_PACK_SELECT_FROM_PACK (t), flags);
       break;
diff --git a/gcc/cp/expr.cc b/gcc/cp/expr.cc
index cdd29c15fc3..8371a245d95 100644
--- a/gcc/cp/expr.cc
+++ b/gcc/cp/expr.cc
@@ -147,7 +147,6 @@ mark_use (tree expr, bool rvalue_p, bool read_p,
 	}
       break;
     case COMPONENT_REF:
-    case NON_DEPENDENT_EXPR:
       recurse_op[0] = true;
       break;
     case COMPOUND_EXPR:
@@ -371,7 +370,6 @@ mark_exp_read (tree exp)
     case ADDR_EXPR:
     case INDIRECT_REF:
     case FLOAT_EXPR:
-    case NON_DEPENDENT_EXPR:
     case VIEW_CONVERT_EXPR:
       mark_exp_read (TREE_OPERAND (exp, 0));
       break;
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 73ac1cb597c..e565c0538b7 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -29294,98 +29294,6 @@ resolve_typename_type (tree type, bool only_current_p)
   return result;
 }
 
-/* EXPR is an expression which is not type-dependent.  Return a proxy
-   for EXPR that can be used to compute the types of larger
-   expressions containing EXPR.  */
-
-tree
-build_non_dependent_expr (tree expr)
-{
-  tree orig_expr = expr;
-  tree inner_expr;
-
-  /* When checking, try to get a constant value for all non-dependent
-     expressions in order to expose bugs in *_dependent_expression_p
-     and constexpr.  This can affect code generation, see PR70704, so
-     only do this for -fchecking=2.  */
-  if (flag_checking > 1
-      && cxx_dialect >= cxx11
-      /* Don't do this during nsdmi parsing as it can lead to
-	 unexpected recursive instantiations.  */
-      && !parsing_nsdmi ()
-      /* Don't do this during concept processing either and for
-         the same reason.  */
-      && !processing_constraint_expression_p ())
-    fold_non_dependent_expr (expr, tf_none);
-
-  STRIP_ANY_LOCATION_WRAPPER (expr);
-
-  /* Preserve OVERLOADs; the functions must be available to resolve
-     types.  */
-  inner_expr = expr;
-  if (TREE_CODE (inner_expr) == STMT_EXPR)
-    inner_expr = stmt_expr_value_expr (inner_expr);
-  if (TREE_CODE (inner_expr) == ADDR_EXPR)
-    inner_expr = TREE_OPERAND (inner_expr, 0);
-  if (TREE_CODE (inner_expr) == COMPONENT_REF)
-    inner_expr = TREE_OPERAND (inner_expr, 1);
-  if (is_overloaded_fn (inner_expr)
-      || TREE_CODE (inner_expr) == OFFSET_REF)
-    return orig_expr;
-  /* There is no need to return a proxy for a variable, parameter
-     or enumerator.  */
-  if (VAR_P (expr) || TREE_CODE (expr) == PARM_DECL
-      || TREE_CODE (expr) == CONST_DECL)
-    return orig_expr;
-  /* Preserve string constants; conversions from string constants to
-     "char *" are allowed, even though normally a "const char *"
-     cannot be used to initialize a "char *".  */
-  if (TREE_CODE (expr) == STRING_CST)
-    return orig_expr;
-  /* Preserve void and arithmetic constants, as an optimization -- there is no
-     reason to create a new node.  */
-  if (TREE_CODE (expr) == VOID_CST
-      || TREE_CODE (expr) == INTEGER_CST
-      || TREE_CODE (expr) == REAL_CST)
-    return orig_expr;
-  /* Preserve THROW_EXPRs -- all throw-expressions have type "void".
-     There is at least one place where we want to know that a
-     particular expression is a throw-expression: when checking a ?:
-     expression, there are special rules if the second or third
-     argument is a throw-expression.  */
-  if (TREE_CODE (expr) == THROW_EXPR)
-    return orig_expr;
-
-  /* Don't wrap an initializer list, we need to be able to look inside.  */
-  if (BRACE_ENCLOSED_INITIALIZER_P (expr))
-    return orig_expr;
-
-  /* Don't wrap a dummy object, we need to be able to test for it.  */
-  if (is_dummy_object (expr))
-    return orig_expr;
-
-  if (TREE_CODE (expr) == COND_EXPR)
-    return build3 (COND_EXPR,
-		   TREE_TYPE (expr),
-		   build_non_dependent_expr (TREE_OPERAND (expr, 0)),
-		   (TREE_OPERAND (expr, 1)
-		    ? build_non_dependent_expr (TREE_OPERAND (expr, 1))
-		    : build_non_dependent_expr (TREE_OPERAND (expr, 0))),
-		   build_non_dependent_expr (TREE_OPERAND (expr, 2)));
-  if (TREE_CODE (expr) == COMPOUND_EXPR)
-    return build2 (COMPOUND_EXPR,
-		   TREE_TYPE (expr),
-		   TREE_OPERAND (expr, 0),
-		   build_non_dependent_expr (TREE_OPERAND (expr, 1)));
-
-  /* If the type is unknown, it can't really be non-dependent */
-  gcc_assert (TREE_TYPE (expr) != unknown_type_node);
-
-  /* Otherwise, build a NON_DEPENDENT_EXPR.  */
-  return build1_loc (EXPR_LOCATION (orig_expr), NON_DEPENDENT_EXPR,
-		     TREE_TYPE (expr), expr);
-}
-
 /* ARGS is a vector of expressions as arguments to a function call.
    Replace the arguments with equivalent non-dependent expressions.
    This modifies ARGS in place.  */
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index eaf882f8854..a3d61d3e7c9 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -308,7 +308,6 @@ lvalue_kind (const_tree ref)
 	 its argument unmodified and we assign it to a const_tree.  */
       return lvalue_kind (BASELINK_FUNCTIONS (CONST_CAST_TREE (ref)));
 
-    case NON_DEPENDENT_EXPR:
     case PAREN_EXPR:
       return lvalue_kind (TREE_OPERAND (ref, 0));
 
@@ -412,10 +411,6 @@ cp_stabilize_reference (tree ref)
   STRIP_ANY_LOCATION_WRAPPER (ref);
   switch (TREE_CODE (ref))
     {
-    case NON_DEPENDENT_EXPR:
-      /* We aren't actually evaluating this.  */
-      return ref;
-
     /* We need to treat specially anything stabilize_reference doesn't
        handle specifically.  */
     case VAR_DECL:
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 8132bd7fccc..2cfa3c8a935 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -4844,9 +4844,6 @@ warn_for_null_address (location_t location, tree op, tsubst_flags_t complain)
       || warning_suppressed_p (op, OPT_Waddress))
     return;
 
-  if (TREE_CODE (op) == NON_DEPENDENT_EXPR)
-    op = TREE_OPERAND (op, 0);
-
   tree cop = fold_for_warn (op);
 
   if (TREE_CODE (cop) == NON_LVALUE_EXPR)
@@ -5405,7 +5402,9 @@ cp_build_binary_op (const op_location_t &location,
 	    type0 = TREE_TYPE (type0);
 	  if (!TYPE_P (type1))
 	    type1 = TREE_TYPE (type1);
-	  if (INDIRECT_TYPE_P (type0) && same_type_p (TREE_TYPE (type0), type1))
+	  if (type0
+	      && INDIRECT_TYPE_P (type0)
+	      && same_type_p (TREE_TYPE (type0), type1))
 	    {
 	      if (!(TREE_CODE (first_arg) == PARM_DECL
 		    && DECL_ARRAY_PARAMETER_P (first_arg)
@@ -5422,7 +5421,9 @@ cp_build_binary_op (const op_location_t &location,
 			      "first %<sizeof%> operand was declared here");
 		}
 	    }
-	  else if (TREE_CODE (type0) == ARRAY_TYPE
+	  else if (!dependent_type_p (type0)
+		   && !dependent_type_p (type1)
+		   && TREE_CODE (type0) == ARRAY_TYPE
 		   && !char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type0)))
 		   /* Set by finish_parenthesized_expr.  */
 		   && !warning_suppressed_p (op1, OPT_Wsizeof_array_div)
@@ -7399,6 +7400,8 @@ cp_build_unary_op (enum tree_code code, tree xarg, bool noconvert,
 					 complain);
       if (arg != error_mark_node)
 	{
+	  if (processing_template_decl)
+	    return build1_loc (location, TRUTH_NOT_EXPR, boolean_type_node, arg);
 	  val = invert_truthvalue_loc (location, arg);
 	  if (obvalue_p (val))
 	    val = non_lvalue_loc (location, val);
diff --git a/gcc/testsuite/g++.dg/concepts/var-concept3.C b/gcc/testsuite/g++.dg/concepts/var-concept3.C
index 6fd96a5042e..b4483ebca89 100644
--- a/gcc/testsuite/g++.dg/concepts/var-concept3.C
+++ b/gcc/testsuite/g++.dg/concepts/var-concept3.C
@@ -12,7 +12,7 @@ template<typename T>
 
 
 template<typename U>
-  requires C1<U>() // { dg-error "cannot be used as a function" }
+  requires C1<U>() // { dg-error "cannot call a concept" }
   void f1(U) { }
 
 template<typename U>
-- 
2.42.0.270.gbcb6cae296


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH] c++: merge tsubst_copy into tsubst_copy_and_build
  2023-09-25 20:43 ` [PATCH 2/2] c++: remove NON_DEPENDENT_EXPR, part 2 Patrick Palka
@ 2023-10-02 19:37   ` Patrick Palka
  2023-10-03 12:41     ` Patrick Palka
  2023-10-19 21:46   ` [PATCH 2/2] c++: remove NON_DEPENDENT_EXPR, part 2 Jason Merrill
  2023-10-20 15:57   ` Andrew Pinski
  2 siblings, 1 reply; 13+ messages in thread
From: Patrick Palka @ 2023-10-02 19:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: jason, Patrick Palka

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(-)

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


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] c++: merge tsubst_copy into tsubst_copy_and_build
  2023-10-02 19:37   ` [PATCH] c++: merge tsubst_copy into tsubst_copy_and_build Patrick Palka
@ 2023-10-03 12:41     ` Patrick Palka
  2023-10-03 21:57       ` Jason Merrill
  0 siblings, 1 reply; 13+ messages in thread
From: Patrick Palka @ 2023-10-03 12:41 UTC (permalink / raw)
  To: Patrick Palka; +Cc: gcc-patches, jason

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
> 
> 


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] c++: merge tsubst_copy into tsubst_copy_and_build
  2023-10-03 12:41     ` Patrick Palka
@ 2023-10-03 21:57       ` Jason Merrill
  2023-10-04 16:08         ` Patrick Palka
  0 siblings, 1 reply; 13+ messages in thread
From: Jason Merrill @ 2023-10-03 21:57 UTC (permalink / raw)
  To: Patrick Palka; +Cc: gcc-patches

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


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] c++: merge tsubst_copy into tsubst_copy_and_build
  2023-10-03 21:57       ` Jason Merrill
@ 2023-10-04 16:08         ` Patrick Palka
  2023-10-04 19:23           ` [PATCH 2/1] c++: rename tsubst_copy_and_build and tsubst_expr Patrick Palka
  2023-10-19 21:43           ` [PATCH] c++: merge tsubst_copy into tsubst_copy_and_build Jason Merrill
  0 siblings, 2 replies; 13+ messages in thread
From: Patrick Palka @ 2023-10-04 16:08 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Patrick Palka, gcc-patches

On Tue, 3 Oct 2023, Jason Merrill wrote:

> On 10/3/23 08:41, Patrick Palka wrote:
> > On Mon, 2 Oct 2023, Patrick Palka wrote:
> > 
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > > OK for trunk?
> > > 
> > > -- >8 --
> > > 
> > > The relationship between tsubst_copy_and_build and tsubst_copy (two of
> > > the main template argument substitution routines for expression trees)
> > > is rather hazy.  The former is mostly a superset of the latter, with
> > > some differences.
> > > 
> > > The main difference is that they handle many tree codes differently, but
> > > much of the tree code handling in tsubst_copy appears to be dead code[1].
> > > This is because tsubst_copy only gets directly called in a few places
> > > and mostly on id-expressions.  The interesting exceptions are PARM_DECL,
> > > VAR_DECL, BIT_NOT_EXPR, SCOPE_REF, TEMPLATE_ID_EXPR and IDENTIFIER_NODE:
> > > 
> > >   * for PARM_DECL and VAR_DECL, tsubst_copy_and_build calls tsubst_copy
> > >     followed by doing some extra handling of its own
> > >   * for BIT_NOT_EXPR tsubst_copy implicitly handles unresolved destructor
> > >     calls (i.e. the first operand is an identifier or a type)
> > >   * for SCOPE_REF, TEMPLATE_ID_EXPR and IDENTIFIER_NODE tsubst_copy
> > >     refrains from doing name lookup of the terminal name
> > > 
> > > Other more minor differences are that tsubst_copy exits early when
> > > 'args' is null, and it calls maybe_dependent_member_ref
> 
> That's curious, since what that function does seems like name lookup; I
> wouldn't think we would want to call it when tf_no_name_lookup.

Ah, that makes sense I think.

> 
> > > and finally it dispatches to tsubst for type trees.
> 
> And it looks like you fix the callers to avoid that?

Yes, I'll make a note of that in the commit message.

> 
> > > Thus tsubst_copy is (at this point) similar enough to
> > > tsubst_copy_and_build
> > > that it makes sense to merge the two functions, with the main difference
> > > being the name lookup behavior[2].  So this patch merges tsubst_copy into
> > > tsubst_copy_and_build via a new tsubst tf_no_name_lookup which controls
> > > name lookup and resolution of a (top-level) id-expression.
> > > 
> > > [1]: http://thrifty.mooo.com:8008/gcc-lcov/gcc/cp/pt.cc.gcov.html#17231
> > > [2]: I don't know the history of tsubst_copy but I would guess it was
> > > added before we settled on using processing_template_decl to control
> > > whether our AST building routines perform semantic checking and return
> > > non-templated trees, and so we needed a separate tsubst routine that
> > > avoids semantic checking and always returns a templated tree for e.g.
> > > partial substitution.
> > 
> > Oops, this is wrong -- tsubst_copy_and_build came after tsubst_copy,
> > and was introduced as an optimization with the intent of getting rid
> > of tsubst_copy eventually:
> > https://gcc.gnu.org/pipermail/gcc-patches/2003-January/093659.html
> 
> I wonder if we want to add a small tsubst_name wrapper to call
> tsubst_copy_and_build with tf_no_name_lookup?

Good idea, that'll complement tsubst_scope nicely.

> 
> Can we also merge in tsubst_expr and use that name instead of the unwieldy
> tsubst_copy_and_build?

That'd be nice.  Another idea would be to rename tsubst_expr to
tsubst_stmt and make it disjoint from tsubst_copy_and_build, and then
rename tsubst_copy_and_build to tsubst_expr, to draw a distinction
between statement-like trees (the substitution of which typically has
side effects like calling add_stmt) and expression-like trees (which
don't usually have such side effects).  I can work on that as a
follow-up patch.

Here's v2 which guards the call to maybe_dependent_member_ref and adds
tsubst_name, bootstrapped and regtested on x86_64-pc-linux-gnu:

-- >8 --

Subject: [PATCH] c++: merge tsubst_copy into tsubst_copy_and_build

gcc/cp/ChangeLog:

	* cp-tree.h (enum tsubst_flags): Add tf_no_name_lookup.
	* pt.cc (tsubst_copy):
	(tsubst_pack_expansion): Use tsubst for substituting BASES_TYPE.
	(tsubst_decl) <case USING_DECL>: Use tsubst_name instead of
	tsubst_copy.
	(tsubst) <case TEMPLATE_TYPE_PARM>: Use tsubst_copy_and_build
	instead of tsubst_copy for substituting
	CLASS_PLACEHOLDER_TEMPLATE.
	<case TYPENAME_TYPE>: Use tsubst_name instead of tsubst_copy for
	substituting TYPENAME_TYPE_FULLNAME.
	(tsubst_name): Define.
	(tsubst_qualified_id): Use tsubst_name instead of tsubst_copy
	for substituting the component name of a SCOPE_REF.
	(tsubst_copy): Remove.
	(tsubst_copy_and_build): Clear tf_no_name_lookup at the start,
	and remember if it was set.  Call maybe_dependent_member_ref if
	tf_no_name_lookup was not set.
	<case IDENTIFIER_NODE>: Don't do name lookup if tf_no_name_lookup
	was set.
	<case TEMPLATE_ID_EXPR>: If tf_no_name_lookup was set, use
	tsubst_name instead of tsubst_copy_and_build to substitute the
	template and don't finish the template-id.
	<case BIT_NOT_EXPR>: Handle identifier and type operand (if
	tf_no_name_lookup was set).
	<case SCOPE_REF>: Avoid trying to resolve a SCOPE_REF if
	tf_no_name_lookup was set by calling build_qualified_name directly
	instead of tsubst_qualified_id.
	<case SIZEOF_EXPR>: Handling of sizeof...  copied from tsubst_copy.
	<case CALL_EXPR>: Use tsubst_name instead of tsubst_copy to
	substitute a TEMPLATE_ID_EXPR callee naming an unresolved template.
	<case COMPONENT_REF>: Likewise to substitute the member.
	<case FUNCTION_DECL>: Copied from tsubst_copy and merged with ...
	<case VAR_DECL, PARM_DECL>: ... these.  Initial handling copied
	from tsubst_copy.  Optimize local variable substitution by
	trying retrieve_local_specialization before checking
	uses_template_parms.
	<case CONST_DECL>: Copied from tsubst_copy.
	<case FIELD_DECL>: Likewise.
	<case NAMESPACE_DECL>: Likewise.
	<case OVERLOAD>: Likewise.
	<case TEMPLATE_DECL>: Likewise.
	<case TEMPLATE_PARM_INDEX>: Likewise.
	<case TYPE_DECL>: Likewise.
	<case CLEANUP_POINT_EXPR>: Likewise.
	<case OFFSET_REF>: Likewise.
	<case EXPR_PACK_EXPANSION>: Likewise.
	<case NONTYPE_ARGUMENT_PACK>: Likewise.
	<case *_CST>: Likewise.
	<case *_*_FOLD_EXPR>: Likewise.
	<case DEBUG_BEGIN_STMT>: Likewise.
	<case CO_AWAIT_EXPR>: Likewise.
	<case TRAIT_EXPR>: Use tsubst and tsubst_copy_and_build instead
	of tsubst_copy.
	<default>: Copied from tsubst_copy.
	(tsubst_initializer_list): Use tsubst and tsubst_copy_and_build
	instead of tsubst_copy.
---
 gcc/cp/cp-tree.h |    3 +
 gcc/cp/pt.cc     | 1186 +++++++++++++++++-----------------------------
 2 files changed, 445 insertions(+), 744 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 8b9a7d58462..919eab34803 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5619,6 +5619,9 @@ enum tsubst_flags {
   tf_qualifying_scope = 1 << 14, /* Substituting the LHS of the :: operator.
 				    Affects TYPENAME_TYPE resolution from
 				    make_typename_type.  */
+  tf_no_name_lookup = 1 << 15, /* Don't look up the terminal name of an
+				  outermost id-expression, or resolve its
+				  constituent template-ids or qualified-ids.  */
   /* Convenient substitution flags combinations.  */
   tf_warning_or_error = tf_warning | tf_error
 };
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 4400d429b6f..e801a224d1b 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -204,9 +204,9 @@ static void copy_default_args_to_explicit_spec (tree);
 static bool invalid_nontype_parm_type_p (tree, tsubst_flags_t);
 static bool dependent_template_arg_p (tree);
 static bool dependent_type_p_r (tree);
-static tree tsubst_copy	(tree, tree, tsubst_flags_t, tree);
 static tree tsubst_decl (tree, tree, tsubst_flags_t, bool = true);
 static tree tsubst_scope (tree, tree, tsubst_flags_t, tree);
+static tree tsubst_name (tree, tree, tsubst_flags_t, tree);
 static void perform_instantiation_time_access_checks (tree, tree);
 static tree listify (tree);
 static tree listify_autos (tree, tree);
@@ -13373,15 +13373,11 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
       if (TREE_CODE (parm_pack) == BASES)
 	{
 	  gcc_assert (parm_pack == pattern);
+	  tree type = tsubst (BASES_TYPE (parm_pack), args, complain, in_decl);
 	  if (BASES_DIRECT (parm_pack))
-	    return calculate_direct_bases (tsubst_expr (BASES_TYPE (parm_pack),
-							args, complain,
-							in_decl),
-					   complain);
+	    return calculate_direct_bases (type, complain);
 	  else
-	    return calculate_bases (tsubst_expr (BASES_TYPE (parm_pack),
-						 args, complain, in_decl),
-				    complain);
+	    return calculate_bases (type, complain);
 	}
       else if (builtin_pack_call_p (parm_pack))
 	{
@@ -15171,7 +15167,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain,
 	      variadic_p = true;
 	    }
 	  else
-	    name = tsubst_copy (name, args, complain, in_decl);
+	    name = tsubst_name (name, args, complain, in_decl);
 
 	  int len;
 	  if (!variadic_p)
@@ -16108,7 +16104,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       if (template_placeholder_p (t))
 	{
 	  tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (t);
-	  tmpl = tsubst_copy (tmpl, args, complain, in_decl);
+	  tmpl = tsubst_copy_and_build (tmpl, args, complain, in_decl);
 	  if (TREE_CODE (tmpl) == TEMPLATE_TEMPLATE_PARM)
 	    tmpl = TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (tmpl);
 
@@ -16592,7 +16588,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	if (ctx == error_mark_node)
 	  return error_mark_node;
 
-	tree f = tsubst_copy (TYPENAME_TYPE_FULLNAME (t), args,
+	tree f = tsubst_name (TYPENAME_TYPE_FULLNAME (t), args,
 			      complain, in_decl);
 	if (f == error_mark_node)
 	  return error_mark_node;
@@ -16780,6 +16776,15 @@ tsubst_scope (tree t, tree args, tsubst_flags_t complain, tree in_decl)
   return tsubst (t, args, complain | tf_qualifying_scope, in_decl);
 }
 
+/* Convenience wrapper over tsubst for substituting into an id-expression
+   without resolving its terminal name.  */
+
+static tree
+tsubst_name (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+{
+  return tsubst_copy_and_build (t, args, complain | tf_no_name_lookup, in_decl);
+}
+
 /* OLDFNS is a lookup set of member functions from some class template, and
    NEWFNS is a lookup set of member functions from NEWTYPE, a specialization
    of that class template.  Return the subset of NEWFNS which are
@@ -17045,7 +17050,7 @@ tsubst_qualified_id (tree qualified_id, tree args,
   if (args)
     {
       scope = tsubst_scope (scope, args, complain, in_decl);
-      expr = tsubst_copy (name, args, complain, in_decl);
+      expr = tsubst_name (name, args, complain, in_decl);
     }
   else
     expr = name;
@@ -17277,707 +17282,6 @@ maybe_dependent_member_ref (tree t, tree args, tsubst_flags_t complain,
 				 TREE_CODE (t) == TEMPLATE_DECL);
 }
 
-/* Like tsubst, but deals with expressions.  This function just replaces
-   template parms; to finish processing the resultant expression, use
-   tsubst_copy_and_build or tsubst_expr.  */
-
-static tree
-tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
-{
-  enum tree_code code;
-  tree r;
-
-  if (t == NULL_TREE || t == error_mark_node || args == NULL_TREE)
-    return t;
-
-  if (TYPE_P (t))
-    return tsubst (t, args, complain, in_decl);
-
-  if (tree d = maybe_dependent_member_ref (t, args, complain, in_decl))
-    return d;
-
-  code = TREE_CODE (t);
-
-  switch (code)
-    {
-    case PARM_DECL:
-      r = retrieve_local_specialization (t);
-
-      if (r == NULL_TREE)
-	{
-	  /* We get here for a use of 'this' in an NSDMI.  */
-	  if (DECL_NAME (t) == this_identifier && current_class_ptr)
-	    return current_class_ptr;
-
-	  /* This can happen for a parameter name used later in a function
-	     declaration (such as in a late-specified return type).  Just
-	     make a dummy decl, since it's only used for its type.  */
-	  gcc_assert (cp_unevaluated_operand);
-	  r = tsubst_decl (t, args, complain);
-	  /* Give it the template pattern as its context; its true context
-	     hasn't been instantiated yet and this is good enough for
-	     mangling.  */
-	  DECL_CONTEXT (r) = DECL_CONTEXT (t);
-	}
-
-      if (TREE_CODE (r) == ARGUMENT_PACK_SELECT)
-	r = argument_pack_select_arg (r);
-      if (!mark_used (r, complain) && !(complain & tf_error))
-	return error_mark_node;
-      return r;
-
-    case CONST_DECL:
-      {
-	tree enum_type;
-	tree v;
-
-	if (DECL_TEMPLATE_PARM_P (t))
-	  return tsubst_copy (DECL_INITIAL (t), args, complain, in_decl);
-	if (!uses_template_parms (DECL_CONTEXT (t)))
-	  return t;
-
-	/* Unfortunately, we cannot just call lookup_name here.
-	   Consider:
-
-	     template <int I> int f() {
-	     enum E { a = I };
-	     struct S { void g() { E e = a; } };
-	     };
-
-	   When we instantiate f<7>::S::g(), say, lookup_name is not
-	   clever enough to find f<7>::a.  */
-	enum_type
-	  = tsubst_aggr_type (DECL_CONTEXT (t), args, complain, in_decl,
-			      /*entering_scope=*/0);
-
-	for (v = TYPE_VALUES (enum_type);
-	     v != NULL_TREE;
-	     v = TREE_CHAIN (v))
-	  if (TREE_PURPOSE (v) == DECL_NAME (t))
-	    return TREE_VALUE (v);
-
-	  /* We didn't find the name.  That should never happen; if
-	     name-lookup found it during preliminary parsing, we
-	     should find it again here during instantiation.  */
-	gcc_unreachable ();
-      }
-      return t;
-
-    case FIELD_DECL:
-      if (DECL_CONTEXT (t))
-	{
-	  tree ctx;
-
-	  ctx = tsubst_aggr_type (DECL_CONTEXT (t), args, complain, in_decl,
-				  /*entering_scope=*/1);
-	  if (ctx != DECL_CONTEXT (t))
-	    {
-	      tree r = lookup_field (ctx, DECL_NAME (t), 0, false);
-	      if (!r)
-		{
-		  if (complain & tf_error)
-		    error ("using invalid field %qD", t);
-		  return error_mark_node;
-		}
-	      return r;
-	    }
-	}
-
-      return t;
-
-    case VAR_DECL:
-    case FUNCTION_DECL:
-      if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t))
-	r = tsubst (t, args, complain, in_decl);
-      else if (DECL_LOCAL_DECL_P (t))
-	{
-	  /* Local specialization will usually have been created when
-	     we instantiated the DECL_EXPR_DECL. */
-	  r = retrieve_local_specialization (t);
-	  if (!r)
-	    {
-	      /* We're in a generic lambda referencing a local extern
-		 from an outer block-scope of a non-template.  */
-	      gcc_checking_assert (LAMBDA_FUNCTION_P (current_function_decl));
-	      r = t;
-	    }
-	}
-      else if (local_variable_p (t)
-	       && uses_template_parms (DECL_CONTEXT (t)))
-	{
-	  r = retrieve_local_specialization (t);
-	  if (r == NULL_TREE)
-	    {
-	      /* First try name lookup to find the instantiation.  */
-	      r = lookup_name (DECL_NAME (t));
-	      if (r)
-		{
-		  if (!VAR_P (r))
-		    {
-		      /* During error-recovery we may find a non-variable,
-			 even an OVERLOAD: just bail out and avoid ICEs and
-			 duplicate diagnostics (c++/62207).  */
-		      gcc_assert (seen_error ());
-		      return error_mark_node;
-		    }
-		  if (!is_capture_proxy (r))
-		    {
-		      /* Make sure the one we found is the one we want.  */
-		      tree ctx = enclosing_instantiation_of (DECL_CONTEXT (t));
-		      if (ctx != DECL_CONTEXT (r))
-			r = NULL_TREE;
-		    }
-		}
-
-	      if (r)
-		/* OK */;
-	      else
-		{
-		  /* This can happen for a variable used in a
-		     late-specified return type of a local lambda, or for a
-		     local static or constant.  Building a new VAR_DECL
-		     should be OK in all those cases.  */
-		  r = tsubst_decl (t, args, complain);
-		  if (local_specializations)
-		    /* Avoid infinite recursion (79640).  */
-		    register_local_specialization (r, t);
-		  if (decl_maybe_constant_var_p (r))
-		    {
-		      /* We can't call cp_finish_decl, so handle the
-			 initializer by hand.  */
-		      tree init = tsubst_init (DECL_INITIAL (t), r, args,
-					       complain, in_decl);
-		      if (!processing_template_decl)
-			init = maybe_constant_init (init);
-		      if (processing_template_decl
-			  ? potential_constant_expression (init)
-			  : reduced_constant_expression_p (init))
-			DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (r)
-			  = TREE_CONSTANT (r) = true;
-		      DECL_INITIAL (r) = init;
-		      if (tree auto_node = type_uses_auto (TREE_TYPE (r)))
-			TREE_TYPE (r)
-			  = do_auto_deduction (TREE_TYPE (r), init, auto_node,
-					       complain, adc_variable_type);
-		    }
-		  gcc_assert (cp_unevaluated_operand
-			      || processing_contract_condition
-			      || TREE_STATIC (r)
-			      || decl_constant_var_p (r)
-			      || seen_error ());
-		  if (!processing_template_decl
-		      && !TREE_STATIC (r))
-		    r = process_outer_var_ref (r, complain);
-		}
-	      /* Remember this for subsequent uses.  */
-	      if (local_specializations)
-		register_local_specialization (r, t);
-	    }
-	  if (TREE_CODE (r) == ARGUMENT_PACK_SELECT)
-	    r = argument_pack_select_arg (r);
-	}
-      else
-	r = t;
-      if (!mark_used (r, complain))
-	return error_mark_node;
-      return r;
-
-    case NAMESPACE_DECL:
-      return t;
-
-    case OVERLOAD:
-      return t;
-
-    case BASELINK:
-      return tsubst_baselink (t, current_nonlambda_class_type (),
-			      args, complain, in_decl);
-
-    case TEMPLATE_DECL:
-      if (DECL_TEMPLATE_TEMPLATE_PARM_P (t))
-	return tsubst (TREE_TYPE (DECL_TEMPLATE_RESULT (t)),
-		       args, complain, in_decl);
-      else if (DECL_FUNCTION_TEMPLATE_P (t) && DECL_MEMBER_TEMPLATE_P (t))
-	return tsubst (t, args, complain, in_decl);
-      else if (DECL_CLASS_SCOPE_P (t)
-	       && uses_template_parms (DECL_CONTEXT (t)))
-	{
-	  /* Template template argument like the following example need
-	     special treatment:
-
-	       template <template <class> class TT> struct C {};
-	       template <class T> struct D {
-		 template <class U> struct E {};
-		 C<E> c;				// #1
-	       };
-	       D<int> d;				// #2
-
-	     We are processing the template argument `E' in #1 for
-	     the template instantiation #2.  Originally, `E' is a
-	     TEMPLATE_DECL with `D<T>' as its DECL_CONTEXT.  Now we
-	     have to substitute this with one having context `D<int>'.  */
-
-	  tree context = tsubst_aggr_type (DECL_CONTEXT (t), args, complain,
-					   in_decl, /*entering_scope=*/true);
-	  return lookup_field (context, DECL_NAME(t), 0, false);
-	}
-      else
-	/* Ordinary template template argument.  */
-	return t;
-
-    case NON_LVALUE_EXPR:
-    case VIEW_CONVERT_EXPR:
-	{
-	  /* Handle location wrappers by substituting the wrapped node
-	     first, *then* reusing the resulting type.  Doing the type
-	     first ensures that we handle template parameters and
-	     parameter pack expansions.  */
-	  if (location_wrapper_p (t))
-	    {
-	      tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args,
-				      complain, in_decl);
-	      return maybe_wrap_with_location (op0, EXPR_LOCATION (t));
-	    }
-	  tree op = TREE_OPERAND (t, 0);
-	  /* force_paren_expr can also create a VIEW_CONVERT_EXPR.  */
-	  if (code == VIEW_CONVERT_EXPR && REF_PARENTHESIZED_P (t))
-	    {
-	      op = tsubst_copy (op, args, complain, in_decl);
-	      op = build1 (code, TREE_TYPE (op), op);
-	      REF_PARENTHESIZED_P (op) = true;
-	      return op;
-	    }
-	  /* We shouldn't see any other uses of these in templates
-	     (tsubst_copy_and_build handles C++20 tparm object wrappers).  */
-	  gcc_unreachable ();
-	}
-
-    case CAST_EXPR:
-    case REINTERPRET_CAST_EXPR:
-    case CONST_CAST_EXPR:
-    case STATIC_CAST_EXPR:
-    case DYNAMIC_CAST_EXPR:
-    case IMPLICIT_CONV_EXPR:
-    CASE_CONVERT:
-      {
-	tsubst_flags_t tcomplain = complain;
-	if (code == CAST_EXPR)
-	  tcomplain |= tf_tst_ok;
-	tree type = tsubst (TREE_TYPE (t), args, tcomplain, in_decl);
-	tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
-	return build1 (code, type, op0);
-      }
-
-    case BIT_CAST_EXPR:
-      {
-	tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
-	tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
-	r = build_min (BIT_CAST_EXPR, type, op0);
-	SET_EXPR_LOCATION (r, EXPR_LOCATION (t));
-	return r;
-      }
-
-    case SIZEOF_EXPR:
-      if (PACK_EXPANSION_P (TREE_OPERAND (t, 0))
-	  || ARGUMENT_PACK_P (TREE_OPERAND (t, 0)))
-        {
-          tree expanded, op = TREE_OPERAND (t, 0);
-	  int len = 0;
-
-	  if (SIZEOF_EXPR_TYPE_P (t))
-	    op = TREE_TYPE (op);
-
-	  ++cp_unevaluated_operand;
-	  ++c_inhibit_evaluation_warnings;
-	  /* We only want to compute the number of arguments.  */
-	  if (PACK_EXPANSION_P (op))
-	    expanded = tsubst_pack_expansion (op, args, complain, in_decl);
-	  else
-	    expanded = tsubst_template_args (ARGUMENT_PACK_ARGS (op),
-					     args, complain, in_decl);
-	  --cp_unevaluated_operand;
-	  --c_inhibit_evaluation_warnings;
-
-	  if (TREE_CODE (expanded) == TREE_VEC)
-	    {
-	      len = TREE_VEC_LENGTH (expanded);
-	      /* Set TREE_USED for the benefit of -Wunused.  */
-	      for (int i = 0; i < len; i++)
-		if (DECL_P (TREE_VEC_ELT (expanded, i)))
-		  TREE_USED (TREE_VEC_ELT (expanded, i)) = true;
-	    }
-
-	  if (expanded == error_mark_node)
-	    return error_mark_node;
-	  else if (PACK_EXPANSION_P (expanded)
-		   || (TREE_CODE (expanded) == TREE_VEC
-		       && pack_expansion_args_count (expanded)))
-
-	    {
-	      if (PACK_EXPANSION_P (expanded))
-		/* OK.  */;
-	      else if (TREE_VEC_LENGTH (expanded) == 1)
-		expanded = TREE_VEC_ELT (expanded, 0);
-	      else
-		expanded = make_argument_pack (expanded);
-
-	      if (TYPE_P (expanded))
-		return cxx_sizeof_or_alignof_type (input_location,
-						   expanded, SIZEOF_EXPR,
-						   false,
-						   complain & tf_error);
-	      else
-		return cxx_sizeof_or_alignof_expr (input_location,
-						   expanded, SIZEOF_EXPR,
-						   false,
-                                                   complain & tf_error);
-	    }
-	  else
-	    return build_int_cst (size_type_node, len);
-        }
-      if (SIZEOF_EXPR_TYPE_P (t))
-	{
-	  r = tsubst (TREE_TYPE (TREE_OPERAND (t, 0)),
-		      args, complain, in_decl);
-	  r = build1 (NOP_EXPR, r, error_mark_node);
-	  r = build1 (SIZEOF_EXPR,
-		      tsubst (TREE_TYPE (t), args, complain, in_decl), r);
-	  SIZEOF_EXPR_TYPE_P (r) = 1;
-	  return r;
-	}
-      /* Fall through */
-
-    case INDIRECT_REF:
-    case NEGATE_EXPR:
-    case TRUTH_NOT_EXPR:
-    case BIT_NOT_EXPR:
-    case ADDR_EXPR:
-    case UNARY_PLUS_EXPR:      /* Unary + */
-    case ALIGNOF_EXPR:
-    case AT_ENCODE_EXPR:
-    case ARROW_EXPR:
-    case THROW_EXPR:
-    case TYPEID_EXPR:
-    case REALPART_EXPR:
-    case IMAGPART_EXPR:
-    case PAREN_EXPR:
-      {
-	tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
-	tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
-	r = build1_loc (EXPR_LOCATION (t), code, type, op0);
-	if (code == ALIGNOF_EXPR)
-	  ALIGNOF_EXPR_STD_P (r) = ALIGNOF_EXPR_STD_P (t);
-	/* For addresses of immediate functions ensure we have EXPR_LOCATION
-	   set for possible later diagnostics.  */
-	if (code == ADDR_EXPR
-	    && EXPR_LOCATION (r) == UNKNOWN_LOCATION
-	    && TREE_CODE (op0) == FUNCTION_DECL
-	    && DECL_IMMEDIATE_FUNCTION_P (op0))
-	  SET_EXPR_LOCATION (r, input_location);
-	return r;
-      }
-
-    case EXCESS_PRECISION_EXPR:
-      {
-	tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
-	tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
-	if (TREE_CODE (op0) == EXCESS_PRECISION_EXPR)
-	  {
-	    gcc_checking_assert (same_type_p (type, TREE_TYPE (op0)));
-	    return op0;
-	  }
-	return build1_loc (EXPR_LOCATION (t), code, type, op0);
-      }
-
-    case COMPONENT_REF:
-      {
-	tree object;
-	tree name;
-
-	object = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
-	name = TREE_OPERAND (t, 1);
-	if (TREE_CODE (name) == BIT_NOT_EXPR)
-	  {
-	    name = tsubst_copy (TREE_OPERAND (name, 0), args,
-				complain, in_decl);
-	    name = build1 (BIT_NOT_EXPR, NULL_TREE, name);
-	  }
-	else if (TREE_CODE (name) == SCOPE_REF
-		 && TREE_CODE (TREE_OPERAND (name, 1)) == BIT_NOT_EXPR)
-	  {
-	    tree base = tsubst_copy (TREE_OPERAND (name, 0), args,
-				     complain, in_decl);
-	    name = TREE_OPERAND (name, 1);
-	    name = tsubst_copy (TREE_OPERAND (name, 0), args,
-				complain, in_decl);
-	    name = build1 (BIT_NOT_EXPR, NULL_TREE, name);
-	    name = build_qualified_name (/*type=*/NULL_TREE,
-					 base, name,
-					 /*template_p=*/false);
-	  }
-	else if (BASELINK_P (name))
-	  name = tsubst_baselink (name,
-				  non_reference (TREE_TYPE (object)),
-				  args, complain,
-				  in_decl);
-	else
-	  name = tsubst_copy (name, args, complain, in_decl);
-	return build_nt (COMPONENT_REF, object, name, NULL_TREE);
-      }
-
-    case PLUS_EXPR:
-    case MINUS_EXPR:
-    case MULT_EXPR:
-    case TRUNC_DIV_EXPR:
-    case CEIL_DIV_EXPR:
-    case FLOOR_DIV_EXPR:
-    case ROUND_DIV_EXPR:
-    case EXACT_DIV_EXPR:
-    case BIT_AND_EXPR:
-    case BIT_IOR_EXPR:
-    case BIT_XOR_EXPR:
-    case TRUNC_MOD_EXPR:
-    case FLOOR_MOD_EXPR:
-    case TRUTH_ANDIF_EXPR:
-    case TRUTH_ORIF_EXPR:
-    case TRUTH_AND_EXPR:
-    case TRUTH_OR_EXPR:
-    case RSHIFT_EXPR:
-    case LSHIFT_EXPR:
-    case EQ_EXPR:
-    case NE_EXPR:
-    case MAX_EXPR:
-    case MIN_EXPR:
-    case LE_EXPR:
-    case GE_EXPR:
-    case LT_EXPR:
-    case GT_EXPR:
-    case COMPOUND_EXPR:
-    case DOTSTAR_EXPR:
-    case MEMBER_REF:
-    case PREDECREMENT_EXPR:
-    case PREINCREMENT_EXPR:
-    case POSTDECREMENT_EXPR:
-    case POSTINCREMENT_EXPR:
-      {
-	tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
-	tree op1 = tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl);
-	return build_nt (code, op0, op1);
-      }
-
-    case SCOPE_REF:
-      {
-	tree op0 = tsubst_scope (TREE_OPERAND (t, 0), args, complain, in_decl);
-	tree op1 = tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl);
-	return build_qualified_name (/*type=*/NULL_TREE, op0, op1,
-				     QUALIFIED_NAME_IS_TEMPLATE (t));
-      }
-
-    case ARRAY_REF:
-      {
-	tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
-	tree op1 = tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl);
-	return build_nt (ARRAY_REF, op0, op1, NULL_TREE, NULL_TREE);
-      }
-
-    case CALL_EXPR:
-      {
-	int n = VL_EXP_OPERAND_LENGTH (t);
-	tree result = build_vl_exp (CALL_EXPR, n);
-	int i;
-	for (i = 0; i < n; i++)
-	  TREE_OPERAND (t, i) = tsubst_copy (TREE_OPERAND (t, i), args,
-					     complain, in_decl);
-	return result;
-      }
-
-    case COND_EXPR:
-    case MODOP_EXPR:
-    case PSEUDO_DTOR_EXPR:
-    case VEC_PERM_EXPR:
-      {
-	tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
-	tree op1 = tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl);
-	tree op2 = tsubst_copy (TREE_OPERAND (t, 2), args, complain, in_decl);
-	r = build_nt (code, op0, op1, op2);
-	copy_warning (r, t);
-	return r;
-      }
-
-    case NEW_EXPR:
-      {
-	tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
-	tree op1 = tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl);
-	tree op2 = tsubst_copy (TREE_OPERAND (t, 2), args, complain, in_decl);
-	r = build_nt (code, op0, op1, op2);
-	NEW_EXPR_USE_GLOBAL (r) = NEW_EXPR_USE_GLOBAL (t);
-	return r;
-      }
-
-    case DELETE_EXPR:
-      {
-	tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
-	tree op1 = tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl);
-	r = build_nt (code, op0, op1);
-	DELETE_EXPR_USE_GLOBAL (r) = DELETE_EXPR_USE_GLOBAL (t);
-	DELETE_EXPR_USE_VEC (r) = DELETE_EXPR_USE_VEC (t);
-	return r;
-      }
-
-    case TEMPLATE_ID_EXPR:
-      {
-	/* Substituted template arguments */
-	tree tmpl = TREE_OPERAND (t, 0);
-	tree targs = TREE_OPERAND (t, 1);
-
-	tmpl = tsubst_copy (tmpl, args, complain, in_decl);
-	if (targs)
-	  targs = tsubst_template_args (targs, args, complain, in_decl);
-
-	if (variable_template_p (tmpl))
-	  return lookup_template_variable (tmpl, targs, complain);
-	else
-	  return lookup_template_function (tmpl, targs);
-      }
-
-    case TREE_LIST:
-      {
-	tree purpose, value, chain;
-
-	if (t == void_list_node)
-	  return t;
-
-	purpose = TREE_PURPOSE (t);
-	if (purpose)
-	  purpose = tsubst_copy (purpose, args, complain, in_decl);
-	value = TREE_VALUE (t);
-	if (value)
-	  value = tsubst_copy (value, args, complain, in_decl);
-	chain = TREE_CHAIN (t);
-	if (chain && chain != void_type_node)
-	  chain = tsubst_copy (chain, args, complain, in_decl);
-	if (purpose == TREE_PURPOSE (t)
-	    && value == TREE_VALUE (t)
-	    && chain == TREE_CHAIN (t))
-	  return t;
-	return tree_cons (purpose, value, chain);
-      }
-
-    case TEMPLATE_PARM_INDEX:
-    case TYPE_DECL:
-      return tsubst (t, args, complain, in_decl);
-
-    case USING_DECL:
-      t = DECL_NAME (t);
-      /* Fall through.  */
-    case IDENTIFIER_NODE:
-      if (IDENTIFIER_CONV_OP_P (t))
-	{
-	  tree new_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
-	  return make_conv_op_name (new_type);
-	}
-      else
-	return t;
-
-    case CONSTRUCTOR:
-      /* This is handled by tsubst_copy_and_build.  */
-      gcc_unreachable ();
-
-    case VA_ARG_EXPR:
-      {
-	tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
-	tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
-	return build_x_va_arg (EXPR_LOCATION (t), op0, type);
-      }
-
-    case CLEANUP_POINT_EXPR:
-      /* We shouldn't have built any of these during initial template
-	 generation.  Instead, they should be built during instantiation
-	 in response to the saved STMT_IS_FULL_EXPR_P setting.  */
-      gcc_unreachable ();
-
-    case OFFSET_REF:
-      {
-	tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
-	tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
-	tree op1 = tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl);
-	r = build2 (code, type, op0, op1);
-	PTRMEM_OK_P (r) = PTRMEM_OK_P (t);
-	if (!mark_used (TREE_OPERAND (r, 1), complain)
-	    && !(complain & tf_error))
-	  return error_mark_node;
-	return r;
-      }
-
-    case EXPR_PACK_EXPANSION:
-      error ("invalid use of pack expansion expression");
-      return error_mark_node;
-
-    case NONTYPE_ARGUMENT_PACK:
-      error ("use %<...%> to expand argument pack");
-      return error_mark_node;
-
-    case VOID_CST:
-      gcc_checking_assert (t == void_node && VOID_TYPE_P (TREE_TYPE (t)));
-      return t;
-
-    case INTEGER_CST:
-    case REAL_CST:
-    case COMPLEX_CST:
-    case VECTOR_CST:
-      {
-	/* Instantiate any typedefs in the type.  */
-	tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
-	r = fold_convert (type, t);
-	gcc_assert (TREE_CODE (r) == code);
-	return r;
-      }
-
-    case STRING_CST:
-      {
-	tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
-	r = t;
-	if (type != TREE_TYPE (t))
-	  {
-	    r = copy_node (t);
-	    TREE_TYPE (r) = type;
-	  }
-	return r;
-      }
-
-    case PTRMEM_CST:
-      /* These can sometimes show up in a partial instantiation, but never
-	 involve template parms.  */
-      gcc_assert (!uses_template_parms (t));
-      return t;
-
-    case UNARY_LEFT_FOLD_EXPR:
-      return tsubst_unary_left_fold (t, args, complain, in_decl);
-    case UNARY_RIGHT_FOLD_EXPR:
-      return tsubst_unary_right_fold (t, args, complain, in_decl);
-    case BINARY_LEFT_FOLD_EXPR:
-      return tsubst_binary_left_fold (t, args, complain, in_decl);
-    case BINARY_RIGHT_FOLD_EXPR:
-      return tsubst_binary_right_fold (t, args, complain, in_decl);
-    case PREDICT_EXPR:
-      return t;
-
-    case DEBUG_BEGIN_STMT:
-      /* ??? There's no point in copying it for now, but maybe some
-	 day it will contain more information, such as a pointer back
-	 to the containing function, inlined copy or so.  */
-      return t;
-
-    case CO_AWAIT_EXPR:
-      return tsubst_expr (t, args, complain, in_decl);
-
-    default:
-      /* We shouldn't get here, but keep going if !flag_checking.  */
-      if (flag_checking)
-	gcc_unreachable ();
-      return t;
-    }
-}
-
 /* Helper function for tsubst_omp_clauses, used for instantiation of
    OMP_CLAUSE_DECL of clauses.  */
 
@@ -20420,6 +19724,15 @@ tsubst_copy_and_build (tree t,
   tsubst_flags_t decltype_flag = (complain & tf_decltype);
   complain &= ~tf_decltype;
 
+  /* This flag only applies to id-expressions at the top level, and
+     controls resolution thereof.  */
+  tsubst_flags_t no_name_lookup_flag = (complain & tf_no_name_lookup);
+  complain &= ~tf_no_name_lookup;
+
+  if (!no_name_lookup_flag)
+    if (tree d = maybe_dependent_member_ref (t, args, complain, in_decl))
+      return d;
+
   switch (TREE_CODE (t))
     {
     case USING_DECL:
@@ -20437,6 +19750,9 @@ tsubst_copy_and_build (tree t,
 	    t = make_conv_op_name (new_type);
 	  }
 
+	if (no_name_lookup_flag)
+	  RETURN (t);
+
 	/* Look up the name.  */
 	decl = lookup_name (t);
 
@@ -20470,10 +19786,14 @@ tsubst_copy_and_build (tree t,
     case TEMPLATE_ID_EXPR:
       {
 	tree object;
-	tree templ = tsubst_copy_and_build (TREE_OPERAND (t, 0), args,
-					    complain, in_decl);
+	tree templ = TREE_OPERAND (t, 0);
 	tree targs = TREE_OPERAND (t, 1);
 
+	if (no_name_lookup_flag)
+	  templ = tsubst_name (templ, args, complain, in_decl);
+	else
+	  templ = tsubst_copy_and_build (templ, args, complain, in_decl);
+
 	if (targs)
 	  targs = tsubst_template_args (targs, args, complain, in_decl);
 	if (targs == error_mark_node)
@@ -20505,6 +19825,9 @@ tsubst_copy_and_build (tree t,
 
 	if (variable_template_p (templ))
 	  {
+	    if (no_name_lookup_flag)
+	      RETURN (lookup_template_variable (templ, targs, complain));
+
 	    tree r = lookup_and_finish_template_variable (templ, targs,
 							  complain);
 	    r = convert_from_reference (r);
@@ -20526,6 +19849,8 @@ tsubst_copy_and_build (tree t,
 	if (object)
 	  RETURN (build3 (COMPONENT_REF, TREE_TYPE (tid),
 			 object, tid, NULL_TREE));
+	else if (no_name_lookup_flag)
+	  RETURN (tid);
 	else if (identifier_p (templ))
 	  {
 	    /* C++20 P0846: we can encounter an IDENTIFIER_NODE here when
@@ -20659,10 +19984,22 @@ tsubst_copy_and_build (tree t,
 				templated_operator_saved_lookups (t),
 				complain|decltype_flag));
 
+    case BIT_NOT_EXPR:
+      if (identifier_p (TREE_OPERAND (t, 0)))
+	{
+	  gcc_checking_assert (no_name_lookup_flag);
+	  RETURN (t);
+	}
+      else if (TYPE_P (TREE_OPERAND (t, 0)))
+	{
+	  gcc_checking_assert (no_name_lookup_flag);
+	  tree op0 = tsubst (TREE_OPERAND (t, 0), args, complain, in_decl);
+	  RETURN (build_min_nt_loc (EXPR_LOCATION (t), BIT_NOT_EXPR, op0));
+	}
+      /* Fall through.  */
     case PREDECREMENT_EXPR:
     case PREINCREMENT_EXPR:
     case NEGATE_EXPR:
-    case BIT_NOT_EXPR:
     case ABS_EXPR:
     case TRUTH_NOT_EXPR:
     case UNARY_PLUS_EXPR:  /* Unary + */
@@ -20779,8 +20116,16 @@ tsubst_copy_and_build (tree t,
       }
 
     case SCOPE_REF:
-      RETURN (tsubst_qualified_id (t, args, complain, in_decl, /*done=*/true,
-				  /*address_p=*/false));
+      if (no_name_lookup_flag)
+	{
+	  tree op0 = tsubst_scope (TREE_OPERAND (t, 0), args, complain, in_decl);
+	  tree op1 = tsubst_name (TREE_OPERAND (t, 1), args, complain, in_decl);
+	  RETURN (build_qualified_name (/*type=*/NULL_TREE, op0, op1,
+					QUALIFIED_NAME_IS_TEMPLATE (t)));
+	}
+      else
+	RETURN (tsubst_qualified_id (t, args, complain, in_decl, /*done=*/true,
+				    /*address_p=*/false));
 
     case BASELINK:
       RETURN (tsubst_baselink (t, current_nonlambda_class_type (),
@@ -20817,7 +20162,61 @@ tsubst_copy_and_build (tree t,
     case SIZEOF_EXPR:
       if (PACK_EXPANSION_P (TREE_OPERAND (t, 0))
 	  || ARGUMENT_PACK_P (TREE_OPERAND (t, 0)))
-	RETURN (tsubst_copy (t, args, complain, in_decl));
+	{
+	  tree expanded, op = TREE_OPERAND (t, 0);
+	  int len = 0;
+
+	  if (SIZEOF_EXPR_TYPE_P (t))
+	    op = TREE_TYPE (op);
+
+	  ++cp_unevaluated_operand;
+	  ++c_inhibit_evaluation_warnings;
+	  /* We only want to compute the number of arguments.  */
+	  if (PACK_EXPANSION_P (op))
+	    expanded = tsubst_pack_expansion (op, args, complain, in_decl);
+	  else
+	    expanded = tsubst_template_args (ARGUMENT_PACK_ARGS (op),
+					     args, complain, in_decl);
+	  --cp_unevaluated_operand;
+	  --c_inhibit_evaluation_warnings;
+
+	  if (TREE_CODE (expanded) == TREE_VEC)
+	    {
+	      len = TREE_VEC_LENGTH (expanded);
+	      /* Set TREE_USED for the benefit of -Wunused.  */
+	      for (int i = 0; i < len; i++)
+		if (DECL_P (TREE_VEC_ELT (expanded, i)))
+		  TREE_USED (TREE_VEC_ELT (expanded, i)) = true;
+	    }
+
+	  if (expanded == error_mark_node)
+	    RETURN (error_mark_node);
+	  else if (PACK_EXPANSION_P (expanded)
+		   || (TREE_CODE (expanded) == TREE_VEC
+		       && pack_expansion_args_count (expanded)))
+
+	    {
+	      if (PACK_EXPANSION_P (expanded))
+		/* OK.  */;
+	      else if (TREE_VEC_LENGTH (expanded) == 1)
+		expanded = TREE_VEC_ELT (expanded, 0);
+	      else
+		expanded = make_argument_pack (expanded);
+
+	      if (TYPE_P (expanded))
+		RETURN (cxx_sizeof_or_alignof_type (input_location,
+						    expanded, SIZEOF_EXPR,
+						    false,
+						    complain & tf_error));
+	      else
+		RETURN (cxx_sizeof_or_alignof_expr (input_location,
+						    expanded, SIZEOF_EXPR,
+						    false,
+						    complain & tf_error));
+	    }
+	  else
+	    RETURN (build_int_cst (size_type_node, len));
+	}
       /* Fall through */
 
     case ALIGNOF_EXPR:
@@ -21072,10 +20471,7 @@ tsubst_copy_and_build (tree t,
 	    qualified_p = false;
 
 	    if (TREE_CODE (function) == TEMPLATE_ID_EXPR)
-	      /* Use tsubst_copy to substitute through the template arguments
-		 of the template-id without performing unqualified lookup of
-		 the template name.  */
-	      function = tsubst_copy (function, args, complain, in_decl);
+	      function = tsubst_name (function, args, complain, in_decl);
 	  }
 	else
 	  {
@@ -21473,7 +20869,7 @@ tsubst_copy_and_build (tree t,
 				    non_reference (TREE_TYPE (object)),
 				    args, complain, in_decl);
 	else
-	  member = tsubst_copy (member, args, complain, in_decl);
+	  member = tsubst_name (member, args, complain, in_decl);
 	if (member == error_mark_node)
 	  RETURN (error_mark_node);
 
@@ -21682,29 +21078,321 @@ tsubst_copy_and_build (tree t,
 	  }
       }
 
+    case FUNCTION_DECL:
+    case PARM_DECL:
     case VAR_DECL:
       if (!args)
 	RETURN (t);
-      /* Fall through */
+      tree r;
+      if (VAR_OR_FUNCTION_DECL_P (t)
+	  && DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t))
+	r = tsubst_decl (t, args, complain);
+      else if (VAR_OR_FUNCTION_DECL_P (t) && DECL_LOCAL_DECL_P (t))
+	{
+	  /* Local specialization will usually have been created when
+	     we instantiated the DECL_EXPR_DECL. */
+	  r = retrieve_local_specialization (t);
+	  if (!r)
+	    {
+	      /* We're in a generic lambda referencing a local extern
+		 from an outer block-scope of a non-template.  */
+	      gcc_checking_assert (LAMBDA_FUNCTION_P (current_function_decl));
+	      r = t;
+	    }
+	}
+      else if (local_variable_p (t)
+	       && ((r = retrieve_local_specialization (t))
+		   || TREE_CODE (t) == PARM_DECL
+		   || uses_template_parms (DECL_CONTEXT (t))))
+	{
+	  if (r == NULL_TREE && TREE_CODE (t) == PARM_DECL)
+	    {
+	      /* We get here for a use of 'this' in an NSDMI.  */
+	      if (DECL_NAME (t) == this_identifier && current_class_ptr)
+		RETURN (current_class_ptr);
 
-    case PARM_DECL:
+	      /* This can happen for a parameter name used later in a function
+		 declaration (such as in a late-specified return type).  Just
+		 make a dummy decl, since it's only used for its type.  */
+	      gcc_assert (cp_unevaluated_operand);
+	      r = tsubst_decl (t, args, complain);
+	      /* Give it the template pattern as its context; its true context
+		 hasn't been instantiated yet and this is good enough for
+		 mangling.  */
+	      DECL_CONTEXT (r) = DECL_CONTEXT (t);
+	    }
+	  else if (r == NULL_TREE)
+	    {
+	      /* First try name lookup to find the instantiation.  */
+	      r = lookup_name (DECL_NAME (t));
+	      if (r)
+		{
+		  if (!VAR_P (r))
+		    {
+		      /* During error-recovery we may find a non-variable,
+			 even an OVERLOAD: just bail out and avoid ICEs and
+			 duplicate diagnostics (c++/62207).  */
+		      gcc_assert (seen_error ());
+		      RETURN (error_mark_node);
+		    }
+		  if (!is_capture_proxy (r))
+		    {
+		      /* Make sure the one we found is the one we want.  */
+		      tree ctx = enclosing_instantiation_of (DECL_CONTEXT (t));
+		      if (ctx != DECL_CONTEXT (r))
+			r = NULL_TREE;
+		    }
+		}
+
+	      if (r)
+		/* OK */;
+	      else
+		{
+		  /* This can happen for a variable used in a
+		     late-specified return type of a local lambda, or for a
+		     local static or constant.  Building a new VAR_DECL
+		     should be OK in all those cases.  */
+		  r = tsubst_decl (t, args, complain);
+		  if (local_specializations)
+		    /* Avoid infinite recursion (79640).  */
+		    register_local_specialization (r, t);
+		  if (decl_maybe_constant_var_p (r))
+		    {
+		      /* We can't call cp_finish_decl, so handle the
+			 initializer by hand.  */
+		      tree init = tsubst_init (DECL_INITIAL (t), r, args,
+					       complain, in_decl);
+		      if (!processing_template_decl)
+			init = maybe_constant_init (init);
+		      if (processing_template_decl
+			  ? potential_constant_expression (init)
+			  : reduced_constant_expression_p (init))
+			DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (r)
+			  = TREE_CONSTANT (r) = true;
+		      DECL_INITIAL (r) = init;
+		      if (tree auto_node = type_uses_auto (TREE_TYPE (r)))
+			TREE_TYPE (r)
+			  = do_auto_deduction (TREE_TYPE (r), init, auto_node,
+					       complain, adc_variable_type);
+		    }
+		  gcc_assert (cp_unevaluated_operand
+			      || processing_contract_condition
+			      || TREE_STATIC (r)
+			      || decl_constant_var_p (r)
+			      || seen_error ());
+		  if (!processing_template_decl
+		      && !TREE_STATIC (r))
+		    r = process_outer_var_ref (r, complain);
+		}
+	      /* Remember this for subsequent uses.  */
+	      if (local_specializations)
+		register_local_specialization (r, t);
+	    }
+	  if (TREE_CODE (r) == ARGUMENT_PACK_SELECT)
+	    r = argument_pack_select_arg (r);
+	}
+      else
+	r = t;
+      if (!mark_used (r, complain))
+	RETURN (error_mark_node);
+
+      if (!no_name_lookup_flag
+	  && (TREE_CODE (t) == PARM_DECL || TREE_CODE (t) == VAR_DECL))
+	{
+	  /* ??? We're doing a subset of finish_id_expression here.  */
+	  if (tree wrap = maybe_get_tls_wrapper_call (r))
+	    /* Replace an evaluated use of the thread_local variable with
+	       a call to its wrapper.  */
+	    r = wrap;
+	  else if (outer_automatic_var_p (r))
+	    r = process_outer_var_ref (r, complain);
+
+	  if (!TYPE_REF_P (TREE_TYPE (t)))
+	    /* If the original type was a reference, we'll be wrapped in
+	       the appropriate INDIRECT_REF.  */
+	    r = convert_from_reference (r);
+	}
+      RETURN (r);
+
+    case CONST_DECL:
       {
-	tree r = tsubst_copy (t, args, complain, in_decl);
-	/* ??? We're doing a subset of finish_id_expression here.  */
-	if (tree wrap = maybe_get_tls_wrapper_call (r))
-	  /* Replace an evaluated use of the thread_local variable with
-	     a call to its wrapper.  */
-	  r = wrap;
-	else if (outer_automatic_var_p (r))
-	  r = process_outer_var_ref (r, complain);
-
-	if (!TYPE_REF_P (TREE_TYPE (t)))
-	  /* If the original type was a reference, we'll be wrapped in
-	     the appropriate INDIRECT_REF.  */
-	  r = convert_from_reference (r);
+	tree enum_type;
+	tree v;
+
+	if (DECL_TEMPLATE_PARM_P (t))
+	  RETURN (RECUR (DECL_INITIAL (t)));
+	if (!uses_template_parms (DECL_CONTEXT (t)))
+	  RETURN (t);
+
+	/* Unfortunately, we cannot just call lookup_name here.
+	   Consider:
+
+	     template <int I> int f() {
+	     enum E { a = I };
+	     struct S { void g() { E e = a; } };
+	     };
+
+	   When we instantiate f<7>::S::g(), say, lookup_name is not
+	   clever enough to find f<7>::a.  */
+	enum_type
+	  = tsubst_aggr_type (DECL_CONTEXT (t), args, complain, in_decl,
+			      /*entering_scope=*/0);
+
+	for (v = TYPE_VALUES (enum_type);
+	     v != NULL_TREE;
+	     v = TREE_CHAIN (v))
+	  if (TREE_PURPOSE (v) == DECL_NAME (t))
+	    RETURN (TREE_VALUE (v));
+
+	  /* We didn't find the name.  That should never happen; if
+	     name-lookup found it during preliminary parsing, we
+	     should find it again here during instantiation.  */
+	gcc_unreachable ();
+	RETURN (t);
+      }
+
+    case FIELD_DECL:
+      if (DECL_CONTEXT (t))
+	{
+	  tree ctx;
+
+	  ctx = tsubst_aggr_type (DECL_CONTEXT (t), args, complain, in_decl,
+				  /*entering_scope=*/1);
+	  if (ctx != DECL_CONTEXT (t))
+	    {
+	      tree r = lookup_field (ctx, DECL_NAME (t), 0, false);
+	      if (!r)
+		{
+		  if (complain & tf_error)
+		    error ("using invalid field %qD", t);
+		  RETURN (error_mark_node);
+		}
+	      RETURN (r);
+	    }
+	}
+      RETURN (t);
+
+    case NAMESPACE_DECL:
+    case OVERLOAD:
+      RETURN (t);
+
+    case TEMPLATE_DECL:
+      if (DECL_TEMPLATE_TEMPLATE_PARM_P (t))
+	RETURN (tsubst (TREE_TYPE (DECL_TEMPLATE_RESULT (t)),
+			args, complain, in_decl));
+      else if (DECL_FUNCTION_TEMPLATE_P (t) && DECL_MEMBER_TEMPLATE_P (t))
+	RETURN (tsubst (t, args, complain, in_decl));
+      else if (DECL_CLASS_SCOPE_P (t)
+	       && uses_template_parms (DECL_CONTEXT (t)))
+	{
+	  /* Template template argument like the following example need
+	     special treatment:
+
+	       template <template <class> class TT> struct C {};
+	       template <class T> struct D {
+		 template <class U> struct E {};
+		 C<E> c;				// #1
+	       };
+	       D<int> d;				// #2
+
+	     We are processing the template argument `E' in #1 for
+	     the template instantiation #2.  Originally, `E' is a
+	     TEMPLATE_DECL with `D<T>' as its DECL_CONTEXT.  Now we
+	     have to substitute this with one having context `D<int>'.  */
+
+	  tree context = tsubst_aggr_type (DECL_CONTEXT (t), args, complain,
+					   in_decl, /*entering_scope=*/true);
+	  RETURN (lookup_field (context, DECL_NAME(t), 0, false));
+	}
+      else
+	/* Ordinary template template argument.  */
+	RETURN (t);
+
+    case TEMPLATE_PARM_INDEX:
+    case TYPE_DECL:
+      RETURN (tsubst (t, args, complain, in_decl));
+
+    case CLEANUP_POINT_EXPR:
+      /* We shouldn't have built any of these during initial template
+	 generation.  Instead, they should be built during instantiation
+	 in response to the saved STMT_IS_FULL_EXPR_P setting.  */
+      gcc_unreachable ();
+
+    case OFFSET_REF:
+      {
+	tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+	tree op0 = RECUR (TREE_OPERAND (t, 0));
+	tree op1 = RECUR (TREE_OPERAND (t, 1));
+	r = build2 (OFFSET_REF, type, op0, op1);
+	PTRMEM_OK_P (r) = PTRMEM_OK_P (t);
+	if (!mark_used (TREE_OPERAND (r, 1), complain)
+	    && !(complain & tf_error))
+	  RETURN (error_mark_node);
+	RETURN (r);
+      }
+
+    case EXPR_PACK_EXPANSION:
+      error ("invalid use of pack expansion expression");
+      RETURN (error_mark_node);
+
+    case NONTYPE_ARGUMENT_PACK:
+      error ("use %<...%> to expand argument pack");
+      RETURN (error_mark_node);
+
+    case VOID_CST:
+      gcc_checking_assert (t == void_node && VOID_TYPE_P (TREE_TYPE (t)));
+      RETURN (t);
+
+    case INTEGER_CST:
+    case REAL_CST:
+    case COMPLEX_CST:
+    case VECTOR_CST:
+      {
+	/* Instantiate any typedefs in the type.  */
+	tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+	r = fold_convert (type, t);
+	gcc_assert (TREE_CODE (r) == TREE_CODE (t));
+	RETURN (r);
+      }
+
+    case STRING_CST:
+      {
+	tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+	r = t;
+	if (type != TREE_TYPE (t))
+	  {
+	    r = copy_node (t);
+	    TREE_TYPE (r) = type;
+	  }
 	RETURN (r);
       }
 
+    case PTRMEM_CST:
+      /* These can sometimes show up in a partial instantiation, but never
+	 involve template parms.  */
+      gcc_assert (!uses_template_parms (t));
+      RETURN (t);
+
+    case UNARY_LEFT_FOLD_EXPR:
+      RETURN (tsubst_unary_left_fold (t, args, complain, in_decl));
+    case UNARY_RIGHT_FOLD_EXPR:
+      RETURN (tsubst_unary_right_fold (t, args, complain, in_decl));
+    case BINARY_LEFT_FOLD_EXPR:
+      RETURN (tsubst_binary_left_fold (t, args, complain, in_decl));
+    case BINARY_RIGHT_FOLD_EXPR:
+      RETURN (tsubst_binary_right_fold (t, args, complain, in_decl));
+    case PREDICT_EXPR:
+      RETURN (t);
+
+    case DEBUG_BEGIN_STMT:
+      /* ??? There's no point in copying it for now, but maybe some
+	 day it will contain more information, such as a pointer back
+	 to the containing function, inlined copy or so.  */
+      RETURN (t);
+
+    case CO_AWAIT_EXPR:
+      RETURN (tsubst_expr (t, args, complain, in_decl));
+
     case VA_ARG_EXPR:
       {
 	tree op0 = RECUR (TREE_OPERAND (t, 0));
@@ -21728,8 +21416,11 @@ tsubst_copy_and_build (tree t,
 
     case TRAIT_EXPR:
       {
-	tree type1 = tsubst_copy (TRAIT_EXPR_TYPE1 (t), args,
-				  complain, in_decl);
+	tree type1 = TRAIT_EXPR_TYPE1 (t);
+	if (TYPE_P (type1))
+	  type1 = tsubst (type1, args, complain, in_decl);
+	else
+	  type1 = tsubst_copy_and_build (type1, args, complain, in_decl);
 	tree type2 = tsubst (TRAIT_EXPR_TYPE2 (t), args,
 			     complain, in_decl);
 	RETURN (finish_trait_expr (TRAIT_EXPR_LOCATION (t),
@@ -21856,7 +21547,10 @@ tsubst_copy_and_build (tree t,
 	if (subst)
 	  RETURN (subst);
       }
-      RETURN (tsubst_copy (t, args, complain, in_decl));
+      /* We shouldn't get here, but keep going if !flag_checking.  */
+      if (flag_checking)
+	gcc_unreachable ();
+      RETURN (t);
     }
 
 #undef RECUR
@@ -27580,8 +27274,12 @@ tsubst_initializer_list (tree t, tree argvec)
           else
             {
 	      tree tmp;
-              decl = tsubst_copy (TREE_PURPOSE (t), argvec, 
-                                  tf_warning_or_error, NULL_TREE);
+	      if (TYPE_P (TREE_PURPOSE (t)))
+		decl = tsubst (TREE_PURPOSE (t), argvec,
+			       tf_warning_or_error, NULL_TREE);
+	      else
+		decl = tsubst_copy_and_build (TREE_PURPOSE (t), argvec,
+					      tf_warning_or_error, NULL_TREE);
 
               decl = expand_member_init (decl);
               if (decl && !DECL_P (decl))
-- 
2.42.0.307.gd0e8084c65


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 2/1] c++: rename tsubst_copy_and_build and tsubst_expr
  2023-10-04 16:08         ` Patrick Palka
@ 2023-10-04 19:23           ` Patrick Palka
  2023-10-19 21:43             ` Jason Merrill
  2023-10-19 21:43           ` [PATCH] c++: merge tsubst_copy into tsubst_copy_and_build Jason Merrill
  1 sibling, 1 reply; 13+ messages in thread
From: Patrick Palka @ 2023-10-04 19:23 UTC (permalink / raw)
  To: gcc-patches; +Cc: jason, Patrick Palka

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

-- >8 --

After the previous patch, we currently have two tsubst entry points
for expression trees: tsubst_copy_and_build and tsubst_expr.  But the
latter is just a superset of the former that also handles statement
trees.  We could merge the two entry points so that we just have
tsubst_expr, but it seems natural to distinguish statement trees from
expression trees and to maintain a separate entry point for them.

To that end, this this patch renames tsubst_copy_and_build to
tsubst_expr, and renames the current tsubst_expr to tsubst_stmt, which
continues to be a superset of the former (since sometimes expression
trees appear in statement contexts, e.g. a branch of an IF_STMT could be
NOP_EXPR).  Making tsubst_stmt disjoint from tsubst_expr is left as
future work (if deemed desirable).

This patch in turn renames suitable existing uses of tsubst_expr (that
expect to take statement trees) to use tsubst_stmt.  Thus untouched
tsubst_expr calls are implicitly strengthened to expect only expression
trees after this patch.  And since I'm not familiar with the
tsubst_omp_* routines this patch renames all tsubst_expr uses there to
tsubst_stmt to ensure no unintended functional change in that area.
This patch also moves the handling of CO_YIELD_EXPR and CO_AWAIT_EXPR
from tsubst_stmt to tsubst_expr since they're expression trees.

gcc/cp/ChangeLog:

	* cp-lang.cc (objcp_tsubst_copy_and_build): Rename to ...
	(objcp_tsubst_expr): ... this.
	* cp-objcp-common.h (objcp_tsubst_copy_and_build): Rename to ...
	(objcp_tsubst_expr): ... this.
	* cp-tree.h (tsubst_copy_and_build): Remove declaration.
	* init.cc (maybe_instantiate_nsdmi_init): Use tsubst_expr
	instead of tsubst_copy_and_build.
	* pt.cc (expand_integer_pack): Likewise.
	(instantiate_non_dependent_expr_internal): Likewise.
	(instantiate_class_template): Use tsubst_stmt instead of
	tsubst_expr for STATIC_ASSERT.
	(tsubst_function_decl): Adjust tsubst_copy_and_build uses.
	(tsubst_arg_types): Likewise.
	(tsubst_exception_specification): Likewise.
	(tsubst_tree_list): Likewise.
	(tsubst): Likewise.
	(tsubst_name): Likewise.
	(tsubst_omp_clause_decl): Use tsubst_stmt instead of tsubst_expr.
	(tsubst_omp_clauses): Likewise.
	(tsubst_copy_asm_operands): Adjust tsubst_copy_and_build use.
	(tsubst_omp_for_iterator): Use tsubst_stmt instead of tsubst_expr.
	(tsubst_expr): Rename to ...
	(tsubst_stmt): ... this.
	<case CO_YIELD_EXPR, CO_AWAIT_EXPR>: Move to tsubst_expr.
	(tsubst_omp_udr): Use tsubst_stmt instead of tsubst_expr.
	(tsubst_non_call_postfix_expression): Adjust tsubst_copy_and_build
	use.
	(tsubst_lambda_expr): Likewise.  Use tsubst_stmt instead of
	tsubst_expr for the body of a lambda.
	(tsubst_copy_and_build_call_args): Rename to ...
	(tsubst_call_args): ... this.  Adjust tsubst_copy_and_build use.
	(tsubst_copy_and_build): Rename to tsubst_expr.  Adjust
	tsubst_copy_and_build and tsubst_copy_and_build_call_args use.
	<case TRANSACTION_EXPR>: Use tsubst_stmt instead of tsubst_expr.
	(maybe_instantiate_noexcept): Adjust tsubst_copy_and_build use.
	(instantiate_body): Use tsubst_stmt instead of tsubst_expr for
	substituting the function body.
	(tsubst_initializer_list): Adjust tsubst_copy_and_build use.

gcc/objcp/ChangeLog:

	* objcp-lang.cc (objcp_tsubst_copy_and_build): Rename to ...
	(objcp_tsubst_expr): ... this.  Adjust tsubst_copy_and_build
	uses.
---
 gcc/cp/cp-lang.cc        |   6 +-
 gcc/cp/cp-objcp-common.h |   2 +-
 gcc/cp/cp-tree.h         |   1 -
 gcc/cp/init.cc           |   3 +-
 gcc/cp/pt.cc             | 177 +++++++++++++++++----------------------
 gcc/objcp/objcp-lang.cc  |   5 +-
 6 files changed, 85 insertions(+), 109 deletions(-)

diff --git a/gcc/cp/cp-lang.cc b/gcc/cp/cp-lang.cc
index 2f541460c4a..f2ed83de4fb 100644
--- a/gcc/cp/cp-lang.cc
+++ b/gcc/cp/cp-lang.cc
@@ -113,10 +113,8 @@ struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
 /* The following function does something real, but only in Objective-C++.  */
 
 tree
-objcp_tsubst_copy_and_build (tree /*t*/,
-			     tree /*args*/,
-			     tsubst_flags_t /*complain*/,
-			     tree /*in_decl*/)
+objcp_tsubst_expr (tree /*t*/, tree /*args*/, tsubst_flags_t /*complain*/,
+		   tree /*in_decl*/)
 {
   return NULL_TREE;
 }
diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h
index 80893aa1752..1408301a300 100644
--- a/gcc/cp/cp-objcp-common.h
+++ b/gcc/cp/cp-objcp-common.h
@@ -24,7 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 /* In cp/objcp-common.c, cp/cp-lang.cc and objcp/objcp-lang.cc.  */
 
 extern tree cp_get_debug_type (const_tree);
-extern tree objcp_tsubst_copy_and_build (tree, tree, tsubst_flags_t, tree);
+extern tree objcp_tsubst_expr (tree, tree, tsubst_flags_t, tree);
 
 extern int cp_decl_dwarf_attribute (const_tree, int);
 extern int cp_type_dwarf_attribute (const_tree, int);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 919eab34803..4b463f12c0c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7458,7 +7458,6 @@ extern void instantiate_pending_templates	(int);
 extern tree tsubst_default_argument		(tree, int, tree, tree,
 						 tsubst_flags_t);
 extern tree tsubst (tree, tree, tsubst_flags_t, tree);
-extern tree tsubst_copy_and_build		(tree, tree, tsubst_flags_t, tree);
 extern tree tsubst_expr                         (tree, tree, tsubst_flags_t, tree);
 extern tree tsubst_pack_expansion		(tree, tree, tsubst_flags_t, tree);
 extern tree tsubst_argument_pack		(tree, tree, tsubst_flags_t, tree);
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index d1bae3b155f..d48bb16c7c5 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -621,8 +621,7 @@ maybe_instantiate_nsdmi_init (tree member, tsubst_flags_t complain)
 	  start_lambda_scope (member);
 
 	  /* Do deferred instantiation of the NSDMI.  */
-	  init = tsubst_copy_and_build (init, DECL_TI_ARGS (member),
-					complain, member);
+	  init = tsubst_expr (init, DECL_TI_ARGS (member), complain, member);
 	  init = digest_nsdmi_init (member, init, complain);
 
 	  finish_lambda_scope ();
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index e801a224d1b..837e81eea83 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -204,6 +204,7 @@ 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_stmt (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);
@@ -3763,7 +3764,7 @@ expand_integer_pack (tree call, tree args, tsubst_flags_t complain,
 		     tree in_decl)
 {
   tree ohi = CALL_EXPR_ARG (call, 0);
-  tree hi = tsubst_copy_and_build (ohi, args, complain, in_decl);
+  tree hi = tsubst_expr (ohi, args, complain, in_decl);
 
   if (instantiation_dependent_expression_p (hi))
     {
@@ -3771,7 +3772,7 @@ expand_integer_pack (tree call, tree args, tsubst_flags_t complain,
 	{
 	  /* Work around maybe_convert_nontype_argument not doing this for
 	     dependent arguments.  Don't use IMPLICIT_CONV_EXPR_NONTYPE_ARG
-	     because that will make tsubst_copy_and_build ignore it.  */
+	     because that will make tsubst_expr ignore it.  */
 	  tree type = tsubst (TREE_TYPE (ohi), args, complain, in_decl);
 	  if (!TREE_TYPE (hi) || !same_type_p (type, TREE_TYPE (hi)))
 	    hi = build1 (IMPLICIT_CONV_EXPR, type, hi);
@@ -6423,10 +6424,7 @@ redeclare_class_template (tree type, tree parms, tree cons)
 tree
 instantiate_non_dependent_expr_internal (tree expr, tsubst_flags_t complain)
 {
-  return tsubst_copy_and_build (expr,
-				/*args=*/NULL_TREE,
-				complain,
-				/*in_decl=*/NULL_TREE);
+  return tsubst_expr (expr, /*args=*/NULL_TREE, complain, /*in_decl=*/NULL_TREE);
 }
 
 /* Instantiate the non-dependent expression EXPR.  */
@@ -12367,7 +12365,7 @@ instantiate_class_template (tree type)
 	    {
 	      /* Build new TYPE_FIELDS.  */
               if (TREE_CODE (t) == STATIC_ASSERT)
-		tsubst_expr (t, args, tf_warning_or_error, NULL_TREE);
+		tsubst_stmt (t, args, tf_warning_or_error, NULL_TREE);
 	      else if (TREE_CODE (t) != CONST_DECL)
 		{
 		  tree r;
@@ -14455,7 +14453,7 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain,
   if (DECL_HAS_DEPENDENT_EXPLICIT_SPEC_P (t))
     {
       tree spec = lookup_explicit_specifier (t);
-      spec = tsubst_copy_and_build (spec, args, complain, in_decl);
+      spec = tsubst_expr (spec, args, complain, in_decl);
       spec = build_explicit_specifier (spec, complain);
       if (spec == error_mark_node)
 	return error_mark_node;
@@ -15584,7 +15582,7 @@ tsubst_arg_types (tree arg_types,
   if (lambda_fn_in_template_p (in_decl)
       || (in_decl && TREE_CODE (in_decl) == FUNCTION_DECL
 	  && DECL_LOCAL_DECL_P (in_decl)))
-    default_arg = tsubst_copy_and_build (default_arg, args, complain, in_decl);
+    default_arg = tsubst_expr (default_arg, args, complain, in_decl);
 
   tree remaining_arg_types = tsubst_arg_types (TREE_CHAIN (arg_types),
 					       args, end, complain, in_decl);
@@ -15765,7 +15763,7 @@ tsubst_exception_specification (tree fntype,
 					   args);
 	      expr = DEFERRED_NOEXCEPT_PATTERN (expr);
 	    }
-	  new_specs = tsubst_copy_and_build (expr, args, complain, in_decl);
+	  new_specs = tsubst_expr (expr, args, complain, in_decl);
 	}
       new_specs = build_noexcept_spec (new_specs, complain);
       /* We've instantiated a template before a noexcept-specifier
@@ -15862,7 +15860,7 @@ tsubst_tree_list (tree t, tree args, tsubst_flags_t complain, tree in_decl)
   else if (TYPE_P (purpose))
     purpose = tsubst (purpose, args, complain, in_decl);
   else
-    purpose = tsubst_copy_and_build (purpose, args, complain, in_decl);
+    purpose = tsubst_expr (purpose, args, complain, in_decl);
   if (purpose == error_mark_node || purposevec == error_mark_node)
     return error_mark_node;
 
@@ -15879,7 +15877,7 @@ tsubst_tree_list (tree t, tree args, tsubst_flags_t complain, tree in_decl)
   else if (TYPE_P (value))
     value = tsubst (value, args, complain, in_decl);
   else
-    value = tsubst_copy_and_build (value, args, complain, in_decl);
+    value = tsubst_expr (value, args, complain, in_decl);
   if (value == error_mark_node || valuevec == error_mark_node)
     return error_mark_node;
 
@@ -15891,7 +15889,7 @@ tsubst_tree_list (tree t, tree args, tsubst_flags_t complain, tree in_decl)
   else if (TYPE_P (chain))
     chain = tsubst (chain, args, complain, in_decl);
   else
-    chain = tsubst_copy_and_build (chain, args, complain, in_decl);
+    chain = tsubst_expr (chain, args, complain, in_decl);
   if (chain == error_mark_node)
     return error_mark_node;
 
@@ -16104,7 +16102,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_and_build (tmpl, args, complain, in_decl);
+	  tmpl = tsubst_expr (tmpl, args, complain, in_decl);
 	  if (TREE_CODE (tmpl) == TEMPLATE_TEMPLATE_PARM)
 	    tmpl = TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (tmpl);
 
@@ -16696,8 +16694,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	++cp_unevaluated_operand;
 	++c_inhibit_evaluation_warnings;
 
-	type = tsubst_copy_and_build (DECLTYPE_TYPE_EXPR (t), args,
-				      complain|tf_decltype, in_decl);
+	type = tsubst_expr (DECLTYPE_TYPE_EXPR (t), args,
+			    complain|tf_decltype, in_decl);
 
 	--cp_unevaluated_operand;
 	--c_inhibit_evaluation_warnings;
@@ -16732,7 +16730,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	if (TYPE_P (type1))
 	  type1 = tsubst (type1, args, complain, in_decl);
 	else
-	  type1 = tsubst_copy_and_build (type1, args, complain, in_decl);
+	  type1 = tsubst_expr (type1, args, complain, in_decl);
 	tree type2 = tsubst (TRAIT_TYPE_TYPE2 (t), args, complain, in_decl);
 	type = finish_trait_type (TRAIT_TYPE_KIND (t), type1, type2, complain);
 	return cp_build_qualified_type (type,
@@ -16782,7 +16780,7 @@ tsubst_scope (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 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);
+  return tsubst_expr (t, args, complain | tf_no_name_lookup, in_decl);
 }
 
 /* OLDFNS is a lookup set of member functions from some class template, and
@@ -17312,11 +17310,11 @@ tsubst_omp_clause_decl (tree decl, tree args, tsubst_flags_t 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);
+		= tsubst_stmt (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);
+		= tsubst_stmt (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);
+		= tsubst_stmt (TREE_VEC_ELT (it, 3), args, complain, in_decl);
 	      TREE_CHAIN (*tp) = NULL_TREE;
 	      tp = &TREE_CHAIN (*tp);
 	    }
@@ -17338,8 +17336,8 @@ tsubst_omp_clause_decl (tree decl, tree args, tsubst_flags_t complain,
   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);
+	= tsubst_stmt (TREE_PURPOSE (decl), args, complain, in_decl);
+      tree length = tsubst_stmt (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
@@ -17351,7 +17349,7 @@ tsubst_omp_clause_decl (tree decl, tree args, tsubst_flags_t complain,
 	= OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (decl);
       return ret;
     }
-  tree ret = tsubst_expr (decl, args, complain, in_decl);
+  tree ret = tsubst_stmt (decl, args, complain, in_decl);
   /* Undo convert_from_reference tsubst_expr could have called.  */
   if (decl
       && REFERENCE_REF_P (ret)
@@ -17382,7 +17380,7 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
 	  if (OMP_CLAUSE_LASTPRIVATE_STMT (oc))
 	    {
 	      OMP_CLAUSE_LASTPRIVATE_STMT (nc) = push_stmt_list ();
-	      tsubst_expr (OMP_CLAUSE_LASTPRIVATE_STMT (oc), args,
+	      tsubst_stmt (OMP_CLAUSE_LASTPRIVATE_STMT (oc), args,
 			   complain, in_decl);
 	      OMP_CLAUSE_LASTPRIVATE_STMT (nc)
 		= pop_stmt_list (OMP_CLAUSE_LASTPRIVATE_STMT (nc));
@@ -17415,7 +17413,7 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
 	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,
+	      = tsubst_stmt (OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (oc), args,
 			     complain, in_decl);
 	  /* FALLTHRU */
 	case OMP_CLAUSE_TILE:
@@ -17444,7 +17442,7 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
 	case OMP_CLAUSE_WAIT:
 	case OMP_CLAUSE_DETACH:
 	  OMP_CLAUSE_OPERAND (nc, 0)
-	    = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain, in_decl);
+	    = tsubst_stmt (OMP_CLAUSE_OPERAND (oc, 0), args, complain, in_decl);
 	  break;
 	case OMP_CLAUSE_REDUCTION:
 	case OMP_CLAUSE_IN_REDUCTION:
@@ -17474,16 +17472,16 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
 	    = tsubst_omp_clause_decl (OMP_CLAUSE_DECL (oc), args, complain,
 				      in_decl, NULL);
 	  OMP_CLAUSE_OPERAND (nc, 1)
-	    = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 1), args, complain, in_decl);
+	    = tsubst_stmt (OMP_CLAUSE_OPERAND (oc, 1), args, complain, in_decl);
 	  break;
 	case OMP_CLAUSE_ALLOCATE:
 	  OMP_CLAUSE_DECL (nc)
 	    = tsubst_omp_clause_decl (OMP_CLAUSE_DECL (oc), args, complain,
 				      in_decl, NULL);
 	  OMP_CLAUSE_OPERAND (nc, 1)
-	    = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 1), args, complain, in_decl);
+	    = tsubst_stmt (OMP_CLAUSE_OPERAND (oc, 1), args, complain, in_decl);
 	  OMP_CLAUSE_OPERAND (nc, 2)
-	    = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 2), args, complain, in_decl);
+	    = tsubst_stmt (OMP_CLAUSE_OPERAND (oc, 2), args, complain, in_decl);
 	  break;
 	case OMP_CLAUSE_LINEAR:
 	  OMP_CLAUSE_DECL (nc)
@@ -17500,7 +17498,7 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
 					complain, in_decl, NULL);
 	  else
 	    OMP_CLAUSE_LINEAR_STEP (nc)
-	      = tsubst_expr (OMP_CLAUSE_LINEAR_STEP (oc), args,
+	      = tsubst_stmt (OMP_CLAUSE_LINEAR_STEP (oc), args,
 			     complain, in_decl);
 	  break;
 	case OMP_CLAUSE_NOWAIT:
@@ -17612,7 +17610,7 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
   return new_clauses;
 }
 
-/* Like tsubst_copy_and_build, but unshare TREE_LIST nodes.  */
+/* Like tsubst_expr, but unshare TREE_LIST nodes.  */
 
 static tree
 tsubst_copy_asm_operands (tree t, tree args, tsubst_flags_t complain,
@@ -17626,7 +17624,7 @@ tsubst_copy_asm_operands (tree t, tree args, tsubst_flags_t complain,
     return t;
 
   if (TREE_CODE (t) != TREE_LIST)
-    return tsubst_copy_and_build (t, args, complain, in_decl);
+    return tsubst_expr (t, args, complain, in_decl);
 
   if (t == void_list_node)
     return t;
@@ -17670,7 +17668,7 @@ tsubst_omp_for_iterator (tree t, int i, tree declv, tree &orig_declv,
 			 tree args, tsubst_flags_t complain, tree in_decl)
 {
 #define RECUR(NODE)				\
-  tsubst_expr ((NODE), args, complain, in_decl)
+  tsubst_stmt ((NODE), args, complain, in_decl)
   tree decl, init, cond = NULL_TREE, incr = NULL_TREE;
   bool ret = false;
 
@@ -18153,15 +18151,14 @@ dependent_operand_p (tree t)
   return r;
 }
 
-/* Like tsubst_copy for expressions, etc. but also does semantic
-   processing.  */
+/* A superset of tsubst_expr that also handles statement trees.  */
 
-tree
-tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+static tree
+tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 {
 #define RETURN(EXP) do { r = (EXP); goto out; } while(0)
 #define RECUR(NODE)				\
-  tsubst_expr ((NODE), args, complain, in_decl)
+  tsubst_stmt ((NODE), args, complain, in_decl)
 
   tree stmt, tmp;
   tree r;
@@ -18198,16 +18195,6 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       finish_co_return_stmt (input_location, RECUR (TREE_OPERAND (t, 0)));
       break;
 
-    case CO_YIELD_EXPR:
-      stmt = finish_co_yield_expr (input_location,
-				   RECUR (TREE_OPERAND (t, 0)));
-      RETURN (stmt);
-
-    case CO_AWAIT_EXPR:
-      stmt = finish_co_await_expr (input_location,
-				   RECUR (TREE_OPERAND (t, 0)));
-      RETURN (stmt);
-
     case EXPR_STMT:
       tmp = RECUR (EXPR_STMT_EXPR (t));
       if (EXPR_STMT_STMT_EXPR_RESULT (t))
@@ -19228,7 +19215,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
     default:
       gcc_assert (!STATEMENT_CODE_P (TREE_CODE (t)));
 
-      RETURN (tsubst_copy_and_build (t, args, complain, in_decl));
+      RETURN (tsubst_expr (t, args, complain, in_decl));
     }
 
   RETURN (NULL_TREE);
@@ -19275,7 +19262,7 @@ tsubst_omp_udr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       DECL_CONTEXT (omp_in) = current_function_decl;
       keep_next_level (true);
       tree block = begin_omp_structured_block ();
-      tsubst_expr (stmts[2], args, complain, in_decl);
+      tsubst_stmt (stmts[2], args, complain, in_decl);
       block = finish_omp_structured_block (block);
       block = maybe_cleanup_point_expr_void (block);
       add_decl_expr (omp_out);
@@ -19295,7 +19282,7 @@ tsubst_omp_udr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       DECL_CONTEXT (omp_orig) = current_function_decl;
       keep_next_level (true);
       tree block = begin_omp_structured_block ();
-      tsubst_expr (stmts[5], args, complain, in_decl);
+      tsubst_stmt (stmts[5], args, complain, in_decl);
       block = finish_omp_structured_block (block);
       block = maybe_cleanup_point_expr_void (block);
       cp_walk_tree (&block, cp_remove_omp_priv_cleanup_stmt, omp_priv, NULL);
@@ -19319,7 +19306,7 @@ tsubst_non_call_postfix_expression (tree t, tree args,
     t = tsubst_qualified_id (t, args, complain, in_decl,
 			     /*done=*/false, /*address_p=*/false);
   else
-    t = tsubst_copy_and_build (t, args, complain, in_decl);
+    t = tsubst_expr (t, args, complain, in_decl);
 
   return t;
 }
@@ -19392,7 +19379,7 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       if (PACK_EXPANSION_P (init))
 	init = tsubst_pack_expansion (init, args, complain, in_decl);
       else
-	init = tsubst_copy_and_build (init, args, complain, in_decl);
+	init = tsubst_expr (init, args, complain, in_decl);
 
       if (init == error_mark_node)
 	return error_mark_node;
@@ -19572,7 +19559,7 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	   need another to confuse NRV (91217).  */
 	saved = BIND_EXPR_BODY (saved);
 
-      tsubst_expr (saved, args, complain, r);
+      tsubst_stmt (saved, args, complain, r);
 
       finish_lambda_function (body);
 
@@ -19657,12 +19644,11 @@ maybe_fold_fn_template_args (tree fn, tsubst_flags_t complain)
   return fold_targs_r (targs, complain);
 }
 
-/* Helper function for tsubst_copy_and_build CALL_EXPR and ARRAY_REF
-   handling.  */
+/* Helper function for tsubst_expr CALL_EXPR and ARRAY_REF handling.  */
 
 static void
-tsubst_copy_and_build_call_args (tree t, tree args, tsubst_flags_t complain,
-				 tree in_decl, releasing_vec &call_args)
+tsubst_call_args (tree t, tree args, tsubst_flags_t complain,
+		  tree in_decl, releasing_vec &call_args)
 {
   unsigned int nargs = call_expr_nargs (t);
   for (unsigned int i = 0; i < nargs; ++i)
@@ -19670,8 +19656,7 @@ tsubst_copy_and_build_call_args (tree t, tree args, tsubst_flags_t complain,
       tree arg = CALL_EXPR_ARG (t, i);
 
       if (!PACK_EXPANSION_P (arg))
-	vec_safe_push (call_args,
-		       tsubst_copy_and_build (arg, args, complain, in_decl));
+	vec_safe_push (call_args, tsubst_expr (arg, args, complain, in_decl));
       else
 	{
 	  /* Expand the pack expansion and push each entry onto CALL_ARGS.  */
@@ -19700,14 +19685,11 @@ tsubst_copy_and_build_call_args (tree t, tree args, tsubst_flags_t complain,
    analysis.  */
 
 tree
-tsubst_copy_and_build (tree t,
-		       tree args,
-		       tsubst_flags_t complain,
-		       tree in_decl)
+tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 {
 #define RETURN(EXP) do { retval = (EXP); goto out; } while(0)
 #define RECUR(NODE)						\
-  tsubst_copy_and_build (NODE, args, complain, in_decl)
+  tsubst_expr (NODE, args, complain, in_decl)
 
   tree retval, op1;
   location_t save_loc;
@@ -19792,7 +19774,7 @@ tsubst_copy_and_build (tree t,
 	if (no_name_lookup_flag)
 	  templ = tsubst_name (templ, args, complain, in_decl);
 	else
-	  templ = tsubst_copy_and_build (templ, args, complain, in_decl);
+	  templ = tsubst_expr (templ, args, complain, in_decl);
 
 	if (targs)
 	  targs = tsubst_template_args (targs, args, complain, in_decl);
@@ -20140,8 +20122,7 @@ tsubst_copy_and_build (tree t,
 	{
 	  tree c = TREE_OPERAND (t, 1);
 	  releasing_vec index_exp_list;
-	  tsubst_copy_and_build_call_args (c, args, complain, in_decl,
-					   index_exp_list);
+	  tsubst_call_args (c, args, complain, in_decl, index_exp_list);
 
 	  tree r;
 	  if (vec_safe_length (index_exp_list) == 1
@@ -20243,7 +20224,7 @@ tsubst_copy_and_build (tree t,
 	    if (TYPE_P (op1))
 	      op1 = tsubst (op1, args, complain, in_decl);
 	    else
-	      op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
+	      op1 = tsubst_expr (op1, args, complain, in_decl);
 	    --cp_unevaluated_operand;
 	    --c_inhibit_evaluation_warnings;
 	  }
@@ -20280,7 +20261,7 @@ tsubst_copy_and_build (tree t,
 	op1 = TREE_OPERAND (t, 0);
 	++cp_unevaluated_operand;
 	++c_inhibit_evaluation_warnings;
-	op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
+	op1 = tsubst_expr (op1, args, complain, in_decl);
 	--cp_unevaluated_operand;
 	--c_inhibit_evaluation_warnings;
 	RETURN (objc_build_encode_expr (op1));
@@ -20291,7 +20272,7 @@ tsubst_copy_and_build (tree t,
       ++cp_unevaluated_operand;
       ++c_inhibit_evaluation_warnings;
       ++cp_noexcept_operand;
-      op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
+      op1 = tsubst_expr (op1, args, complain, in_decl);
       --cp_unevaluated_operand;
       --c_inhibit_evaluation_warnings;
       --cp_noexcept_operand;
@@ -20399,8 +20380,8 @@ tsubst_copy_and_build (tree t,
 
     case COMPOUND_EXPR:
       {
-	tree op0 = tsubst_copy_and_build (TREE_OPERAND (t, 0), args,
-					  complain & ~tf_decltype, in_decl);
+	tree op0 = tsubst_expr (TREE_OPERAND (t, 0), args,
+				complain & ~tf_decltype, in_decl);
 	RETURN (build_x_compound_expr (EXPR_LOCATION (t),
 				       op0,
 				       RECUR (TREE_OPERAND (t, 1)),
@@ -20460,7 +20441,7 @@ tsubst_copy_and_build (tree t,
 		     || (TREE_CODE (function) == TEMPLATE_ID_EXPR
 			 && identifier_p (TREE_OPERAND (function, 0)))))
 	  {
-	    /* Do nothing; calling tsubst_copy_and_build on an identifier
+	    /* Do nothing; calling tsubst_expr on an identifier
 	       would incorrectly perform unqualified lookup again.
 
 	       Note that we can also have an IDENTIFIER_NODE if the earlier
@@ -20497,7 +20478,7 @@ tsubst_copy_and_build (tree t,
 		 augmenting the overload set via ADL, so during this initial
 		 substitution we disable mark_used by setting tf_conv (68942).  */
 	      subcomplain |= tf_conv;
-	    function = tsubst_copy_and_build (function, args, subcomplain, in_decl);
+	    function = tsubst_expr (function, args, subcomplain, in_decl);
 
 	    if (BASELINK_P (function))
 	      qualified_p = true;
@@ -20505,8 +20486,7 @@ tsubst_copy_and_build (tree t,
 
 	nargs = call_expr_nargs (t);
 	releasing_vec call_args;
-	tsubst_copy_and_build_call_args (t, args, complain, in_decl,
-					 call_args);
+	tsubst_call_args (t, args, complain, in_decl, call_args);
 
 	/* Stripped-down processing for a call in a thunk.  Specifically, in
 	   the thunk template for a generic lambda.  */
@@ -20598,8 +20578,7 @@ tsubst_copy_and_build (tree t,
 		/* For backwards compatibility and good diagnostics, try
 		   the unqualified lookup again if we aren't in SFINAE
 		   context.  */
-		tree unq = tsubst_copy_and_build (function, args,
-						  complain, in_decl);
+		tree unq = tsubst_expr (function, args, complain, in_decl);
 		if (unq == error_mark_node)
 		  RETURN (error_mark_node);
 
@@ -21390,8 +21369,13 @@ tsubst_copy_and_build (tree t,
 	 to the containing function, inlined copy or so.  */
       RETURN (t);
 
+    case CO_YIELD_EXPR:
+      RETURN (finish_co_yield_expr (input_location,
+				    RECUR (TREE_OPERAND (t, 0))));
+
     case CO_AWAIT_EXPR:
-      RETURN (tsubst_expr (t, args, complain, in_decl));
+      RETURN (finish_co_await_expr (input_location,
+				    RECUR (TREE_OPERAND (t, 0))));
 
     case VA_ARG_EXPR:
       {
@@ -21403,8 +21387,7 @@ tsubst_copy_and_build (tree t,
     case OFFSETOF_EXPR:
       {
 	tree object_ptr
-	  = tsubst_copy_and_build (TREE_OPERAND (t, 1), args,
-				   complain, in_decl);
+	  = tsubst_expr (TREE_OPERAND (t, 1), args, complain, in_decl);
 	RETURN (finish_offsetof (object_ptr,
 				 RECUR (TREE_OPERAND (t, 0)),
 				 EXPR_LOCATION (t)));
@@ -21420,7 +21403,7 @@ tsubst_copy_and_build (tree t,
 	if (TYPE_P (type1))
 	  type1 = tsubst (type1, args, complain, in_decl);
 	else
-	  type1 = tsubst_copy_and_build (type1, args, complain, in_decl);
+	  type1 = tsubst_expr (type1, args, complain, in_decl);
 	tree type2 = tsubst (TRAIT_EXPR_TYPE2 (t), args,
 			     complain, in_decl);
 	RETURN (finish_trait_expr (TRAIT_EXPR_LOCATION (t),
@@ -21433,7 +21416,7 @@ tsubst_copy_and_build (tree t,
 	tree stmt_expr = begin_stmt_expr ();
 
 	cur_stmt_expr = stmt_expr;
-	tsubst_expr (STMT_EXPR_STMT (t), args, complain, in_decl);
+	tsubst_stmt (STMT_EXPR_STMT (t), args, complain, in_decl);
 	stmt_expr = finish_stmt_expr (stmt_expr, false);
 	cur_stmt_expr = old_stmt_expr;
 
@@ -21460,7 +21443,8 @@ tsubst_copy_and_build (tree t,
       }
 
     case TRANSACTION_EXPR:
-      RETURN (tsubst_expr (t, args, complain, in_decl));
+      gcc_checking_assert (!TRANSACTION_EXPR_IS_STMT (t));
+      RETURN (tsubst_stmt (t, args, complain, in_decl));
 
     case PAREN_EXPR:
       if (REF_PARENTHESIZED_P (t))
@@ -21541,12 +21525,9 @@ tsubst_copy_and_build (tree t,
 
     default:
       /* Handle Objective-C++ constructs, if appropriate.  */
-      {
-	tree subst
-	  = objcp_tsubst_copy_and_build (t, args, complain, in_decl);
-	if (subst)
-	  RETURN (subst);
-      }
+      if (tree subst = objcp_tsubst_expr (t, args, complain, in_decl))
+	RETURN (subst);
+
       /* We shouldn't get here, but keep going if !flag_checking.  */
       if (flag_checking)
 	gcc_unreachable ();
@@ -26582,9 +26563,9 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain)
 	    ++processing_template_decl;
 
 	  /* Do deferred instantiation of the noexcept-specifier.  */
-	  noex = tsubst_copy_and_build (DEFERRED_NOEXCEPT_PATTERN (noex),
-					DEFERRED_NOEXCEPT_ARGS (noex),
-					tf_warning_or_error, fn);
+	  noex = tsubst_expr (DEFERRED_NOEXCEPT_PATTERN (noex),
+			      DEFERRED_NOEXCEPT_ARGS (noex),
+			      tf_warning_or_error, fn);
 
 	  /* Build up the noexcept-specification.  */
 	  spec = build_noexcept_spec (noex, tf_warning_or_error);
@@ -26758,7 +26739,7 @@ instantiate_body (tree pattern, tree args, tree d, bool nested_p)
 			tf_warning_or_error, d);
       else
 	{
-	  tsubst_expr (DECL_SAVED_TREE (code_pattern), args,
+	  tsubst_stmt (DECL_SAVED_TREE (code_pattern), args,
 		       tf_warning_or_error, DECL_TI_TEMPLATE (d));
 
 	  /* Set the current input_location to the end of the function
@@ -27278,8 +27259,8 @@ tsubst_initializer_list (tree t, tree argvec)
 		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 = tsubst_expr (TREE_PURPOSE (t), argvec,
+				    tf_warning_or_error, NULL_TREE);
 
               decl = expand_member_init (decl);
               if (decl && !DECL_P (decl))
diff --git a/gcc/objcp/objcp-lang.cc b/gcc/objcp/objcp-lang.cc
index 9887209b9c8..5b04cd66290 100644
--- a/gcc/objcp/objcp-lang.cc
+++ b/gcc/objcp/objcp-lang.cc
@@ -50,11 +50,10 @@ struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
    there should be very few (if any) routines below.  */
 
 tree
-objcp_tsubst_copy_and_build (tree t, tree args, tsubst_flags_t complain,
-			     tree in_decl)
+objcp_tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 {
 #define RECURSE(NODE)							\
-  tsubst_copy_and_build (NODE, args, complain, in_decl)
+  tsubst_expr (NODE, args, complain, in_decl)
 
   /* The following two can only occur in Objective-C++.  */
 
-- 
2.42.0.307.gd0e8084c65


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] c++: merge tsubst_copy into tsubst_copy_and_build
  2023-10-04 16:08         ` Patrick Palka
  2023-10-04 19:23           ` [PATCH 2/1] c++: rename tsubst_copy_and_build and tsubst_expr Patrick Palka
@ 2023-10-19 21:43           ` Jason Merrill
  1 sibling, 0 replies; 13+ messages in thread
From: Jason Merrill @ 2023-10-19 21:43 UTC (permalink / raw)
  To: Patrick Palka; +Cc: gcc-patches

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.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/1] c++: rename tsubst_copy_and_build and tsubst_expr
  2023-10-04 19:23           ` [PATCH 2/1] c++: rename tsubst_copy_and_build and tsubst_expr Patrick Palka
@ 2023-10-19 21:43             ` Jason Merrill
  0 siblings, 0 replies; 13+ messages in thread
From: Jason Merrill @ 2023-10-19 21:43 UTC (permalink / raw)
  To: Patrick Palka, gcc-patches

On 10/4/23 15:23, Patrick Palka wrote:
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?

OK.

> -- >8 --
> 
> After the previous patch, we currently have two tsubst entry points
> for expression trees: tsubst_copy_and_build and tsubst_expr.  But the
> latter is just a superset of the former that also handles statement
> trees.  We could merge the two entry points so that we just have
> tsubst_expr, but it seems natural to distinguish statement trees from
> expression trees and to maintain a separate entry point for them.
> 
> To that end, this this patch renames tsubst_copy_and_build to
> tsubst_expr, and renames the current tsubst_expr to tsubst_stmt, which
> continues to be a superset of the former (since sometimes expression
> trees appear in statement contexts, e.g. a branch of an IF_STMT could be
> NOP_EXPR).  Making tsubst_stmt disjoint from tsubst_expr is left as
> future work (if deemed desirable).
> 
> This patch in turn renames suitable existing uses of tsubst_expr (that
> expect to take statement trees) to use tsubst_stmt.  Thus untouched
> tsubst_expr calls are implicitly strengthened to expect only expression
> trees after this patch.  And since I'm not familiar with the
> tsubst_omp_* routines this patch renames all tsubst_expr uses there to
> tsubst_stmt to ensure no unintended functional change in that area.
> This patch also moves the handling of CO_YIELD_EXPR and CO_AWAIT_EXPR
> from tsubst_stmt to tsubst_expr since they're expression trees.
> 
> gcc/cp/ChangeLog:
> 
> 	* cp-lang.cc (objcp_tsubst_copy_and_build): Rename to ...
> 	(objcp_tsubst_expr): ... this.
> 	* cp-objcp-common.h (objcp_tsubst_copy_and_build): Rename to ...
> 	(objcp_tsubst_expr): ... this.
> 	* cp-tree.h (tsubst_copy_and_build): Remove declaration.
> 	* init.cc (maybe_instantiate_nsdmi_init): Use tsubst_expr
> 	instead of tsubst_copy_and_build.
> 	* pt.cc (expand_integer_pack): Likewise.
> 	(instantiate_non_dependent_expr_internal): Likewise.
> 	(instantiate_class_template): Use tsubst_stmt instead of
> 	tsubst_expr for STATIC_ASSERT.
> 	(tsubst_function_decl): Adjust tsubst_copy_and_build uses.
> 	(tsubst_arg_types): Likewise.
> 	(tsubst_exception_specification): Likewise.
> 	(tsubst_tree_list): Likewise.
> 	(tsubst): Likewise.
> 	(tsubst_name): Likewise.
> 	(tsubst_omp_clause_decl): Use tsubst_stmt instead of tsubst_expr.
> 	(tsubst_omp_clauses): Likewise.
> 	(tsubst_copy_asm_operands): Adjust tsubst_copy_and_build use.
> 	(tsubst_omp_for_iterator): Use tsubst_stmt instead of tsubst_expr.
> 	(tsubst_expr): Rename to ...
> 	(tsubst_stmt): ... this.
> 	<case CO_YIELD_EXPR, CO_AWAIT_EXPR>: Move to tsubst_expr.
> 	(tsubst_omp_udr): Use tsubst_stmt instead of tsubst_expr.
> 	(tsubst_non_call_postfix_expression): Adjust tsubst_copy_and_build
> 	use.
> 	(tsubst_lambda_expr): Likewise.  Use tsubst_stmt instead of
> 	tsubst_expr for the body of a lambda.
> 	(tsubst_copy_and_build_call_args): Rename to ...
> 	(tsubst_call_args): ... this.  Adjust tsubst_copy_and_build use.
> 	(tsubst_copy_and_build): Rename to tsubst_expr.  Adjust
> 	tsubst_copy_and_build and tsubst_copy_and_build_call_args use.
> 	<case TRANSACTION_EXPR>: Use tsubst_stmt instead of tsubst_expr.
> 	(maybe_instantiate_noexcept): Adjust tsubst_copy_and_build use.
> 	(instantiate_body): Use tsubst_stmt instead of tsubst_expr for
> 	substituting the function body.
> 	(tsubst_initializer_list): Adjust tsubst_copy_and_build use.
> 
> gcc/objcp/ChangeLog:
> 
> 	* objcp-lang.cc (objcp_tsubst_copy_and_build): Rename to ...
> 	(objcp_tsubst_expr): ... this.  Adjust tsubst_copy_and_build
> 	uses.
> ---
>   gcc/cp/cp-lang.cc        |   6 +-
>   gcc/cp/cp-objcp-common.h |   2 +-
>   gcc/cp/cp-tree.h         |   1 -
>   gcc/cp/init.cc           |   3 +-
>   gcc/cp/pt.cc             | 177 +++++++++++++++++----------------------
>   gcc/objcp/objcp-lang.cc  |   5 +-
>   6 files changed, 85 insertions(+), 109 deletions(-)
> 
> diff --git a/gcc/cp/cp-lang.cc b/gcc/cp/cp-lang.cc
> index 2f541460c4a..f2ed83de4fb 100644
> --- a/gcc/cp/cp-lang.cc
> +++ b/gcc/cp/cp-lang.cc
> @@ -113,10 +113,8 @@ struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
>   /* The following function does something real, but only in Objective-C++.  */
>   
>   tree
> -objcp_tsubst_copy_and_build (tree /*t*/,
> -			     tree /*args*/,
> -			     tsubst_flags_t /*complain*/,
> -			     tree /*in_decl*/)
> +objcp_tsubst_expr (tree /*t*/, tree /*args*/, tsubst_flags_t /*complain*/,
> +		   tree /*in_decl*/)
>   {
>     return NULL_TREE;
>   }
> diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h
> index 80893aa1752..1408301a300 100644
> --- a/gcc/cp/cp-objcp-common.h
> +++ b/gcc/cp/cp-objcp-common.h
> @@ -24,7 +24,7 @@ along with GCC; see the file COPYING3.  If not see
>   /* In cp/objcp-common.c, cp/cp-lang.cc and objcp/objcp-lang.cc.  */
>   
>   extern tree cp_get_debug_type (const_tree);
> -extern tree objcp_tsubst_copy_and_build (tree, tree, tsubst_flags_t, tree);
> +extern tree objcp_tsubst_expr (tree, tree, tsubst_flags_t, tree);
>   
>   extern int cp_decl_dwarf_attribute (const_tree, int);
>   extern int cp_type_dwarf_attribute (const_tree, int);
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 919eab34803..4b463f12c0c 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -7458,7 +7458,6 @@ extern void instantiate_pending_templates	(int);
>   extern tree tsubst_default_argument		(tree, int, tree, tree,
>   						 tsubst_flags_t);
>   extern tree tsubst (tree, tree, tsubst_flags_t, tree);
> -extern tree tsubst_copy_and_build		(tree, tree, tsubst_flags_t, tree);
>   extern tree tsubst_expr                         (tree, tree, tsubst_flags_t, tree);
>   extern tree tsubst_pack_expansion		(tree, tree, tsubst_flags_t, tree);
>   extern tree tsubst_argument_pack		(tree, tree, tsubst_flags_t, tree);
> diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
> index d1bae3b155f..d48bb16c7c5 100644
> --- a/gcc/cp/init.cc
> +++ b/gcc/cp/init.cc
> @@ -621,8 +621,7 @@ maybe_instantiate_nsdmi_init (tree member, tsubst_flags_t complain)
>   	  start_lambda_scope (member);
>   
>   	  /* Do deferred instantiation of the NSDMI.  */
> -	  init = tsubst_copy_and_build (init, DECL_TI_ARGS (member),
> -					complain, member);
> +	  init = tsubst_expr (init, DECL_TI_ARGS (member), complain, member);
>   	  init = digest_nsdmi_init (member, init, complain);
>   
>   	  finish_lambda_scope ();
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index e801a224d1b..837e81eea83 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -204,6 +204,7 @@ 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_stmt (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);
> @@ -3763,7 +3764,7 @@ expand_integer_pack (tree call, tree args, tsubst_flags_t complain,
>   		     tree in_decl)
>   {
>     tree ohi = CALL_EXPR_ARG (call, 0);
> -  tree hi = tsubst_copy_and_build (ohi, args, complain, in_decl);
> +  tree hi = tsubst_expr (ohi, args, complain, in_decl);
>   
>     if (instantiation_dependent_expression_p (hi))
>       {
> @@ -3771,7 +3772,7 @@ expand_integer_pack (tree call, tree args, tsubst_flags_t complain,
>   	{
>   	  /* Work around maybe_convert_nontype_argument not doing this for
>   	     dependent arguments.  Don't use IMPLICIT_CONV_EXPR_NONTYPE_ARG
> -	     because that will make tsubst_copy_and_build ignore it.  */
> +	     because that will make tsubst_expr ignore it.  */
>   	  tree type = tsubst (TREE_TYPE (ohi), args, complain, in_decl);
>   	  if (!TREE_TYPE (hi) || !same_type_p (type, TREE_TYPE (hi)))
>   	    hi = build1 (IMPLICIT_CONV_EXPR, type, hi);
> @@ -6423,10 +6424,7 @@ redeclare_class_template (tree type, tree parms, tree cons)
>   tree
>   instantiate_non_dependent_expr_internal (tree expr, tsubst_flags_t complain)
>   {
> -  return tsubst_copy_and_build (expr,
> -				/*args=*/NULL_TREE,
> -				complain,
> -				/*in_decl=*/NULL_TREE);
> +  return tsubst_expr (expr, /*args=*/NULL_TREE, complain, /*in_decl=*/NULL_TREE);
>   }
>   
>   /* Instantiate the non-dependent expression EXPR.  */
> @@ -12367,7 +12365,7 @@ instantiate_class_template (tree type)
>   	    {
>   	      /* Build new TYPE_FIELDS.  */
>                 if (TREE_CODE (t) == STATIC_ASSERT)
> -		tsubst_expr (t, args, tf_warning_or_error, NULL_TREE);
> +		tsubst_stmt (t, args, tf_warning_or_error, NULL_TREE);
>   	      else if (TREE_CODE (t) != CONST_DECL)
>   		{
>   		  tree r;
> @@ -14455,7 +14453,7 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain,
>     if (DECL_HAS_DEPENDENT_EXPLICIT_SPEC_P (t))
>       {
>         tree spec = lookup_explicit_specifier (t);
> -      spec = tsubst_copy_and_build (spec, args, complain, in_decl);
> +      spec = tsubst_expr (spec, args, complain, in_decl);
>         spec = build_explicit_specifier (spec, complain);
>         if (spec == error_mark_node)
>   	return error_mark_node;
> @@ -15584,7 +15582,7 @@ tsubst_arg_types (tree arg_types,
>     if (lambda_fn_in_template_p (in_decl)
>         || (in_decl && TREE_CODE (in_decl) == FUNCTION_DECL
>   	  && DECL_LOCAL_DECL_P (in_decl)))
> -    default_arg = tsubst_copy_and_build (default_arg, args, complain, in_decl);
> +    default_arg = tsubst_expr (default_arg, args, complain, in_decl);
>   
>     tree remaining_arg_types = tsubst_arg_types (TREE_CHAIN (arg_types),
>   					       args, end, complain, in_decl);
> @@ -15765,7 +15763,7 @@ tsubst_exception_specification (tree fntype,
>   					   args);
>   	      expr = DEFERRED_NOEXCEPT_PATTERN (expr);
>   	    }
> -	  new_specs = tsubst_copy_and_build (expr, args, complain, in_decl);
> +	  new_specs = tsubst_expr (expr, args, complain, in_decl);
>   	}
>         new_specs = build_noexcept_spec (new_specs, complain);
>         /* We've instantiated a template before a noexcept-specifier
> @@ -15862,7 +15860,7 @@ tsubst_tree_list (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>     else if (TYPE_P (purpose))
>       purpose = tsubst (purpose, args, complain, in_decl);
>     else
> -    purpose = tsubst_copy_and_build (purpose, args, complain, in_decl);
> +    purpose = tsubst_expr (purpose, args, complain, in_decl);
>     if (purpose == error_mark_node || purposevec == error_mark_node)
>       return error_mark_node;
>   
> @@ -15879,7 +15877,7 @@ tsubst_tree_list (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>     else if (TYPE_P (value))
>       value = tsubst (value, args, complain, in_decl);
>     else
> -    value = tsubst_copy_and_build (value, args, complain, in_decl);
> +    value = tsubst_expr (value, args, complain, in_decl);
>     if (value == error_mark_node || valuevec == error_mark_node)
>       return error_mark_node;
>   
> @@ -15891,7 +15889,7 @@ tsubst_tree_list (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>     else if (TYPE_P (chain))
>       chain = tsubst (chain, args, complain, in_decl);
>     else
> -    chain = tsubst_copy_and_build (chain, args, complain, in_decl);
> +    chain = tsubst_expr (chain, args, complain, in_decl);
>     if (chain == error_mark_node)
>       return error_mark_node;
>   
> @@ -16104,7 +16102,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_and_build (tmpl, args, complain, in_decl);
> +	  tmpl = tsubst_expr (tmpl, args, complain, in_decl);
>   	  if (TREE_CODE (tmpl) == TEMPLATE_TEMPLATE_PARM)
>   	    tmpl = TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (tmpl);
>   
> @@ -16696,8 +16694,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>   	++cp_unevaluated_operand;
>   	++c_inhibit_evaluation_warnings;
>   
> -	type = tsubst_copy_and_build (DECLTYPE_TYPE_EXPR (t), args,
> -				      complain|tf_decltype, in_decl);
> +	type = tsubst_expr (DECLTYPE_TYPE_EXPR (t), args,
> +			    complain|tf_decltype, in_decl);
>   
>   	--cp_unevaluated_operand;
>   	--c_inhibit_evaluation_warnings;
> @@ -16732,7 +16730,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>   	if (TYPE_P (type1))
>   	  type1 = tsubst (type1, args, complain, in_decl);
>   	else
> -	  type1 = tsubst_copy_and_build (type1, args, complain, in_decl);
> +	  type1 = tsubst_expr (type1, args, complain, in_decl);
>   	tree type2 = tsubst (TRAIT_TYPE_TYPE2 (t), args, complain, in_decl);
>   	type = finish_trait_type (TRAIT_TYPE_KIND (t), type1, type2, complain);
>   	return cp_build_qualified_type (type,
> @@ -16782,7 +16780,7 @@ tsubst_scope (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>   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);
> +  return tsubst_expr (t, args, complain | tf_no_name_lookup, in_decl);
>   }
>   
>   /* OLDFNS is a lookup set of member functions from some class template, and
> @@ -17312,11 +17310,11 @@ tsubst_omp_clause_decl (tree decl, tree args, tsubst_flags_t 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);
> +		= tsubst_stmt (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);
> +		= tsubst_stmt (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);
> +		= tsubst_stmt (TREE_VEC_ELT (it, 3), args, complain, in_decl);
>   	      TREE_CHAIN (*tp) = NULL_TREE;
>   	      tp = &TREE_CHAIN (*tp);
>   	    }
> @@ -17338,8 +17336,8 @@ tsubst_omp_clause_decl (tree decl, tree args, tsubst_flags_t complain,
>     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);
> +	= tsubst_stmt (TREE_PURPOSE (decl), args, complain, in_decl);
> +      tree length = tsubst_stmt (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
> @@ -17351,7 +17349,7 @@ tsubst_omp_clause_decl (tree decl, tree args, tsubst_flags_t complain,
>   	= OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (decl);
>         return ret;
>       }
> -  tree ret = tsubst_expr (decl, args, complain, in_decl);
> +  tree ret = tsubst_stmt (decl, args, complain, in_decl);
>     /* Undo convert_from_reference tsubst_expr could have called.  */
>     if (decl
>         && REFERENCE_REF_P (ret)
> @@ -17382,7 +17380,7 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
>   	  if (OMP_CLAUSE_LASTPRIVATE_STMT (oc))
>   	    {
>   	      OMP_CLAUSE_LASTPRIVATE_STMT (nc) = push_stmt_list ();
> -	      tsubst_expr (OMP_CLAUSE_LASTPRIVATE_STMT (oc), args,
> +	      tsubst_stmt (OMP_CLAUSE_LASTPRIVATE_STMT (oc), args,
>   			   complain, in_decl);
>   	      OMP_CLAUSE_LASTPRIVATE_STMT (nc)
>   		= pop_stmt_list (OMP_CLAUSE_LASTPRIVATE_STMT (nc));
> @@ -17415,7 +17413,7 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
>   	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,
> +	      = tsubst_stmt (OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (oc), args,
>   			     complain, in_decl);
>   	  /* FALLTHRU */
>   	case OMP_CLAUSE_TILE:
> @@ -17444,7 +17442,7 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
>   	case OMP_CLAUSE_WAIT:
>   	case OMP_CLAUSE_DETACH:
>   	  OMP_CLAUSE_OPERAND (nc, 0)
> -	    = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain, in_decl);
> +	    = tsubst_stmt (OMP_CLAUSE_OPERAND (oc, 0), args, complain, in_decl);
>   	  break;
>   	case OMP_CLAUSE_REDUCTION:
>   	case OMP_CLAUSE_IN_REDUCTION:
> @@ -17474,16 +17472,16 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
>   	    = tsubst_omp_clause_decl (OMP_CLAUSE_DECL (oc), args, complain,
>   				      in_decl, NULL);
>   	  OMP_CLAUSE_OPERAND (nc, 1)
> -	    = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 1), args, complain, in_decl);
> +	    = tsubst_stmt (OMP_CLAUSE_OPERAND (oc, 1), args, complain, in_decl);
>   	  break;
>   	case OMP_CLAUSE_ALLOCATE:
>   	  OMP_CLAUSE_DECL (nc)
>   	    = tsubst_omp_clause_decl (OMP_CLAUSE_DECL (oc), args, complain,
>   				      in_decl, NULL);
>   	  OMP_CLAUSE_OPERAND (nc, 1)
> -	    = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 1), args, complain, in_decl);
> +	    = tsubst_stmt (OMP_CLAUSE_OPERAND (oc, 1), args, complain, in_decl);
>   	  OMP_CLAUSE_OPERAND (nc, 2)
> -	    = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 2), args, complain, in_decl);
> +	    = tsubst_stmt (OMP_CLAUSE_OPERAND (oc, 2), args, complain, in_decl);
>   	  break;
>   	case OMP_CLAUSE_LINEAR:
>   	  OMP_CLAUSE_DECL (nc)
> @@ -17500,7 +17498,7 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
>   					complain, in_decl, NULL);
>   	  else
>   	    OMP_CLAUSE_LINEAR_STEP (nc)
> -	      = tsubst_expr (OMP_CLAUSE_LINEAR_STEP (oc), args,
> +	      = tsubst_stmt (OMP_CLAUSE_LINEAR_STEP (oc), args,
>   			     complain, in_decl);
>   	  break;
>   	case OMP_CLAUSE_NOWAIT:
> @@ -17612,7 +17610,7 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
>     return new_clauses;
>   }
>   
> -/* Like tsubst_copy_and_build, but unshare TREE_LIST nodes.  */
> +/* Like tsubst_expr, but unshare TREE_LIST nodes.  */
>   
>   static tree
>   tsubst_copy_asm_operands (tree t, tree args, tsubst_flags_t complain,
> @@ -17626,7 +17624,7 @@ tsubst_copy_asm_operands (tree t, tree args, tsubst_flags_t complain,
>       return t;
>   
>     if (TREE_CODE (t) != TREE_LIST)
> -    return tsubst_copy_and_build (t, args, complain, in_decl);
> +    return tsubst_expr (t, args, complain, in_decl);
>   
>     if (t == void_list_node)
>       return t;
> @@ -17670,7 +17668,7 @@ tsubst_omp_for_iterator (tree t, int i, tree declv, tree &orig_declv,
>   			 tree args, tsubst_flags_t complain, tree in_decl)
>   {
>   #define RECUR(NODE)				\
> -  tsubst_expr ((NODE), args, complain, in_decl)
> +  tsubst_stmt ((NODE), args, complain, in_decl)
>     tree decl, init, cond = NULL_TREE, incr = NULL_TREE;
>     bool ret = false;
>   
> @@ -18153,15 +18151,14 @@ dependent_operand_p (tree t)
>     return r;
>   }
>   
> -/* Like tsubst_copy for expressions, etc. but also does semantic
> -   processing.  */
> +/* A superset of tsubst_expr that also handles statement trees.  */
>   
> -tree
> -tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
> +static tree
> +tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>   {
>   #define RETURN(EXP) do { r = (EXP); goto out; } while(0)
>   #define RECUR(NODE)				\
> -  tsubst_expr ((NODE), args, complain, in_decl)
> +  tsubst_stmt ((NODE), args, complain, in_decl)
>   
>     tree stmt, tmp;
>     tree r;
> @@ -18198,16 +18195,6 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>         finish_co_return_stmt (input_location, RECUR (TREE_OPERAND (t, 0)));
>         break;
>   
> -    case CO_YIELD_EXPR:
> -      stmt = finish_co_yield_expr (input_location,
> -				   RECUR (TREE_OPERAND (t, 0)));
> -      RETURN (stmt);
> -
> -    case CO_AWAIT_EXPR:
> -      stmt = finish_co_await_expr (input_location,
> -				   RECUR (TREE_OPERAND (t, 0)));
> -      RETURN (stmt);
> -
>       case EXPR_STMT:
>         tmp = RECUR (EXPR_STMT_EXPR (t));
>         if (EXPR_STMT_STMT_EXPR_RESULT (t))
> @@ -19228,7 +19215,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>       default:
>         gcc_assert (!STATEMENT_CODE_P (TREE_CODE (t)));
>   
> -      RETURN (tsubst_copy_and_build (t, args, complain, in_decl));
> +      RETURN (tsubst_expr (t, args, complain, in_decl));
>       }
>   
>     RETURN (NULL_TREE);
> @@ -19275,7 +19262,7 @@ tsubst_omp_udr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>         DECL_CONTEXT (omp_in) = current_function_decl;
>         keep_next_level (true);
>         tree block = begin_omp_structured_block ();
> -      tsubst_expr (stmts[2], args, complain, in_decl);
> +      tsubst_stmt (stmts[2], args, complain, in_decl);
>         block = finish_omp_structured_block (block);
>         block = maybe_cleanup_point_expr_void (block);
>         add_decl_expr (omp_out);
> @@ -19295,7 +19282,7 @@ tsubst_omp_udr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>         DECL_CONTEXT (omp_orig) = current_function_decl;
>         keep_next_level (true);
>         tree block = begin_omp_structured_block ();
> -      tsubst_expr (stmts[5], args, complain, in_decl);
> +      tsubst_stmt (stmts[5], args, complain, in_decl);
>         block = finish_omp_structured_block (block);
>         block = maybe_cleanup_point_expr_void (block);
>         cp_walk_tree (&block, cp_remove_omp_priv_cleanup_stmt, omp_priv, NULL);
> @@ -19319,7 +19306,7 @@ tsubst_non_call_postfix_expression (tree t, tree args,
>       t = tsubst_qualified_id (t, args, complain, in_decl,
>   			     /*done=*/false, /*address_p=*/false);
>     else
> -    t = tsubst_copy_and_build (t, args, complain, in_decl);
> +    t = tsubst_expr (t, args, complain, in_decl);
>   
>     return t;
>   }
> @@ -19392,7 +19379,7 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>         if (PACK_EXPANSION_P (init))
>   	init = tsubst_pack_expansion (init, args, complain, in_decl);
>         else
> -	init = tsubst_copy_and_build (init, args, complain, in_decl);
> +	init = tsubst_expr (init, args, complain, in_decl);
>   
>         if (init == error_mark_node)
>   	return error_mark_node;
> @@ -19572,7 +19559,7 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>   	   need another to confuse NRV (91217).  */
>   	saved = BIND_EXPR_BODY (saved);
>   
> -      tsubst_expr (saved, args, complain, r);
> +      tsubst_stmt (saved, args, complain, r);
>   
>         finish_lambda_function (body);
>   
> @@ -19657,12 +19644,11 @@ maybe_fold_fn_template_args (tree fn, tsubst_flags_t complain)
>     return fold_targs_r (targs, complain);
>   }
>   
> -/* Helper function for tsubst_copy_and_build CALL_EXPR and ARRAY_REF
> -   handling.  */
> +/* Helper function for tsubst_expr CALL_EXPR and ARRAY_REF handling.  */
>   
>   static void
> -tsubst_copy_and_build_call_args (tree t, tree args, tsubst_flags_t complain,
> -				 tree in_decl, releasing_vec &call_args)
> +tsubst_call_args (tree t, tree args, tsubst_flags_t complain,
> +		  tree in_decl, releasing_vec &call_args)
>   {
>     unsigned int nargs = call_expr_nargs (t);
>     for (unsigned int i = 0; i < nargs; ++i)
> @@ -19670,8 +19656,7 @@ tsubst_copy_and_build_call_args (tree t, tree args, tsubst_flags_t complain,
>         tree arg = CALL_EXPR_ARG (t, i);
>   
>         if (!PACK_EXPANSION_P (arg))
> -	vec_safe_push (call_args,
> -		       tsubst_copy_and_build (arg, args, complain, in_decl));
> +	vec_safe_push (call_args, tsubst_expr (arg, args, complain, in_decl));
>         else
>   	{
>   	  /* Expand the pack expansion and push each entry onto CALL_ARGS.  */
> @@ -19700,14 +19685,11 @@ tsubst_copy_and_build_call_args (tree t, tree args, tsubst_flags_t complain,
>      analysis.  */
>   
>   tree
> -tsubst_copy_and_build (tree t,
> -		       tree args,
> -		       tsubst_flags_t complain,
> -		       tree in_decl)
> +tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>   {
>   #define RETURN(EXP) do { retval = (EXP); goto out; } while(0)
>   #define RECUR(NODE)						\
> -  tsubst_copy_and_build (NODE, args, complain, in_decl)
> +  tsubst_expr (NODE, args, complain, in_decl)
>   
>     tree retval, op1;
>     location_t save_loc;
> @@ -19792,7 +19774,7 @@ tsubst_copy_and_build (tree t,
>   	if (no_name_lookup_flag)
>   	  templ = tsubst_name (templ, args, complain, in_decl);
>   	else
> -	  templ = tsubst_copy_and_build (templ, args, complain, in_decl);
> +	  templ = tsubst_expr (templ, args, complain, in_decl);
>   
>   	if (targs)
>   	  targs = tsubst_template_args (targs, args, complain, in_decl);
> @@ -20140,8 +20122,7 @@ tsubst_copy_and_build (tree t,
>   	{
>   	  tree c = TREE_OPERAND (t, 1);
>   	  releasing_vec index_exp_list;
> -	  tsubst_copy_and_build_call_args (c, args, complain, in_decl,
> -					   index_exp_list);
> +	  tsubst_call_args (c, args, complain, in_decl, index_exp_list);
>   
>   	  tree r;
>   	  if (vec_safe_length (index_exp_list) == 1
> @@ -20243,7 +20224,7 @@ tsubst_copy_and_build (tree t,
>   	    if (TYPE_P (op1))
>   	      op1 = tsubst (op1, args, complain, in_decl);
>   	    else
> -	      op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
> +	      op1 = tsubst_expr (op1, args, complain, in_decl);
>   	    --cp_unevaluated_operand;
>   	    --c_inhibit_evaluation_warnings;
>   	  }
> @@ -20280,7 +20261,7 @@ tsubst_copy_and_build (tree t,
>   	op1 = TREE_OPERAND (t, 0);
>   	++cp_unevaluated_operand;
>   	++c_inhibit_evaluation_warnings;
> -	op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
> +	op1 = tsubst_expr (op1, args, complain, in_decl);
>   	--cp_unevaluated_operand;
>   	--c_inhibit_evaluation_warnings;
>   	RETURN (objc_build_encode_expr (op1));
> @@ -20291,7 +20272,7 @@ tsubst_copy_and_build (tree t,
>         ++cp_unevaluated_operand;
>         ++c_inhibit_evaluation_warnings;
>         ++cp_noexcept_operand;
> -      op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
> +      op1 = tsubst_expr (op1, args, complain, in_decl);
>         --cp_unevaluated_operand;
>         --c_inhibit_evaluation_warnings;
>         --cp_noexcept_operand;
> @@ -20399,8 +20380,8 @@ tsubst_copy_and_build (tree t,
>   
>       case COMPOUND_EXPR:
>         {
> -	tree op0 = tsubst_copy_and_build (TREE_OPERAND (t, 0), args,
> -					  complain & ~tf_decltype, in_decl);
> +	tree op0 = tsubst_expr (TREE_OPERAND (t, 0), args,
> +				complain & ~tf_decltype, in_decl);
>   	RETURN (build_x_compound_expr (EXPR_LOCATION (t),
>   				       op0,
>   				       RECUR (TREE_OPERAND (t, 1)),
> @@ -20460,7 +20441,7 @@ tsubst_copy_and_build (tree t,
>   		     || (TREE_CODE (function) == TEMPLATE_ID_EXPR
>   			 && identifier_p (TREE_OPERAND (function, 0)))))
>   	  {
> -	    /* Do nothing; calling tsubst_copy_and_build on an identifier
> +	    /* Do nothing; calling tsubst_expr on an identifier
>   	       would incorrectly perform unqualified lookup again.
>   
>   	       Note that we can also have an IDENTIFIER_NODE if the earlier
> @@ -20497,7 +20478,7 @@ tsubst_copy_and_build (tree t,
>   		 augmenting the overload set via ADL, so during this initial
>   		 substitution we disable mark_used by setting tf_conv (68942).  */
>   	      subcomplain |= tf_conv;
> -	    function = tsubst_copy_and_build (function, args, subcomplain, in_decl);
> +	    function = tsubst_expr (function, args, subcomplain, in_decl);
>   
>   	    if (BASELINK_P (function))
>   	      qualified_p = true;
> @@ -20505,8 +20486,7 @@ tsubst_copy_and_build (tree t,
>   
>   	nargs = call_expr_nargs (t);
>   	releasing_vec call_args;
> -	tsubst_copy_and_build_call_args (t, args, complain, in_decl,
> -					 call_args);
> +	tsubst_call_args (t, args, complain, in_decl, call_args);
>   
>   	/* Stripped-down processing for a call in a thunk.  Specifically, in
>   	   the thunk template for a generic lambda.  */
> @@ -20598,8 +20578,7 @@ tsubst_copy_and_build (tree t,
>   		/* For backwards compatibility and good diagnostics, try
>   		   the unqualified lookup again if we aren't in SFINAE
>   		   context.  */
> -		tree unq = tsubst_copy_and_build (function, args,
> -						  complain, in_decl);
> +		tree unq = tsubst_expr (function, args, complain, in_decl);
>   		if (unq == error_mark_node)
>   		  RETURN (error_mark_node);
>   
> @@ -21390,8 +21369,13 @@ tsubst_copy_and_build (tree t,
>   	 to the containing function, inlined copy or so.  */
>         RETURN (t);
>   
> +    case CO_YIELD_EXPR:
> +      RETURN (finish_co_yield_expr (input_location,
> +				    RECUR (TREE_OPERAND (t, 0))));
> +
>       case CO_AWAIT_EXPR:
> -      RETURN (tsubst_expr (t, args, complain, in_decl));
> +      RETURN (finish_co_await_expr (input_location,
> +				    RECUR (TREE_OPERAND (t, 0))));
>   
>       case VA_ARG_EXPR:
>         {
> @@ -21403,8 +21387,7 @@ tsubst_copy_and_build (tree t,
>       case OFFSETOF_EXPR:
>         {
>   	tree object_ptr
> -	  = tsubst_copy_and_build (TREE_OPERAND (t, 1), args,
> -				   complain, in_decl);
> +	  = tsubst_expr (TREE_OPERAND (t, 1), args, complain, in_decl);
>   	RETURN (finish_offsetof (object_ptr,
>   				 RECUR (TREE_OPERAND (t, 0)),
>   				 EXPR_LOCATION (t)));
> @@ -21420,7 +21403,7 @@ tsubst_copy_and_build (tree t,
>   	if (TYPE_P (type1))
>   	  type1 = tsubst (type1, args, complain, in_decl);
>   	else
> -	  type1 = tsubst_copy_and_build (type1, args, complain, in_decl);
> +	  type1 = tsubst_expr (type1, args, complain, in_decl);
>   	tree type2 = tsubst (TRAIT_EXPR_TYPE2 (t), args,
>   			     complain, in_decl);
>   	RETURN (finish_trait_expr (TRAIT_EXPR_LOCATION (t),
> @@ -21433,7 +21416,7 @@ tsubst_copy_and_build (tree t,
>   	tree stmt_expr = begin_stmt_expr ();
>   
>   	cur_stmt_expr = stmt_expr;
> -	tsubst_expr (STMT_EXPR_STMT (t), args, complain, in_decl);
> +	tsubst_stmt (STMT_EXPR_STMT (t), args, complain, in_decl);
>   	stmt_expr = finish_stmt_expr (stmt_expr, false);
>   	cur_stmt_expr = old_stmt_expr;
>   
> @@ -21460,7 +21443,8 @@ tsubst_copy_and_build (tree t,
>         }
>   
>       case TRANSACTION_EXPR:
> -      RETURN (tsubst_expr (t, args, complain, in_decl));
> +      gcc_checking_assert (!TRANSACTION_EXPR_IS_STMT (t));
> +      RETURN (tsubst_stmt (t, args, complain, in_decl));
>   
>       case PAREN_EXPR:
>         if (REF_PARENTHESIZED_P (t))
> @@ -21541,12 +21525,9 @@ tsubst_copy_and_build (tree t,
>   
>       default:
>         /* Handle Objective-C++ constructs, if appropriate.  */
> -      {
> -	tree subst
> -	  = objcp_tsubst_copy_and_build (t, args, complain, in_decl);
> -	if (subst)
> -	  RETURN (subst);
> -      }
> +      if (tree subst = objcp_tsubst_expr (t, args, complain, in_decl))
> +	RETURN (subst);
> +
>         /* We shouldn't get here, but keep going if !flag_checking.  */
>         if (flag_checking)
>   	gcc_unreachable ();
> @@ -26582,9 +26563,9 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain)
>   	    ++processing_template_decl;
>   
>   	  /* Do deferred instantiation of the noexcept-specifier.  */
> -	  noex = tsubst_copy_and_build (DEFERRED_NOEXCEPT_PATTERN (noex),
> -					DEFERRED_NOEXCEPT_ARGS (noex),
> -					tf_warning_or_error, fn);
> +	  noex = tsubst_expr (DEFERRED_NOEXCEPT_PATTERN (noex),
> +			      DEFERRED_NOEXCEPT_ARGS (noex),
> +			      tf_warning_or_error, fn);
>   
>   	  /* Build up the noexcept-specification.  */
>   	  spec = build_noexcept_spec (noex, tf_warning_or_error);
> @@ -26758,7 +26739,7 @@ instantiate_body (tree pattern, tree args, tree d, bool nested_p)
>   			tf_warning_or_error, d);
>         else
>   	{
> -	  tsubst_expr (DECL_SAVED_TREE (code_pattern), args,
> +	  tsubst_stmt (DECL_SAVED_TREE (code_pattern), args,
>   		       tf_warning_or_error, DECL_TI_TEMPLATE (d));
>   
>   	  /* Set the current input_location to the end of the function
> @@ -27278,8 +27259,8 @@ tsubst_initializer_list (tree t, tree argvec)
>   		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 = tsubst_expr (TREE_PURPOSE (t), argvec,
> +				    tf_warning_or_error, NULL_TREE);
>   
>                 decl = expand_member_init (decl);
>                 if (decl && !DECL_P (decl))
> diff --git a/gcc/objcp/objcp-lang.cc b/gcc/objcp/objcp-lang.cc
> index 9887209b9c8..5b04cd66290 100644
> --- a/gcc/objcp/objcp-lang.cc
> +++ b/gcc/objcp/objcp-lang.cc
> @@ -50,11 +50,10 @@ struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
>      there should be very few (if any) routines below.  */
>   
>   tree
> -objcp_tsubst_copy_and_build (tree t, tree args, tsubst_flags_t complain,
> -			     tree in_decl)
> +objcp_tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>   {
>   #define RECURSE(NODE)							\
> -  tsubst_copy_and_build (NODE, args, complain, in_decl)
> +  tsubst_expr (NODE, args, complain, in_decl)
>   
>     /* The following two can only occur in Objective-C++.  */
>   


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/2] c++: remove NON_DEPENDENT_EXPR, part 2
  2023-09-25 20:43 ` [PATCH 2/2] c++: remove NON_DEPENDENT_EXPR, part 2 Patrick Palka
  2023-10-02 19:37   ` [PATCH] c++: merge tsubst_copy into tsubst_copy_and_build Patrick Palka
@ 2023-10-19 21:46   ` Jason Merrill
  2023-10-20 15:57   ` Andrew Pinski
  2 siblings, 0 replies; 13+ messages in thread
From: Jason Merrill @ 2023-10-19 21:46 UTC (permalink / raw)
  To: Patrick Palka, gcc-patches

On 9/25/23 16:43, Patrick Palka wrote:
> This much more mechanical patch removes build_non_dependent_expr
> (and make_args_non_dependent) and adjusts callers accordingly,
> no functional change.

These two patches are OK either separately or squashed, whichever you 
prefer.

> gcc/cp/ChangeLog:
> 
> 	* call.cc (build_new_method_call): Remove calls to
> 	build_non_dependent_expr and/or make_args_non_dependent.
> 	* coroutines.cc (finish_co_return_stmt): Likewise.
> 	* cp-tree.h (build_non_dependent_expr): Remove.
> 	(make_args_non_dependent): Remove.
> 	* decl2.cc (grok_array_decl): Remove calls to
> 	build_non_dependent_expr and/or make_args_non_dependent.
> 	(build_offset_ref_call_from_tree): Likewise.
> 	* init.cc (build_new): Likewise.
> 	* pt.cc (make_args_non_dependent): Remove.
> 	(test_build_non_dependent_expr): Remove.
> 	(cp_pt_cc_tests): Adjust.
> 	* semantics.cc (finish_expr_stmt): Remove calls to
> 	build_non_dependent_expr and/or make_args_non_dependent.
> 	(finish_for_expr): Likewise.
> 	(finish_call_expr): Likewise.
> 	(finish_omp_atomic): Likewise.
> 	* typeck.cc (finish_class_member_access_expr): Likewise.
> 	(build_x_indirect_ref): Likewise.
> 	(build_x_binary_op): Likewise.
> 	(build_x_array_ref): Likewise.
> 	(build_x_vec_perm_expr): Likewise.
> 	(build_x_shufflevector): Likewise.
> 	(build_x_unary_op): Likewise.
> 	(cp_build_addressof): Likewise.
> 	(build_x_conditional_expr):
> 	(build_x_compound_expr): Likewise.
> 	(build_static_cast): Likewise.
> 	(build_x_modify_expr): Likewise.
> 	(check_return_expr): Likewise.
> 	* typeck2.cc (build_x_arrow): Likewise.
> ---
>   gcc/cp/call.cc       |  7 +------
>   gcc/cp/coroutines.cc |  3 ---
>   gcc/cp/cp-tree.h     |  2 --
>   gcc/cp/decl2.cc      | 17 +++-------------
>   gcc/cp/init.cc       |  5 -----
>   gcc/cp/pt.cc         | 46 --------------------------------------------
>   gcc/cp/semantics.cc  | 25 ++----------------------
>   gcc/cp/typeck.cc     | 31 -----------------------------
>   gcc/cp/typeck2.cc    |  1 -
>   9 files changed, 6 insertions(+), 131 deletions(-)
> 
> diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> index e8dafbd8ba6..15079ddf6dc 100644
> --- a/gcc/cp/call.cc
> +++ b/gcc/cp/call.cc
> @@ -11430,12 +11430,7 @@ build_new_method_call (tree instance, tree fns, vec<tree, va_gc> **args,
>       }
>   
>     if (processing_template_decl)
> -    {
> -      orig_args = args == NULL ? NULL : make_tree_vector_copy (*args);
> -      instance = build_non_dependent_expr (instance);
> -      if (args != NULL)
> -	make_args_non_dependent (*args);
> -    }
> +    orig_args = args == NULL ? NULL : make_tree_vector_copy (*args);
>   
>     /* Process the argument list.  */
>     if (args != NULL && *args != NULL)
> diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
> index df3cc820797..a5464becf7f 100644
> --- a/gcc/cp/coroutines.cc
> +++ b/gcc/cp/coroutines.cc
> @@ -1351,9 +1351,6 @@ finish_co_return_stmt (location_t kw, tree expr)
>   	 to undo it so we can try to treat it as an rvalue below.  */
>         expr = maybe_undo_parenthesized_ref (expr);
>   
> -      if (processing_template_decl)
> -	expr = build_non_dependent_expr (expr);
> -
>         if (error_operand_p (expr))
>   	return error_mark_node;
>       }
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 66b9a9c4b9a..8b9a7d58462 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -7488,8 +7488,6 @@ extern bool any_value_dependent_elements_p      (const_tree);
>   extern bool dependent_omp_for_p			(tree, tree, tree, tree);
>   extern tree resolve_typename_type		(tree, bool);
>   extern tree template_for_substitution		(tree);
> -inline tree build_non_dependent_expr		(tree t) { return t; } // XXX remove
> -extern void make_args_non_dependent		(vec<tree, va_gc> *);
>   extern bool reregister_specialization		(tree, tree, tree);
>   extern tree instantiate_non_dependent_expr	(tree, tsubst_flags_t = tf_error);
>   extern tree instantiate_non_dependent_expr_internal (tree, tsubst_flags_t);
> diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
> index 344e19ec98b..0aa1e355972 100644
> --- a/gcc/cp/decl2.cc
> +++ b/gcc/cp/decl2.cc
> @@ -427,14 +427,8 @@ grok_array_decl (location_t loc, tree array_expr, tree index_exp,
>   	  return build_min_nt_loc (loc, ARRAY_REF, array_expr, index_exp,
>   				   NULL_TREE, NULL_TREE);
>   	}
> -      array_expr = build_non_dependent_expr (array_expr);
> -      if (index_exp)
> -	index_exp = build_non_dependent_expr (index_exp);
> -      else
> -	{
> -	  orig_index_exp_list = make_tree_vector_copy (*index_exp_list);
> -	  make_args_non_dependent (*index_exp_list);
> -	}
> +      if (!index_exp)
> +	orig_index_exp_list = make_tree_vector_copy (*index_exp_list);
>       }
>   
>     type = TREE_TYPE (array_expr);
> @@ -5435,18 +5429,13 @@ build_offset_ref_call_from_tree (tree fn, vec<tree, va_gc> **args,
>         orig_args = make_tree_vector_copy (*args);
>   
>         /* Transform the arguments and add the implicit "this"
> -	 parameter.  That must be done before the FN is transformed
> -	 because we depend on the form of FN.  */
> -      make_args_non_dependent (*args);
> -      object = build_non_dependent_expr (object);
> +	 parameter.  */
>         if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
>   	{
>   	  if (TREE_CODE (fn) == DOTSTAR_EXPR)
>   	    object = cp_build_addr_expr (object, complain);
>   	  vec_safe_insert (*args, 0, object);
>   	}
> -      /* Now that the arguments are done, transform FN.  */
> -      fn = build_non_dependent_expr (fn);
>       }
>   
>     /* A qualified name corresponding to a bound pointer-to-member is
> diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
> index c5830297b93..d1bae3b155f 100644
> --- a/gcc/cp/init.cc
> +++ b/gcc/cp/init.cc
> @@ -3920,11 +3920,6 @@ build_new (location_t loc, vec<tree, va_gc> **placement, tree type,
>   		(**init)[i] = copy_node (e);
>   	    }
>   	}
> -
> -      make_args_non_dependent (*placement);
> -      if (nelts)
> -	nelts = build_non_dependent_expr (nelts);
> -      make_args_non_dependent (*init);
>       }
>   
>     if (nelts)
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index e565c0538b7..382db4dd01d 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -29294,24 +29294,6 @@ resolve_typename_type (tree type, bool only_current_p)
>     return result;
>   }
>   
> -/* ARGS is a vector of expressions as arguments to a function call.
> -   Replace the arguments with equivalent non-dependent expressions.
> -   This modifies ARGS in place.  */
> -
> -void
> -make_args_non_dependent (vec<tree, va_gc> *args)
> -{
> -  unsigned int ix;
> -  tree arg;
> -
> -  FOR_EACH_VEC_SAFE_ELT (args, ix, arg)
> -    {
> -      tree newarg = build_non_dependent_expr (arg);
> -      if (newarg != arg)
> -	(*args)[ix] = newarg;
> -    }
> -}
> -
>   /* Returns a type which represents 'auto' or 'decltype(auto)'.  We use a
>      TEMPLATE_TYPE_PARM with a level one deeper than the actual template parms,
>      by default.  If set_canonical is true, we set TYPE_CANONICAL on it.  */
> @@ -31523,33 +31505,6 @@ print_template_statistics (void)
>   
>   namespace selftest {
>   
> -/* Verify that build_non_dependent_expr () works, for various expressions,
> -   and that location wrappers don't affect the results.  */
> -
> -static void
> -test_build_non_dependent_expr ()
> -{
> -  location_t loc = BUILTINS_LOCATION;
> -
> -  /* Verify constants, without and with location wrappers.  */
> -  tree int_cst = build_int_cst (integer_type_node, 42);
> -  ASSERT_EQ (int_cst, build_non_dependent_expr (int_cst));
> -
> -  tree wrapped_int_cst = maybe_wrap_with_location (int_cst, loc);
> -  ASSERT_TRUE (location_wrapper_p (wrapped_int_cst));
> -  ASSERT_EQ (wrapped_int_cst, build_non_dependent_expr (wrapped_int_cst));
> -
> -  tree string_lit = build_string (4, "foo");
> -  TREE_TYPE (string_lit) = char_array_type_node;
> -  string_lit = fix_string_type (string_lit);
> -  ASSERT_EQ (string_lit, build_non_dependent_expr (string_lit));
> -
> -  tree wrapped_string_lit = maybe_wrap_with_location (string_lit, loc);
> -  ASSERT_TRUE (location_wrapper_p (wrapped_string_lit));
> -  ASSERT_EQ (wrapped_string_lit,
> -	     build_non_dependent_expr (wrapped_string_lit));
> -}
> -
>   /* Verify that type_dependent_expression_p () works correctly, even
>      in the presence of location wrapper nodes.  */
>   
> @@ -31590,7 +31545,6 @@ test_type_dependent_expression_p ()
>   void
>   cp_pt_cc_tests ()
>   {
> -  test_build_non_dependent_expr ();
>     test_type_dependent_expression_p ();
>   }
>   
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index 80ef1364e33..1d478f0781f 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -916,8 +916,7 @@ finish_expr_stmt (tree expr)
>   	  expr = convert_to_void (expr, ICV_STATEMENT, tf_warning_or_error);
>   	}
>         else if (!type_dependent_expression_p (expr))
> -	convert_to_void (build_non_dependent_expr (expr), ICV_STATEMENT,
> -                         tf_warning_or_error);
> +	convert_to_void (expr, ICV_STATEMENT, tf_warning_or_error);
>   
>         if (check_for_bare_parameter_packs (expr))
>           expr = error_mark_node;
> @@ -1396,8 +1395,7 @@ finish_for_expr (tree expr, tree for_stmt)
>                                 tf_warning_or_error);
>       }
>     else if (!type_dependent_expression_p (expr))
> -    convert_to_void (build_non_dependent_expr (expr), ICV_THIRD_IN_FOR,
> -                     tf_warning_or_error);
> +    convert_to_void (expr, ICV_THIRD_IN_FOR, tf_warning_or_error);
>     expr = maybe_cleanup_point_expr_void (expr);
>     if (check_for_bare_parameter_packs (expr))
>       expr = error_mark_node;
> @@ -2819,11 +2817,6 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
>   	  return result;
>   	}
>         orig_args = make_tree_vector_copy (*args);
> -      if (!BASELINK_P (fn)
> -	  && TREE_CODE (fn) != PSEUDO_DTOR_EXPR
> -	  && TREE_TYPE (fn) != unknown_type_node)
> -	fn = build_non_dependent_expr (fn);
> -      make_args_non_dependent (*args);
>       }
>   
>     if (TREE_CODE (fn) == COMPONENT_REF)
> @@ -11034,20 +11027,6 @@ finish_omp_atomic (location_t loc, enum tree_code code, enum tree_code opcode,
>   	      || TREE_CODE (OMP_CLAUSE_HINT_EXPR (clauses)) != INTEGER_CST)
>   	    dependent_p = true;
>   	}
> -      if (!dependent_p)
> -	{
> -	  lhs = build_non_dependent_expr (lhs);
> -	  if (rhs)
> -	    rhs = build_non_dependent_expr (rhs);
> -	  if (v)
> -	    v = build_non_dependent_expr (v);
> -	  if (lhs1)
> -	    lhs1 = build_non_dependent_expr (lhs1);
> -	  if (rhs1)
> -	    rhs1 = build_non_dependent_expr (rhs1);
> -	  if (r && r != void_list_node)
> -	    r = build_non_dependent_expr (r);
> -	}
>       }
>     if (!dependent_p)
>       {
> diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
> index 2cfa3c8a935..f3dc80c40cf 100644
> --- a/gcc/cp/typeck.cc
> +++ b/gcc/cp/typeck.cc
> @@ -3385,7 +3385,6 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
>   	  return build_min_nt_loc (UNKNOWN_LOCATION, COMPONENT_REF,
>   				   orig_object, orig_name, NULL_TREE);
>   	}
> -      object = build_non_dependent_expr (object);
>       }
>     else if (c_dialect_objc ()
>   	   && identifier_p (name)
> @@ -3743,7 +3742,6 @@ build_x_indirect_ref (location_t loc, tree expr, ref_operator errorstring,
>   	    = build_dependent_operator_type (lookups, INDIRECT_REF, false);
>   	  return expr;
>   	}
> -      expr = build_non_dependent_expr (expr);
>       }
>   
>     rval = build_new_op (loc, INDIRECT_REF, LOOKUP_NORMAL, expr,
> @@ -4712,8 +4710,6 @@ build_x_binary_op (const op_location_t &loc, enum tree_code code, tree arg1,
>   	    = build_dependent_operator_type (lookups, code, false);
>   	  return expr;
>   	}
> -      arg1 = build_non_dependent_expr (arg1);
> -      arg2 = build_non_dependent_expr (arg2);
>       }
>   
>     if (code == DOTSTAR_EXPR)
> @@ -4767,8 +4763,6 @@ build_x_array_ref (location_t loc, tree arg1, tree arg2,
>   	  || type_dependent_expression_p (arg2))
>   	return build_min_nt_loc (loc, ARRAY_REF, arg1, arg2,
>   				 NULL_TREE, NULL_TREE);
> -      arg1 = build_non_dependent_expr (arg1);
> -      arg2 = build_non_dependent_expr (arg2);
>       }
>   
>     expr = build_new_op (loc, ARRAY_REF, LOOKUP_NORMAL, arg1, arg2,
> @@ -6601,10 +6595,6 @@ build_x_vec_perm_expr (location_t loc,
>   	  || type_dependent_expression_p (arg1)
>   	  || type_dependent_expression_p (arg2))
>   	return build_min_nt_loc (loc, VEC_PERM_EXPR, arg0, arg1, arg2);
> -      arg0 = build_non_dependent_expr (arg0);
> -      if (arg1)
> -	arg1 = build_non_dependent_expr (arg1);
> -      arg2 = build_non_dependent_expr (arg2);
>       }
>     tree exp = c_build_vec_perm_expr (loc, arg0, arg1, arg2, complain & tf_error);
>     if (processing_template_decl && exp != error_mark_node)
> @@ -6632,9 +6622,6 @@ build_x_shufflevector (location_t loc, vec<tree, va_gc> *args,
>   	    CALL_EXPR_IFN (exp) = IFN_SHUFFLEVECTOR;
>   	    return exp;
>   	  }
> -      arg0 = build_non_dependent_expr (arg0);
> -      arg1 = build_non_dependent_expr (arg1);
> -      /* ???  Nothing needed for the index arguments?  */
>       }
>     auto_vec<tree, 16> mask;
>     for (unsigned i = 2; i < args->length (); ++i)
> @@ -6804,8 +6791,6 @@ build_x_unary_op (location_t loc, enum tree_code code, cp_expr xarg,
>   	  TREE_TYPE (e) = build_dependent_operator_type (lookups, code, false);
>   	  return e;
>   	}
> -
> -      xarg = build_non_dependent_expr (xarg);
>       }
>   
>     exp = NULL_TREE;
> @@ -6923,8 +6908,6 @@ cp_build_addressof (location_t loc, tree arg, tsubst_flags_t complain)
>       {
>         if (type_dependent_expression_p (arg))
>   	return build_min_nt_loc (loc, ADDRESSOF_EXPR, arg, NULL_TREE);
> -
> -      arg = build_non_dependent_expr (arg);
>       }
>   
>     tree exp = cp_build_addr_expr_strict (arg, complain);
> @@ -7859,10 +7842,6 @@ build_x_conditional_expr (location_t loc, tree ifexp, tree op1, tree op2,
>   	  || (op1 && type_dependent_expression_p (op1))
>   	  || type_dependent_expression_p (op2))
>   	return build_min_nt_loc (loc, COND_EXPR, ifexp, op1, op2);
> -      ifexp = build_non_dependent_expr (ifexp);
> -      if (op1)
> -	op1 = build_non_dependent_expr (op1);
> -      op2 = build_non_dependent_expr (op2);
>       }
>   
>     expr = build_conditional_expr (loc, ifexp, op1, op2, complain);
> @@ -7983,8 +7962,6 @@ build_x_compound_expr (location_t loc, tree op1, tree op2,
>   	    = build_dependent_operator_type (lookups, COMPOUND_EXPR, false);
>   	  return result;
>   	}
> -      op1 = build_non_dependent_expr (op1);
> -      op2 = build_non_dependent_expr (op2);
>       }
>   
>     result = build_new_op (loc, COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2,
> @@ -8556,8 +8533,6 @@ build_static_cast (location_t loc, tree type, tree oexpr,
>         protected_set_expr_location (result, loc);
>         return result;
>       }
> -  else if (processing_template_decl)
> -    expr = build_non_dependent_expr (expr);
>   
>     /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
>        Strip such NOP_EXPRs if VALUE is being used in non-lvalue context.  */
> @@ -9737,9 +9712,6 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
>   	      = build_dependent_operator_type (lookups, modifycode, true);
>   	  return rval;
>   	}
> -
> -      lhs = build_non_dependent_expr (lhs);
> -      rhs = build_non_dependent_expr (rhs);
>       }
>   
>     tree rval;
> @@ -11230,9 +11202,6 @@ check_return_expr (tree retval, bool *no_warning, bool *dangling)
>         if (VOID_TYPE_P (functype))
>   	return error_mark_node;
>   
> -      if (processing_template_decl)
> -	retval = build_non_dependent_expr (retval);
> -
>         /* Under C++11 [12.8/32 class.copy], a returned lvalue is sometimes
>   	 treated as an rvalue for the purposes of overload resolution to
>   	 favor move constructors over copy constructors.
> diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
> index cd1ea045720..5ac8d3d08e9 100644
> --- a/gcc/cp/typeck2.cc
> +++ b/gcc/cp/typeck2.cc
> @@ -2218,7 +2218,6 @@ build_x_arrow (location_t loc, tree expr, tsubst_flags_t complain)
>   	  TREE_TYPE (expr) = ttype;
>   	  return expr;
>   	}
> -      expr = build_non_dependent_expr (expr);
>       }
>   
>     if (MAYBE_CLASS_TYPE_P (type))


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/2] c++: remove NON_DEPENDENT_EXPR, part 2
  2023-09-25 20:43 ` [PATCH 2/2] c++: remove NON_DEPENDENT_EXPR, part 2 Patrick Palka
  2023-10-02 19:37   ` [PATCH] c++: merge tsubst_copy into tsubst_copy_and_build Patrick Palka
  2023-10-19 21:46   ` [PATCH 2/2] c++: remove NON_DEPENDENT_EXPR, part 2 Jason Merrill
@ 2023-10-20 15:57   ` Andrew Pinski
  2 siblings, 0 replies; 13+ messages in thread
From: Andrew Pinski @ 2023-10-20 15:57 UTC (permalink / raw)
  To: Patrick Palka; +Cc: gcc-patches, jason

On Mon, Sep 25, 2023 at 1:43 PM Patrick Palka <ppalka@redhat.com> wrote:
>
> This much more mechanical patch removes build_non_dependent_expr
> (and make_args_non_dependent) and adjusts callers accordingly,
> no functional change.


This broke the RUST front-end which decided to copy/reuse the C++ code
for constexpr and not modify it not to include trees it does not use.
In this case NON_DEPENDENT_EXPR was removed and now the rust front-end
is broken.

Thanks,
Andrew

>
> gcc/cp/ChangeLog:
>
>         * call.cc (build_new_method_call): Remove calls to
>         build_non_dependent_expr and/or make_args_non_dependent.
>         * coroutines.cc (finish_co_return_stmt): Likewise.
>         * cp-tree.h (build_non_dependent_expr): Remove.
>         (make_args_non_dependent): Remove.
>         * decl2.cc (grok_array_decl): Remove calls to
>         build_non_dependent_expr and/or make_args_non_dependent.
>         (build_offset_ref_call_from_tree): Likewise.
>         * init.cc (build_new): Likewise.
>         * pt.cc (make_args_non_dependent): Remove.
>         (test_build_non_dependent_expr): Remove.
>         (cp_pt_cc_tests): Adjust.
>         * semantics.cc (finish_expr_stmt): Remove calls to
>         build_non_dependent_expr and/or make_args_non_dependent.
>         (finish_for_expr): Likewise.
>         (finish_call_expr): Likewise.
>         (finish_omp_atomic): Likewise.
>         * typeck.cc (finish_class_member_access_expr): Likewise.
>         (build_x_indirect_ref): Likewise.
>         (build_x_binary_op): Likewise.
>         (build_x_array_ref): Likewise.
>         (build_x_vec_perm_expr): Likewise.
>         (build_x_shufflevector): Likewise.
>         (build_x_unary_op): Likewise.
>         (cp_build_addressof): Likewise.
>         (build_x_conditional_expr):
>         (build_x_compound_expr): Likewise.
>         (build_static_cast): Likewise.
>         (build_x_modify_expr): Likewise.
>         (check_return_expr): Likewise.
>         * typeck2.cc (build_x_arrow): Likewise.
> ---
>  gcc/cp/call.cc       |  7 +------
>  gcc/cp/coroutines.cc |  3 ---
>  gcc/cp/cp-tree.h     |  2 --
>  gcc/cp/decl2.cc      | 17 +++-------------
>  gcc/cp/init.cc       |  5 -----
>  gcc/cp/pt.cc         | 46 --------------------------------------------
>  gcc/cp/semantics.cc  | 25 ++----------------------
>  gcc/cp/typeck.cc     | 31 -----------------------------
>  gcc/cp/typeck2.cc    |  1 -
>  9 files changed, 6 insertions(+), 131 deletions(-)
>
> diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> index e8dafbd8ba6..15079ddf6dc 100644
> --- a/gcc/cp/call.cc
> +++ b/gcc/cp/call.cc
> @@ -11430,12 +11430,7 @@ build_new_method_call (tree instance, tree fns, vec<tree, va_gc> **args,
>      }
>
>    if (processing_template_decl)
> -    {
> -      orig_args = args == NULL ? NULL : make_tree_vector_copy (*args);
> -      instance = build_non_dependent_expr (instance);
> -      if (args != NULL)
> -       make_args_non_dependent (*args);
> -    }
> +    orig_args = args == NULL ? NULL : make_tree_vector_copy (*args);
>
>    /* Process the argument list.  */
>    if (args != NULL && *args != NULL)
> diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
> index df3cc820797..a5464becf7f 100644
> --- a/gcc/cp/coroutines.cc
> +++ b/gcc/cp/coroutines.cc
> @@ -1351,9 +1351,6 @@ finish_co_return_stmt (location_t kw, tree expr)
>          to undo it so we can try to treat it as an rvalue below.  */
>        expr = maybe_undo_parenthesized_ref (expr);
>
> -      if (processing_template_decl)
> -       expr = build_non_dependent_expr (expr);
> -
>        if (error_operand_p (expr))
>         return error_mark_node;
>      }
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 66b9a9c4b9a..8b9a7d58462 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -7488,8 +7488,6 @@ extern bool any_value_dependent_elements_p      (const_tree);
>  extern bool dependent_omp_for_p                        (tree, tree, tree, tree);
>  extern tree resolve_typename_type              (tree, bool);
>  extern tree template_for_substitution          (tree);
> -inline tree build_non_dependent_expr           (tree t) { return t; } // XXX remove
> -extern void make_args_non_dependent            (vec<tree, va_gc> *);
>  extern bool reregister_specialization          (tree, tree, tree);
>  extern tree instantiate_non_dependent_expr     (tree, tsubst_flags_t = tf_error);
>  extern tree instantiate_non_dependent_expr_internal (tree, tsubst_flags_t);
> diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
> index 344e19ec98b..0aa1e355972 100644
> --- a/gcc/cp/decl2.cc
> +++ b/gcc/cp/decl2.cc
> @@ -427,14 +427,8 @@ grok_array_decl (location_t loc, tree array_expr, tree index_exp,
>           return build_min_nt_loc (loc, ARRAY_REF, array_expr, index_exp,
>                                    NULL_TREE, NULL_TREE);
>         }
> -      array_expr = build_non_dependent_expr (array_expr);
> -      if (index_exp)
> -       index_exp = build_non_dependent_expr (index_exp);
> -      else
> -       {
> -         orig_index_exp_list = make_tree_vector_copy (*index_exp_list);
> -         make_args_non_dependent (*index_exp_list);
> -       }
> +      if (!index_exp)
> +       orig_index_exp_list = make_tree_vector_copy (*index_exp_list);
>      }
>
>    type = TREE_TYPE (array_expr);
> @@ -5435,18 +5429,13 @@ build_offset_ref_call_from_tree (tree fn, vec<tree, va_gc> **args,
>        orig_args = make_tree_vector_copy (*args);
>
>        /* Transform the arguments and add the implicit "this"
> -        parameter.  That must be done before the FN is transformed
> -        because we depend on the form of FN.  */
> -      make_args_non_dependent (*args);
> -      object = build_non_dependent_expr (object);
> +        parameter.  */
>        if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
>         {
>           if (TREE_CODE (fn) == DOTSTAR_EXPR)
>             object = cp_build_addr_expr (object, complain);
>           vec_safe_insert (*args, 0, object);
>         }
> -      /* Now that the arguments are done, transform FN.  */
> -      fn = build_non_dependent_expr (fn);
>      }
>
>    /* A qualified name corresponding to a bound pointer-to-member is
> diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
> index c5830297b93..d1bae3b155f 100644
> --- a/gcc/cp/init.cc
> +++ b/gcc/cp/init.cc
> @@ -3920,11 +3920,6 @@ build_new (location_t loc, vec<tree, va_gc> **placement, tree type,
>                 (**init)[i] = copy_node (e);
>             }
>         }
> -
> -      make_args_non_dependent (*placement);
> -      if (nelts)
> -       nelts = build_non_dependent_expr (nelts);
> -      make_args_non_dependent (*init);
>      }
>
>    if (nelts)
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index e565c0538b7..382db4dd01d 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -29294,24 +29294,6 @@ resolve_typename_type (tree type, bool only_current_p)
>    return result;
>  }
>
> -/* ARGS is a vector of expressions as arguments to a function call.
> -   Replace the arguments with equivalent non-dependent expressions.
> -   This modifies ARGS in place.  */
> -
> -void
> -make_args_non_dependent (vec<tree, va_gc> *args)
> -{
> -  unsigned int ix;
> -  tree arg;
> -
> -  FOR_EACH_VEC_SAFE_ELT (args, ix, arg)
> -    {
> -      tree newarg = build_non_dependent_expr (arg);
> -      if (newarg != arg)
> -       (*args)[ix] = newarg;
> -    }
> -}
> -
>  /* Returns a type which represents 'auto' or 'decltype(auto)'.  We use a
>     TEMPLATE_TYPE_PARM with a level one deeper than the actual template parms,
>     by default.  If set_canonical is true, we set TYPE_CANONICAL on it.  */
> @@ -31523,33 +31505,6 @@ print_template_statistics (void)
>
>  namespace selftest {
>
> -/* Verify that build_non_dependent_expr () works, for various expressions,
> -   and that location wrappers don't affect the results.  */
> -
> -static void
> -test_build_non_dependent_expr ()
> -{
> -  location_t loc = BUILTINS_LOCATION;
> -
> -  /* Verify constants, without and with location wrappers.  */
> -  tree int_cst = build_int_cst (integer_type_node, 42);
> -  ASSERT_EQ (int_cst, build_non_dependent_expr (int_cst));
> -
> -  tree wrapped_int_cst = maybe_wrap_with_location (int_cst, loc);
> -  ASSERT_TRUE (location_wrapper_p (wrapped_int_cst));
> -  ASSERT_EQ (wrapped_int_cst, build_non_dependent_expr (wrapped_int_cst));
> -
> -  tree string_lit = build_string (4, "foo");
> -  TREE_TYPE (string_lit) = char_array_type_node;
> -  string_lit = fix_string_type (string_lit);
> -  ASSERT_EQ (string_lit, build_non_dependent_expr (string_lit));
> -
> -  tree wrapped_string_lit = maybe_wrap_with_location (string_lit, loc);
> -  ASSERT_TRUE (location_wrapper_p (wrapped_string_lit));
> -  ASSERT_EQ (wrapped_string_lit,
> -            build_non_dependent_expr (wrapped_string_lit));
> -}
> -
>  /* Verify that type_dependent_expression_p () works correctly, even
>     in the presence of location wrapper nodes.  */
>
> @@ -31590,7 +31545,6 @@ test_type_dependent_expression_p ()
>  void
>  cp_pt_cc_tests ()
>  {
> -  test_build_non_dependent_expr ();
>    test_type_dependent_expression_p ();
>  }
>
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index 80ef1364e33..1d478f0781f 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -916,8 +916,7 @@ finish_expr_stmt (tree expr)
>           expr = convert_to_void (expr, ICV_STATEMENT, tf_warning_or_error);
>         }
>        else if (!type_dependent_expression_p (expr))
> -       convert_to_void (build_non_dependent_expr (expr), ICV_STATEMENT,
> -                         tf_warning_or_error);
> +       convert_to_void (expr, ICV_STATEMENT, tf_warning_or_error);
>
>        if (check_for_bare_parameter_packs (expr))
>          expr = error_mark_node;
> @@ -1396,8 +1395,7 @@ finish_for_expr (tree expr, tree for_stmt)
>                                tf_warning_or_error);
>      }
>    else if (!type_dependent_expression_p (expr))
> -    convert_to_void (build_non_dependent_expr (expr), ICV_THIRD_IN_FOR,
> -                     tf_warning_or_error);
> +    convert_to_void (expr, ICV_THIRD_IN_FOR, tf_warning_or_error);
>    expr = maybe_cleanup_point_expr_void (expr);
>    if (check_for_bare_parameter_packs (expr))
>      expr = error_mark_node;
> @@ -2819,11 +2817,6 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
>           return result;
>         }
>        orig_args = make_tree_vector_copy (*args);
> -      if (!BASELINK_P (fn)
> -         && TREE_CODE (fn) != PSEUDO_DTOR_EXPR
> -         && TREE_TYPE (fn) != unknown_type_node)
> -       fn = build_non_dependent_expr (fn);
> -      make_args_non_dependent (*args);
>      }
>
>    if (TREE_CODE (fn) == COMPONENT_REF)
> @@ -11034,20 +11027,6 @@ finish_omp_atomic (location_t loc, enum tree_code code, enum tree_code opcode,
>               || TREE_CODE (OMP_CLAUSE_HINT_EXPR (clauses)) != INTEGER_CST)
>             dependent_p = true;
>         }
> -      if (!dependent_p)
> -       {
> -         lhs = build_non_dependent_expr (lhs);
> -         if (rhs)
> -           rhs = build_non_dependent_expr (rhs);
> -         if (v)
> -           v = build_non_dependent_expr (v);
> -         if (lhs1)
> -           lhs1 = build_non_dependent_expr (lhs1);
> -         if (rhs1)
> -           rhs1 = build_non_dependent_expr (rhs1);
> -         if (r && r != void_list_node)
> -           r = build_non_dependent_expr (r);
> -       }
>      }
>    if (!dependent_p)
>      {
> diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
> index 2cfa3c8a935..f3dc80c40cf 100644
> --- a/gcc/cp/typeck.cc
> +++ b/gcc/cp/typeck.cc
> @@ -3385,7 +3385,6 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
>           return build_min_nt_loc (UNKNOWN_LOCATION, COMPONENT_REF,
>                                    orig_object, orig_name, NULL_TREE);
>         }
> -      object = build_non_dependent_expr (object);
>      }
>    else if (c_dialect_objc ()
>            && identifier_p (name)
> @@ -3743,7 +3742,6 @@ build_x_indirect_ref (location_t loc, tree expr, ref_operator errorstring,
>             = build_dependent_operator_type (lookups, INDIRECT_REF, false);
>           return expr;
>         }
> -      expr = build_non_dependent_expr (expr);
>      }
>
>    rval = build_new_op (loc, INDIRECT_REF, LOOKUP_NORMAL, expr,
> @@ -4712,8 +4710,6 @@ build_x_binary_op (const op_location_t &loc, enum tree_code code, tree arg1,
>             = build_dependent_operator_type (lookups, code, false);
>           return expr;
>         }
> -      arg1 = build_non_dependent_expr (arg1);
> -      arg2 = build_non_dependent_expr (arg2);
>      }
>
>    if (code == DOTSTAR_EXPR)
> @@ -4767,8 +4763,6 @@ build_x_array_ref (location_t loc, tree arg1, tree arg2,
>           || type_dependent_expression_p (arg2))
>         return build_min_nt_loc (loc, ARRAY_REF, arg1, arg2,
>                                  NULL_TREE, NULL_TREE);
> -      arg1 = build_non_dependent_expr (arg1);
> -      arg2 = build_non_dependent_expr (arg2);
>      }
>
>    expr = build_new_op (loc, ARRAY_REF, LOOKUP_NORMAL, arg1, arg2,
> @@ -6601,10 +6595,6 @@ build_x_vec_perm_expr (location_t loc,
>           || type_dependent_expression_p (arg1)
>           || type_dependent_expression_p (arg2))
>         return build_min_nt_loc (loc, VEC_PERM_EXPR, arg0, arg1, arg2);
> -      arg0 = build_non_dependent_expr (arg0);
> -      if (arg1)
> -       arg1 = build_non_dependent_expr (arg1);
> -      arg2 = build_non_dependent_expr (arg2);
>      }
>    tree exp = c_build_vec_perm_expr (loc, arg0, arg1, arg2, complain & tf_error);
>    if (processing_template_decl && exp != error_mark_node)
> @@ -6632,9 +6622,6 @@ build_x_shufflevector (location_t loc, vec<tree, va_gc> *args,
>             CALL_EXPR_IFN (exp) = IFN_SHUFFLEVECTOR;
>             return exp;
>           }
> -      arg0 = build_non_dependent_expr (arg0);
> -      arg1 = build_non_dependent_expr (arg1);
> -      /* ???  Nothing needed for the index arguments?  */
>      }
>    auto_vec<tree, 16> mask;
>    for (unsigned i = 2; i < args->length (); ++i)
> @@ -6804,8 +6791,6 @@ build_x_unary_op (location_t loc, enum tree_code code, cp_expr xarg,
>           TREE_TYPE (e) = build_dependent_operator_type (lookups, code, false);
>           return e;
>         }
> -
> -      xarg = build_non_dependent_expr (xarg);
>      }
>
>    exp = NULL_TREE;
> @@ -6923,8 +6908,6 @@ cp_build_addressof (location_t loc, tree arg, tsubst_flags_t complain)
>      {
>        if (type_dependent_expression_p (arg))
>         return build_min_nt_loc (loc, ADDRESSOF_EXPR, arg, NULL_TREE);
> -
> -      arg = build_non_dependent_expr (arg);
>      }
>
>    tree exp = cp_build_addr_expr_strict (arg, complain);
> @@ -7859,10 +7842,6 @@ build_x_conditional_expr (location_t loc, tree ifexp, tree op1, tree op2,
>           || (op1 && type_dependent_expression_p (op1))
>           || type_dependent_expression_p (op2))
>         return build_min_nt_loc (loc, COND_EXPR, ifexp, op1, op2);
> -      ifexp = build_non_dependent_expr (ifexp);
> -      if (op1)
> -       op1 = build_non_dependent_expr (op1);
> -      op2 = build_non_dependent_expr (op2);
>      }
>
>    expr = build_conditional_expr (loc, ifexp, op1, op2, complain);
> @@ -7983,8 +7962,6 @@ build_x_compound_expr (location_t loc, tree op1, tree op2,
>             = build_dependent_operator_type (lookups, COMPOUND_EXPR, false);
>           return result;
>         }
> -      op1 = build_non_dependent_expr (op1);
> -      op2 = build_non_dependent_expr (op2);
>      }
>
>    result = build_new_op (loc, COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2,
> @@ -8556,8 +8533,6 @@ build_static_cast (location_t loc, tree type, tree oexpr,
>        protected_set_expr_location (result, loc);
>        return result;
>      }
> -  else if (processing_template_decl)
> -    expr = build_non_dependent_expr (expr);
>
>    /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
>       Strip such NOP_EXPRs if VALUE is being used in non-lvalue context.  */
> @@ -9737,9 +9712,6 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
>               = build_dependent_operator_type (lookups, modifycode, true);
>           return rval;
>         }
> -
> -      lhs = build_non_dependent_expr (lhs);
> -      rhs = build_non_dependent_expr (rhs);
>      }
>
>    tree rval;
> @@ -11230,9 +11202,6 @@ check_return_expr (tree retval, bool *no_warning, bool *dangling)
>        if (VOID_TYPE_P (functype))
>         return error_mark_node;
>
> -      if (processing_template_decl)
> -       retval = build_non_dependent_expr (retval);
> -
>        /* Under C++11 [12.8/32 class.copy], a returned lvalue is sometimes
>          treated as an rvalue for the purposes of overload resolution to
>          favor move constructors over copy constructors.
> diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
> index cd1ea045720..5ac8d3d08e9 100644
> --- a/gcc/cp/typeck2.cc
> +++ b/gcc/cp/typeck2.cc
> @@ -2218,7 +2218,6 @@ build_x_arrow (location_t loc, tree expr, tsubst_flags_t complain)
>           TREE_TYPE (expr) = ttype;
>           return expr;
>         }
> -      expr = build_non_dependent_expr (expr);
>      }
>
>    if (MAYBE_CLASS_TYPE_P (type))
> --
> 2.42.0.270.gbcb6cae296
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2023-10-20 15:57 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-09-25 20:43 [PATCH 1/2] c++: remove NON_DEPENDENT_EXPR, part 1 Patrick Palka
2023-09-25 20:43 ` [PATCH 2/2] c++: remove NON_DEPENDENT_EXPR, part 2 Patrick Palka
2023-10-02 19:37   ` [PATCH] c++: merge tsubst_copy into tsubst_copy_and_build Patrick Palka
2023-10-03 12:41     ` Patrick Palka
2023-10-03 21:57       ` Jason Merrill
2023-10-04 16:08         ` Patrick Palka
2023-10-04 19:23           ` [PATCH 2/1] c++: rename tsubst_copy_and_build and tsubst_expr Patrick Palka
2023-10-19 21:43             ` Jason Merrill
2023-10-19 21:43           ` [PATCH] c++: merge tsubst_copy into tsubst_copy_and_build Jason Merrill
2023-10-19 21:46   ` [PATCH 2/2] c++: remove NON_DEPENDENT_EXPR, part 2 Jason Merrill
2023-10-20 15:57   ` Andrew Pinski
2023-09-26 23:18 ` [PATCH 1/2] c++: remove NON_DEPENDENT_EXPR, part 1 Jason Merrill
2023-09-27 11:54   ` 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).