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