/* PR c/71924 - missing -Wreturn-local-addr returning alloca result
   { dg-do compile }
   { dg-options "-O2 -Wall" }
   { dg-require-effective-target alloca } */

#define ATTR(...) __attribute__ ((__VA_ARGS__))

struct A { int a, b, c; };
struct B { int a, b, c[]; };

void sink (void*, ...);

ATTR (noipa) void*
return_alloca (int n)
{
  void *p = __builtin_alloca (n);
  sink (p);
  return p;         /* { dg-warning "function returns address of local" } */
}

ATTR (noipa) void*
return_alloca_index_cst (int n)
{
  int *p = (int*)__builtin_alloca (n);
  p = &p[1];
  sink (p);
  return p;         /* { dg-warning "function returns address of local" } */
}

ATTR (noipa) void*
return_alloca_plus_cst (int n)
{
  int *p = (int*)__builtin_alloca (n);
  p += 1;
  sink (p);
  return p;         /* { dg-warning "function returns address of local" } */
}

ATTR (noipa) void*
return_alloca_plus_var (int n, int i)
{
  char *p = (char*)__builtin_alloca (n);
  p += i;
  sink (p);
  return p;         /* { dg-warning "function returns address of local" } */
}

ATTR (noipa) void*
return_alloca_member_1 (int n)
{
  struct A *p = (struct A*)__builtin_alloca (n);
  sink (&p->a);
  return &p->a;     /* { dg-warning "function returns address of local" } */
}

ATTR (noipa) void*
return_alloca_member_2 (int n)
{
  struct A *p = (struct A*)__builtin_alloca (n);
  sink (&p->b);
  return &p->b;     /* { dg-warning "function returns address of local" } */
}

ATTR (noipa) void*
return_alloca_flexarray (int n)
{
  struct B *p = (struct B*)__builtin_alloca (n);
  sink (p->c);
  return p->c;      /* { dg-warning "function returns address of local" } */
}


ATTR (noipa) void*
return_array (void)
{
  int a[32];
  void *p = a;
  sink (p);
  return p;         /* { dg-warning "function returns address of local" } */
}

ATTR (noipa) void*
return_array_index_cst (void)
{
  int a[32];
  void *p = &a[2];
  sink (p);
  return p;         /* { dg-warning "function returns address of local" } */
}

ATTR (noipa) void*
return_array_plus_cst (void)
{
  int a[32];
  void *p = a + 2;
  sink (p);
  return p;         /* { dg-warning "function returns address of local" } */
}

ATTR (noipa) void*
return_array_plus_var (int i)
{
  int a[32];
  void *p = a + i;
  sink (p);
  return p;         /* { dg-warning "function returns address of local" } */
}

ATTR (noipa) void*
return_array_member_1 (void)
{
  struct A a[2];
  int *p = &a[1].a;
  sink (a, p);
  return p;         /* { dg-warning "function returns address of local" } */
}

ATTR (noipa) void*
return_array_member_2 (void)
{
  struct A a[32];
  int *p = &a[1].b;
  sink (a, p);
  return p;         /* { dg-warning "function returns address of local" } */
}


ATTR (noipa) void*
return_vla (int n)
{
  char a[n];
  void *p = a;
  sink (p);
  return p;   /* { dg-warning "function returns address of local" } */
}

ATTR (noipa) void*
return_vla_index_cst (int n)
{
  char a[n];
  char *p = &a[3];
  sink (p);
  return p;   /* { dg-warning "function returns address of local" } */
}

ATTR (noipa) void*
return_vla_plus_cst (int n)
{
  char a[n];
  char *p = a + 3;
  sink (p);
  return p;   /* { dg-warning "function returns address of local" } */
}

ATTR (noipa) void*
return_vla_index_var (int n, int i)
{
  char a[n];
  char *p = &a[i];
  sink (p);
  return p;   /* { dg-warning "function returns address of local" } */
}

ATTR (noipa) void*
return_vla_plus_var (int n, int i)
{
  char a[n];
  char *p = a + i;
  sink (p);
  return p;   /* { dg-warning "function returns address of local" } */
}

ATTR (noipa) void*
return_vla_member_1 (int n, int i)
{
  struct A a[n];
  void *p = &a[i].a;
  sink (a, p);
  return p;   /* { dg-warning "function returns address of local" } */
}

ATTR (noipa) void*
return_vla_member_2 (int n, int i)
{
  struct A a[n];
  void *p = &a[i].b;
  sink (a, p);
  return p;   /* { dg-warning "function returns address of local" } */
}


ATTR (noipa) void*
return_alloca_or_alloca (int n, int i)
{
  void *p = i ? __builtin_alloca (n * i) : __builtin_alloca (n);
  sink (p);
  /* The warning here should really be "function returns".  */
  return p;   /* { dg-warning "function (returns|may return) address of local" } */
}

ATTR (noipa) void*
return_alloca_or_alloca_2 (int n, int i)
{
  void *p0 = __builtin_alloca (n);
  void *p1 = __builtin_alloca (n * 2);
  void *p = i ? p0 : p1;
  sink (p0, p1, p);
  /* Same as above.  */
  return p;   /* { dg-warning "function (returns|may return) address of local" } */
}

ATTR (noipa) void*
return_array_or_array (int i)
{
  int a[5];
  int b[7];
  void *p = i ? a : b;
  sink (a, b, p);
  /* The warning here should really be "function returns".  */
  return p;   /* { dg-warning "function (returns|may return) address of local" } */
}

ATTR (noipa) void*
return_array_or_array_plus_var (int i, int j)
{
  int a[5];
  int b[7];

  void *p0 = a + i;
  void *p1 = b + j;

  void *p = i < j ? p0 : p1;
  sink (a, b, p0, p1, p);
  /* The warning here should really be "function returns".  */
  return p;   /* { dg-warning "function (returns|may return) address of local" } */
}

extern int global[32];

ATTR (noipa) void*
may_return_global_or_alloca (int n, int i)
{
  void *p = i ? global : __builtin_alloca (n);
  sink (p);
  return p;   /* { dg-warning "function may return address of local" } */
}


ATTR (noipa) void*
may_return_global_or_alloca_plus_cst (int n, int i)
{
  int *p = i ? global : (int*)__builtin_alloca (n);
  p += 7;
  sink (p);
  return p;   /* { dg-warning "function may return address of local" } */
}

ATTR (noipa) void*
may_return_global_or_array (int n, int i)
{
  int a[32];
  void *p = i ? global : a;
  sink (p);
  return p;   /* { dg-warning "function may return address of local" } */
}

ATTR (noipa) void*
may_return_global_or_array_plus_cst (int n, int i)
{
  int a[32];
  int *p = i ? global : a;
  p += 4;
  sink (p);
  return p;   /* { dg-warning "function may return address of local" } */
}

ATTR (noipa) void*
may_return_global_or_vla (int n, int i)
{
  int a[n];
  void *p = i ? global : a;
  sink (p);
  return p;   /* { dg-warning "function may return address of local" } */
}

ATTR (noipa) void*
may_return_global_or_vla_plus_cst (int n, int i)
{
  int a[n];
  int *p = i ? global : a;
  p += 4;
  sink (p);
  return p;   /* { dg-warning "function may return address of local" } */
}
