(root)/
gcc-13.2.0/
gcc/
testsuite/
gcc.dg/
builtin-dynamic-object-size-19.c
       1  /* PR tree-optimization/88372 - alloc_size attribute is ignored
       2     on function pointers { dg-do compile }
       3     { dg-options "-O2 -fdump-tree-optimized" } */
       4  
       5  #define __builtin_object_size __builtin_dynamic_object_size
       6  #include "builtin-object-size-18.c"
       7  
       8  typedef __SIZE_TYPE__ size_t;
       9  
      10  #define ATTR(...) __attribute__ ((__VA_ARGS__))
      11  #define CONCAT(x, y) x ## y
      12  #define CAT(x, y) CONCAT (x, y)
      13  #define FAILNAME(name) CAT (call_ ## name ##_on_line_, __LINE__)
      14  
      15  #define FAIL(name) do {				\
      16      extern void FAILNAME (name) (void);		\
      17      FAILNAME (name)();				\
      18    } while (0)
      19  
      20  /* Macro to emit a call to function named
      21     call_in_true_branch_not_eliminated_on_line_NNN()
      22     for each call that's expected to be eliminated.  The dg-final
      23     scan-tree-dump-time directive at the bottom of the test verifies
      24     that no such call appears in output.  */
      25  #define ELIM(expr)							\
      26    if (!(expr)) FAIL (in_true_branch_not_eliminated); else (void)0
      27  
      28  void sink (void*);
      29  
      30  #define T(alloc, n) do {			\
      31      void *p = alloc;				\
      32      sink (p);					\
      33      ELIM (n == __builtin_object_size (p, 0));	\
      34      ELIM (n == __builtin_object_size (p, 1));	\
      35      ELIM (n == __builtin_object_size (p, 2));	\
      36      ELIM (n == __builtin_object_size (p, 3));	\
      37    } while (0)
      38  
      39  
      40  ATTR (alloc_size (1)) void* (*alloc_1_x)(size_t, size_t);
      41  ATTR (alloc_size (2)) void* (*alloc_x_2)(size_t, size_t);
      42  
      43  /* Verify that things work when attribute alloc_size is applied
      44     to a typedef that is then used to declared a pointer.  */
      45  typedef ATTR (alloc_size (1, 2)) void* (alloc_1_2_t)(size_t, size_t);
      46  
      47  void test_alloc_ptr (alloc_1_2_t *alloc_1_2)
      48  {
      49    T (alloc_1_x (0, 0), 0);
      50    T (alloc_1_x (1, 0), 1);
      51    T (alloc_1_x (3, 0), 3);
      52    T (alloc_1_x (9, 5), 9);
      53  
      54    T (alloc_x_2 (0, 0), 0);
      55    T (alloc_x_2 (1, 0), 0);
      56    T (alloc_x_2 (0, 1), 1);
      57    T (alloc_x_2 (9, 5), 5);
      58  
      59    T (alloc_1_2 (0, 0), 0);
      60    T (alloc_1_2 (1, 0), 0);
      61    T (alloc_1_2 (0, 1), 0);
      62    T (alloc_1_2 (9, 5), 45);
      63  }
      64  
      65  /* Verify that object size is detected even in indirect calls via
      66     function pointers to built-in allocation functions, even without
      67     explicit use of attribute alloc_size on the pointers.  */
      68  
      69  typedef void *(allocfn_1) (size_t);
      70  typedef void *(allocfn_1_2) (size_t, size_t);
      71  
      72  static inline void *
      73  call_alloc (allocfn_1 *fn1, allocfn_1_2 *fn2, size_t n1, size_t n2)
      74  {
      75    return fn1 ? fn1 (n1) : fn2 (n1, n2);
      76  }
      77  
      78  static inline void *
      79  call_malloc (size_t n)
      80  {
      81    return call_alloc (__builtin_malloc, 0, n, 0);
      82  }
      83  
      84  static inline void *
      85  call_calloc (size_t n1, size_t n2)
      86  {
      87    return call_alloc (0, __builtin_calloc, n1, n2);
      88  }
      89  
      90  void test_builtin_ptr (void)
      91  {
      92    T (call_malloc (0), 0);
      93    T (call_malloc (1), 1);
      94    T (call_malloc (9), 9);
      95  
      96    T (call_calloc (0, 0), 0);
      97    T (call_calloc (0, 1), 0);
      98    T (call_calloc (1, 0), 0);
      99    T (call_calloc (1, 1), 1);
     100    T (call_calloc (1, 3), 3);
     101    T (call_calloc (2, 3), 6);
     102  }
     103  
     104  /* { dg-final { scan-tree-dump-not "not_eliminated" "optimized" } } */