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