+
+/* Similar, but look for a PLACEHOLDER_EXPR in EXP and find a replacement
+ for it within OBJ, a tree that is an object or a chain of references. */
+
+tree
+substitute_placeholder_in_expr (tree exp, tree obj)
+{
+ enum tree_code code = TREE_CODE (exp);
+ tree op0, op1, op2;
+
+ /* If this is a PLACEHOLDER_EXPR, see if we find a corresponding type
+ in the chain of OBJ. */
+ if (code == PLACEHOLDER_EXPR)
+ {
+ tree need_type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
+ tree elt;
+
+ for (elt = obj; elt != 0;
+ elt = ((TREE_CODE (elt) == COMPOUND_EXPR
+ || TREE_CODE (elt) == COND_EXPR)
+ ? TREE_OPERAND (elt, 1)
+ : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
+ ? TREE_OPERAND (elt, 0) : 0))
+ if (TYPE_MAIN_VARIANT (TREE_TYPE (elt)) == need_type)
+ return elt;
+
+ for (elt = obj; elt != 0;
+ elt = ((TREE_CODE (elt) == COMPOUND_EXPR
+ || TREE_CODE (elt) == COND_EXPR)
+ ? TREE_OPERAND (elt, 1)
+ : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
+ ? TREE_OPERAND (elt, 0) : 0))
+ if (POINTER_TYPE_P (TREE_TYPE (elt))
+ && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (elt)))
+ == need_type))
+ return fold (build1 (INDIRECT_REF, need_type, elt));
+
+ /* If we didn't find it, return the original PLACEHOLDER_EXPR. If it
+ survives until RTL generation, there will be an error. */
+ return exp;
+ }
+
+ /* TREE_LIST is special because we need to look at TREE_VALUE
+ and TREE_CHAIN, not TREE_OPERANDS. */
+ else if (code == TREE_LIST)
+ {
+ op0 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_CHAIN (exp), obj);
+ op1 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_VALUE (exp), obj);
+ if (op0 == TREE_CHAIN (exp) && op1 == TREE_VALUE (exp))
+ return exp;
+
+ return tree_cons (TREE_PURPOSE (exp), op1, op0);
+ }
+ else
+ switch (TREE_CODE_CLASS (code))
+ {
+ case 'c':
+ case 'd':
+ case 'b':
+ return exp;
+
+ case 'x':
+ case '1':
+ case '2':
+ case '<':
+ case 'e':
+ case 'r':
+ case 's':
+ switch (first_rtl_op (code))
+ {
+ case 0:
+ return exp;
+
+ case 1:
+ op0 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 0), obj);
+ if (op0 == TREE_OPERAND (exp, 0))
+ return exp;
+ else
+ return fold (build1 (code, TREE_TYPE (exp), op0));
+
+ case 2:
+ op0 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 0), obj);
+ op1 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 1), obj);
+
+ if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1))
+ return exp;
+ else
+ return fold (build2 (code, TREE_TYPE (exp), op0, op1));
+
+ case 3:
+ op0 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 0), obj);
+ op1 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 1), obj);
+ op2 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 2), obj);
+
+ if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1)
+ && op2 == TREE_OPERAND (exp, 2))
+ return exp;
+ else
+ return fold (build3 (code, TREE_TYPE (exp), op0, op1, op2));
+
+ default:
+ abort ();
+ }
+ break;
+
+ default:
+ abort ();
+ }
+}