/* PR tree-optimization/84095 - false-positive -Wrestrict warnings for
   memcpy within array
   { dg-do compile }
   { dg-options "-O2 -Wrestrict -ftrack-macro-expansion=0" } */

typedef __SIZE_TYPE__ size_t;

extern void* memcpy (void* restrict, const void* restrict, size_t);

void foo (void *);

#define T(d, s, n)   do { memcpy (d, s, n); foo (d); } while (0)

struct S1 { char c; } a8_1[8];

void test_1_dim_var (int i, int j)
{
  /* Variable destination index and constant source index.  */
  T (&a8_1[i], &a8_1[0], 1);
  T (&a8_1[i], &a8_1[0], 2);
  T (&a8_1[i], &a8_1[0], 3);
  T (&a8_1[i], &a8_1[0], 4);

  T (&a8_1[i], &a8_1[0], 5);    /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and 0 overlaps between 2 and 5 bytes at offset \\\[0, 3\\\]" } */
  T (&a8_1[i], &a8_1[0], 6);    /* { dg-warning "accessing 6 bytes at offsets \\\[0, 8] and 0 overlaps between 4 and 6 bytes at offset \\\[0, 2\\\]" } */
  T (&a8_1[i], &a8_1[0], 7);    /* { dg-warning "accessing 7 bytes at offsets \\\[0, 8] and 0 overlaps between 6 and 7 bytes at offset \\\[0, 1\\\]" } */
  T (&a8_1[i], &a8_1[0], 8);    /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and 0 overlaps 8 bytes at offset 0" } */

  /* The following is diagnosed by -Warray-bounds when it's enabled
     rather than by -Wrestrict.  */
  T (&a8_1[i], &a8_1[0], 9);    /* { dg-warning "accessing 9 bytes at offsets \\\[0, 8] and 0 overlaps 9 bytes at offset 0" } */

  /* Same as above but with constant destination index and variable
     source index.  */
  T (&a8_1[0], &a8_1[i], 1);
  T (&a8_1[0], &a8_1[i], 2);
  T (&a8_1[0], &a8_1[i], 3);
  T (&a8_1[0], &a8_1[i], 4);

  T (&a8_1[0], &a8_1[i], 5);    /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[0, 8] overlaps between 2 and 5 bytes at offset \\\[0, 3\\\]" } */
  T (&a8_1[0], &a8_1[i], 6);    /* { dg-warning "accessing 6 bytes at offsets 0 and \\\[0, 8] overlaps between 4 and 6 bytes at offset \\\[0, 2\\\]" } */
  T (&a8_1[0], &a8_1[i], 7);    /* { dg-warning "accessing 7 bytes at offsets 0 and \\\[0, 8] overlaps between 6 and 7 bytes at offset \\\[0, 1\\\]" } */
  T (&a8_1[0], &a8_1[i], 8);    /* { dg-warning "accessing 8 bytes at offsets 0 and \\\[0, 8] overlaps 8 bytes at offset 0" } */
  T (&a8_1[0], &a8_1[i], 9);    /* { dg-warning "accessing 9 bytes at offsets 0 and \\\[0, 8] overlaps 9 bytes at offset 0" } */


  /* Variable destination and source indices.  */
  T (&a8_1[i], &a8_1[j], 1);
  T (&a8_1[i], &a8_1[j], 2);
  T (&a8_1[i], &a8_1[j], 3);
  T (&a8_1[i], &a8_1[j], 4);

  T (&a8_1[i], &a8_1[j], 5);    /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps between 2 and 5 bytes at offset \\\[0, 3\\\]" } */
  T (&a8_1[i], &a8_1[j], 6);    /* { dg-warning "accessing 6 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps between 4 and 6 bytes at offset \\\[0, 2\\\]" } */
  T (&a8_1[i], &a8_1[j], 7);    /* { dg-warning "accessing 7 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps between 6 and 7 bytes at offset \\\[0, 1\\\]" } */
  T (&a8_1[i], &a8_1[j], 8);    /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps 8 bytes at offset 0" } */

  /* The following is diagnosed by -Warray-bounds when it's enabled
     rather than by -Wrestrict.  */
  T (&a8_1[i], &a8_1[j], 9);    /* { dg-warning "accessing 9 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps 9 bytes at offset 0" } */
}

struct S4 { char a4[4]; } a2_4[2];

void test_2_dim (int i, int j)
{
  T (&a2_4[i], &a2_4[0], 1);
  T (&a2_4[i], &a2_4[0], 4);

  T (&a2_4[i], &a2_4[0], 5);    /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and 0 overlaps between 2 and 5 bytes at offset \\\[0, 3]" } */
  T (&a2_4[i], &a2_4[0], 6);    /* { dg-warning "accessing 6 bytes at offsets \\\[0, 8] and 0 overlaps between 4 and 6 bytes at offset \\\[0, 2]" } */
  T (&a2_4[i], &a2_4[0], 7);    /* { dg-warning "accessing 7 bytes at offsets \\\[0, 8] and 0 overlaps between 6 and 7 bytes at offset \\\[0, 1]" } */
  T (&a2_4[i], &a2_4[0], 8);    /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and 0 overlaps 8 bytes at offset 0" } */

  T (a2_4[i].a4, a2_4[0].a4, 1);
  T (a2_4[i].a4, a2_4[0].a4, 4);

  T (a2_4[i].a4, a2_4[0].a4, 5);   /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and 0 overlaps between 2 and 5 bytes at offset \\\[0, 3]" } */
  T (a2_4[i].a4, a2_4[0].a4, 8);   /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and 0 overlaps 8 bytes at offset 0" } */

  T (a2_4[i].a4, a2_4[j].a4, 1);
  T (a2_4[i].a4, a2_4[j].a4, 4);

  /* The destination and source offsets printed below ignore the size
     of the copy and only indicate the values that are valid for each
     of the destination and source arguments on its own, without
     considering the size of the overlapping access.  */
  T (a2_4[i].a4, a2_4[j].a4, 5);   /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps between 2 and 5 bytes at offset \\\[0, 3]" } */
  T (a2_4[i].a4, a2_4[j].a4, 8);   /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps 8 bytes at offset 0" } */

  /* Same as above but referencing the first elements of each array.  */
  T (&a2_4[i].a4[0], &a2_4[j].a4[0], 1);
  T (&a2_4[i].a4[0], &a2_4[j].a4[0], 4);

  T (&a2_4[i].a4[0], &a2_4[j].a4[0], 5);   /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps between 2 and 5 bytes at offset \\\[0, 3]" } */
  T (&a2_4[i].a4[0], &a2_4[j].a4[0], 8);   /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps 8 bytes at offset 0" } */

  T (&a2_4[i].a4[0], &a2_4[j].a4[1], 3);
  T (&a2_4[i].a4[0], &a2_4[j].a4[2], 2);
  T (&a2_4[i].a4[0], &a2_4[j].a4[3], 1);
}

struct { int i; } a2[2][8];

void test_single_2_dim_major (int i)
{
  memcpy (&a2[i], &a2[0], sizeof *a2);   /* { dg-bogus "\\\[-Wrestrict]" } */
}

void test_single_2_dim_minor (int i)
{
  memcpy (&a2[i][0], &a2[0][0], sizeof a2[0][0]);   /* { dg-bogus "\\\[-Wrestrict]" } */
}

void test_single_2_dim_major_minor (int i, int j)
{
  memcpy (&a2[i][j], &a2[0][0], sizeof a2[0][0]);   /* { dg-bogus "\\\[-Wrestrict]" } */
}
