https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98597

--- Comment #9 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
That would be then following (though I didn't want to touch the rest of
print_mem_ref so the patch doesn't remember op anywhere and resets byte_off
too).
--- gcc/c-family/c-pretty-print.c.jj    2021-01-13 08:02:09.425498954 +0100
+++ gcc/c-family/c-pretty-print.c       2021-01-13 15:02:57.860329998 +0100
@@ -1809,6 +1809,113 @@ pp_c_call_argument_list (c_pretty_printe
   pp_c_right_paren (pp);
 }

+/* Try to fold *(type *)&op into op.fld.fld2[1] if possible.
+   Only used for printing expressions.  Should punt if ambiguous
+   (e.g. in unions).  */
+
+static tree
+c_fold_indirect_ref_for_warn (location_t loc, tree type, tree op,
+                             offset_int &off)
+{
+  tree optype = TREE_TYPE (op);
+  if (off == 0)
+    {
+      if (lang_hooks.types_compatible_p (optype, type))
+       return op;
+      /* *(foo *)&complexfoo => __real__ complexfoo */
+      else if (TREE_CODE (optype) == COMPLEX_TYPE
+              && lang_hooks.types_compatible_p (type, TREE_TYPE (optype)))
+       return build1_loc (loc, REALPART_EXPR, type, op);
+    }
+  /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */
+  else if (TREE_CODE (optype) == COMPLEX_TYPE
+          && lang_hooks.types_compatible_p (type, TREE_TYPE (optype))
+          && tree_to_uhwi (TYPE_SIZE_UNIT (type)) == off)
+    {
+      off = 0;
+      return build1_loc (loc, IMAGPART_EXPR, type, op);
+    }
+  /* ((foo *)&fooarray)[x] => fooarray[x] */
+  if (TREE_CODE (optype) == ARRAY_TYPE
+      && TYPE_SIZE_UNIT (TREE_TYPE (optype))
+      && TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (optype))) == INTEGER_CST
+      && !integer_zerop (TYPE_SIZE_UNIT (TREE_TYPE (optype))))
+    {
+      tree type_domain = TYPE_DOMAIN (optype);
+      tree min_val = size_zero_node;
+      if (type_domain && TYPE_MIN_VALUE (type_domain))
+       min_val = TYPE_MIN_VALUE (type_domain);
+      offset_int el_sz = wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (optype)));
+      offset_int idx = off / el_sz;
+      offset_int rem = off % el_sz;
+      if (TREE_CODE (min_val) == INTEGER_CST)
+       {
+         tree index
+           = wide_int_to_tree (sizetype, idx + wi::to_offset (min_val));
+         op = build4_loc (loc, ARRAY_REF, TREE_TYPE (optype), op, index,
+                          NULL_TREE, NULL_TREE);
+         off = rem;
+         if (tree ret = c_fold_indirect_ref_for_warn (loc, type, op, off))
+           return ret;
+         return op;
+       }
+    }
+  /* ((foo *)&struct_with_foo_field)[x] => COMPONENT_REF */
+  else if (TREE_CODE (optype) == RECORD_TYPE)
+    {
+      for (tree field = TYPE_FIELDS (optype);
+          field; field = DECL_CHAIN (field))
+       if (TREE_CODE (field) == FIELD_DECL
+           && TREE_TYPE (field) != error_mark_node
+           && TYPE_SIZE_UNIT (TREE_TYPE (field))
+           && TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (field))) == INTEGER_CST)
+         {
+           tree pos = byte_position (field);
+           if (TREE_CODE (pos) != INTEGER_CST)
+             continue;
+           offset_int upos = wi::to_offset (pos);
+           offset_int el_sz
+             = wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (field)));
+           if (upos <= off && off < upos + el_sz)
+             {
+               tree cop = build3_loc (loc, COMPONENT_REF, TREE_TYPE (field),
+                                      op, field, NULL_TREE);
+               off = off - upos;
+               if (tree ret = c_fold_indirect_ref_for_warn (loc, type, cop,
+                                                            off))
+                 return ret;
+               return cop;
+             }
+         }
+    }
+  /* Similarly for unions, but in this case try to be very conservative,
+     only match if some field has type compatible with type and it is the
+     only such field.  */
+  else if (TREE_CODE (optype) == UNION_TYPE)
+    {
+      tree fld = NULL_TREE;
+      for (tree field = TYPE_FIELDS (optype);
+          field; field = DECL_CHAIN (field))
+       if (TREE_CODE (field) == FIELD_DECL
+           && TREE_TYPE (field) != error_mark_node
+           && lang_hooks.types_compatible_p (TREE_TYPE (field), type))
+         {
+           if (fld)
+             return NULL_TREE;
+           else
+             fld = field;
+         }
+      if (fld)
+       {
+         off = 0;
+         return build3_loc (loc, COMPONENT_REF, TREE_TYPE (fld), op, fld,
+                            NULL_TREE);
+       }
+    }
+
+  return NULL_TREE;
+}
+
 /* Print the MEM_REF expression REF, including its type and offset.
    Apply casts as necessary if the type of the access is different
    from the type of the accessed object.  Produce compact output
@@ -1836,6 +1943,17 @@ print_mem_ref (c_pretty_printer *pp, tre
   const bool addr = TREE_CODE (arg) == ADDR_EXPR;
   if (addr)
     {
+      tree op
+       = c_fold_indirect_ref_for_warn (EXPR_LOCATION (e), TREE_TYPE (e),
+                                       TREE_OPERAND (arg, 0), byte_off);
+      if (op
+         && byte_off == 0
+         && lang_hooks.types_compatible_p (TREE_TYPE (e), TREE_TYPE (op)))
+       {
+         pp->expression (op);
+         return;
+       }
+      byte_off = wi::to_offset (TREE_OPERAND (e, 1));
       arg = TREE_OPERAND (arg, 0);
       if (byte_off == 0)
        {

Reply via email to