On 12/18/18 4:12 PM, H.J. Lu wrote:
On Tue, Dec 18, 2018 at 12:36 PM Jason Merrill <ja...@redhat.com> wrote:

On 12/18/18 9:10 AM, H.J. Lu wrote:
+  switch (TREE_CODE (rhs))
+    {
+    case ADDR_EXPR:
+      base = TREE_OPERAND (rhs, 0);
+      while (handled_component_p (base))
+     {
+       if (TREE_CODE (base) == COMPONENT_REF)
+         break;
+       base = TREE_OPERAND (base, 0);
+     }
+      if (TREE_CODE (base) != COMPONENT_REF)
+     return NULL_TREE;
+      object = TREE_OPERAND (base, 0);
+      field = TREE_OPERAND (base, 1);
+      break;
+    case COMPONENT_REF:
+      object = TREE_OPERAND (rhs, 0);
+      field = TREE_OPERAND (rhs, 1);
+      break;
+    default:
+      return NULL_TREE;
+    }
+
+  tree context = check_alignment_of_packed_member (type, field);
+  if (context)
+    return context;
+
+  /* Check alignment of the object.  */
+  while (TREE_CODE (object) == COMPONENT_REF)
+    {
+      field = TREE_OPERAND (object, 1);
+      context = check_alignment_of_packed_member (type, field);
+      if (context)
+     return context;
+      object = TREE_OPERAND (object, 0);
+    }
+

You can see interleaved COMPONENT_REF and ARRAY_REF that this still
doesn't look like it will handle, something like

struct A
{
    int i;
};

struct B
{
    char c;
    __attribute ((packed)) A ar[4];
};

B b;

int *p = &b.ar[1].i;

Rather than have a loop in the ADDR_EXPR case of the switch, you can
handle everything in the lower loop.  And not have a switch at all, just
strip any ADDR_EXPR before the loop.

I changed it to

  if (TREE_CODE (rhs) == ADDR_EXPR)
     rhs = TREE_OPERAND (rhs, 0);
   while (handled_component_p (rhs))
     {
       if (TREE_CODE (rhs) == COMPONENT_REF)
         break;
       rhs = TREE_OPERAND (rhs, 0);
     }

   if (TREE_CODE (rhs) != COMPONENT_REF)
     return NULL_TREE;

   object = TREE_OPERAND (rhs, 0);
   field = TREE_OPERAND (rhs, 1);

That still doesn't warn about my testcase above.

[hjl@gnu-cfl-1 pr51628-6]$ cat a.i
struct A
{
    int i;
} __attribute ((packed));

struct B
{
    char c;
    struct A ar[4];
};

struct B b;

int *p = &b.ar[1].i;

This testcase is importantly different because 'i' is packed, whereas in my testcase only the ar member of B is packed.

My suggestion was that this loop:

+  /* Check alignment of the object.  */
+  while (TREE_CODE (object) == COMPONENT_REF)
+    {
+      field = TREE_OPERAND (object, 1);
+      context = check_alignment_of_packed_member (type, field);
+      if (context)
+       return context;
+      object = TREE_OPERAND (object, 0);
+    }

could loop over all handled_component_p, but only call check_alignment_of_packed_member for COMPONENT_REF.

+  if (TREE_CODE (rhs) != COND_EXPR)
+    {
+      while (TREE_CODE (rhs) == COMPOUND_EXPR)
+       rhs = TREE_OPERAND (rhs, 1);

What if you have a COND_EXPR inside a COMPOUND_EXPR?

Jason

Reply via email to