(root)/
gcc-13.2.0/
gcc/
testsuite/
gcc.dg/
Winfinite-recursion.c
       1  /* PR middle-end/88232 - Please implement -Winfinite-recursion
       2     Verify simple cases without optimization.
       3     { dg-do compile }
       4     { dg-options "-Wall -Winfinite-recursion" } */
       5  
       6  #define NORETURN __attribute__ ((noreturn))
       7  
       8  typedef __SIZE_TYPE__ size_t;
       9  
      10  extern void abort (void);
      11  extern void exit (int);
      12  
      13  extern int ei;
      14  int (*pfi_v)(void);
      15  
      16  
      17  /* Make sure the warning doesn't assume every call has a DECL.  */
      18  
      19  int nowarn_pfi_v (void)
      20  {
      21    return pfi_v ();
      22  }
      23  
      24  
      25  int warn_fi_v (void)                // { dg-warning "-Winfinite-recursion" }
      26  {
      27    return warn_fi_v ();              // { dg-message "recursive call" }
      28  }
      29  
      30  /* Verify #pragma suppression works.  */
      31  
      32  #pragma GCC diagnostic push
      33  #pragma GCC diagnostic ignored "-Winfinite-recursion"
      34  
      35  int suppress_warn_fi_v (void)
      36  {
      37    return warn_fi_v ();
      38  }
      39  
      40  #pragma GCC diagnostic pop
      41  
      42  
      43  int nowarn_fi_v (void)
      44  {
      45    if (ei++ == 0)
      46      return nowarn_fi_v ();
      47    return 0;
      48  }
      49  
      50  int warn_if_i (int i)               // { dg-warning "-Winfinite-recursion" }
      51  {
      52    if (i > 0)
      53      return warn_if_i (--i);         // { dg-message "recursive call" }
      54    else if (i < 0)
      55      return warn_if_i (-i);          // { dg-message "recursive call" }
      56    else
      57      return warn_if_i (7);           // { dg-message "recursive call" }
      58  }
      59  
      60  
      61  int nowarn_if_i (int i)
      62  {
      63    if (i > 0)
      64      return nowarn_if_i (--i);
      65    else if (i < 0)
      66      return nowarn_if_i (-i);
      67    else
      68      return -1;
      69  }
      70  
      71  int nowarn_switch (int i, int a[])
      72  {
      73    switch (i)
      74      {
      75      case 0: return nowarn_switch (a[3], a + 1);
      76      case 1: return nowarn_switch (a[5], a + 2);
      77      case 2: return nowarn_switch (a[7], a + 3);
      78      case 3: return nowarn_switch (a[9], a + 4);
      79      }
      80    return 77;
      81  }
      82  
      83  int warn_switch (int i, int a[])    // { dg-warning "-Winfinite-recursion" }
      84  {
      85    switch (i)
      86      {
      87      case 0: return warn_switch (a[3], a + 1);
      88      case 1: return warn_switch (a[5], a + 2);
      89      case 2: return warn_switch (a[7], a + 3);
      90      case 3: return warn_switch (a[9], a + 4);
      91      default: return warn_switch (a[1], a + 5);
      92      }
      93  }
      94  
      95  NORETURN void fnoreturn (void);
      96  
      97  /* Verify there's no warning for a function that doesn't return.  */
      98  int nowarn_call_noret (void)
      99  {
     100    fnoreturn ();
     101  }
     102  
     103  int warn_call_noret_r (void)        // { dg-warning "-Winfinite-recursion" }
     104  {
     105    warn_call_noret_r ();             // { dg-message "recursive call" }
     106    fnoreturn ();
     107  }
     108  
     109  /* Verify a warning even though the abort() call would prevent the infinite
     110     recursion.  There's no good way to tell the two cases apart and letting
     111     a simple abort prevent the warning would make it ineffective in cases
     112     where it's the result of assert() expansion and not meant to actually
     113     prevent recursion.  */
     114  
     115  int
     116  warn_noret_call_abort_r (char *s, int n)  // { dg-warning "-Winfinite-recursion" }
     117  {
     118    if (!s)
     119      abort ();
     120  
     121    if (n > 7)
     122      abort ();
     123  
     124    return n + warn_noret_call_abort_r (s, n - 1);  // { dg-message "recursive call" }
     125  }
     126  
     127  /* Verify that a warning is not issued for an apparently infinitely
     128     recursive function like the one above where the recursion would be
     129     prevented by a call to a noreturn function if the recursive function
     130     is itself declared noreturn.  */
     131  
     132  NORETURN void nowarn_noret_call_abort_r (int n)
     133  {
     134    if (n > 7)
     135      abort ();
     136  
     137    nowarn_noret_call_abort_r (n - 1);
     138  }
     139  
     140  int warn_call_abort_r (int n)       // { dg-warning "-Winfinite-recursion" }
     141  {
     142    n += warn_call_abort_r (n - 1);   // { dg-message "recursive call" }
     143    if (n > 7)   // unreachable
     144      abort ();
     145    return n;
     146  }
     147  
     148  
     149  /* And again with exit() for good measure.  */
     150  
     151  int warn_call_exit_r (int n)        // { dg-warning "-Winfinite-recursion" }
     152  {
     153    n += warn_call_exit_r (n - 1);    // { dg-message "recursive call" }
     154    if (n > 7)
     155      exit (0);
     156    return n;
     157  }
     158  
     159  struct __jmp_buf_tag { };
     160  typedef struct __jmp_buf_tag jmp_buf[1];
     161  
     162  extern jmp_buf jmpbuf;
     163  
     164  /* A call to longjmp() breaks infinite recursion.  Verify it suppresses
     165     the warning.  */
     166  
     167  int nowarn_call_longjmp_r (int n)
     168  {
     169    if (n > 7)
     170      __builtin_longjmp (jmpbuf, 1);
     171    return n + nowarn_call_longjmp_r (n - 1);
     172  }
     173  
     174  int warn_call_longjmp_r (int n)     // { dg-warning "-Winfinite-recursion" }
     175  {
     176    n += warn_call_longjmp_r (n - 1); // { dg-message "recursive call" }
     177    if (n > 7)
     178      __builtin_longjmp (jmpbuf, 1);
     179    return n;
     180  }
     181  
     182  
     183  struct __sigjmp_buf_tag { };
     184  typedef struct __sigjmp_buf_tag sigjmp_buf[1];
     185  
     186  extern sigjmp_buf sigjmpbuf;
     187  
     188  /* GCC has no __builtin_siglongjmp().  */
     189  extern void siglongjmp (sigjmp_buf, int);
     190  
     191  /* A call to longjmp() breaks infinite recursion.  Verify it suppresses
     192     the warning.  */
     193  
     194  int nowarn_call_siglongjmp_r (int n)
     195  {
     196    if (n > 7)
     197      siglongjmp (sigjmpbuf, 1);
     198    return n + nowarn_call_siglongjmp_r (n - 1);
     199  }
     200  
     201  
     202  int nowarn_while_do_call_r (int n)
     203  {
     204    int z = 0;
     205    while (n)
     206      z += nowarn_while_do_call_r (n--);
     207    return z;
     208  }
     209  
     210  int warn_do_while_call_r (int n)    // { dg-warning "-Winfinite-recursion" }
     211  {
     212    int z = 0;
     213    do
     214      z += warn_do_while_call_r (n);  // { dg-message "recursive call" }
     215    while (--n);
     216    return z;
     217  }
     218  
     219  /* Verify warnings for a naive replacement of a built-in fucntion.  */
     220  
     221  void* malloc (size_t n)             // { dg-warning "-Winfinite-recursion" }
     222  {
     223    size_t *p =
     224      (size_t*)__builtin_malloc (n + sizeof n);   // { dg-message "recursive call" }
     225    *p = n;
     226    return p + 1;
     227  }