1 /* PR66516 - missing diagnostic on taking the address of a builtin function
2 { dg-do compile } */
3
4 typedef void (F)(void);
5 typedef __UINTPTR_TYPE__ uintptr_t;
6
7 /* Utility function to test passing built-in functions as an ordinary
8 argument and via the ellipsis. */
9 static void func_arg (F *p, ...) { (void)p; }
10
11 static F* test_taking_address_of_gcc_builtin (void)
12 {
13 F *p;
14 void *q;
15 uintptr_t a;
16
17 /* Call, cast to void, and id are allowed. */
18 __builtin_trap ();
19 (void)__builtin_trap;
20 __builtin_trap;
21
22 {
23 typedef __typeof__ (__builtin_trap) F; /* Okay. */
24 }
25
26 /* Address and indirection operators. */
27 p = &__builtin_trap; /* { dg-error "built-in function" } */
28 p = *__builtin_trap; /* { dg-error "built-in function" } */
29
30 /* Unary NOT. */
31 a = !__builtin_trap; /* { dg-error "built-in function" } */
32
33 /* Sizeof and _Alignof are disallowed by C but allowed by GCC
34 and there's no reason to reject built-ins as operands since
35 doing so doesn't yield their address. */
36 #pragma GCC diagnostic push
37 /* Disable: invalid application of 'sizeof' to a function type. */
38 #pragma GCC diagnostic ignored "-Wpointer-arith"
39 a = sizeof __builtin_trap;
40 #pragma GCC diagnostic pop
41
42 #ifndef __STDC_VERSION__
43 # pragma GCC diagnostic push
44 /* Disable: ISO C90 does not support '_Alignof'. */
45 # pragma GCC diagnostic ignored "-Wpedantic"
46 #endif
47
48 a = _Alignof __builtin_trap;
49
50 #ifndef __STDC_VERSION__
51 # pragma GCC diagnostic pop
52 #endif
53
54 /* Casts. */
55 p = (F*)__builtin_trap; /* { dg-error "built-in function" } */
56 a = (uintptr_t)__builtin_trap; /* { dg-error "built-in function" } */
57
58 /* Additive operator. */
59 p = __builtin_trap + 0; /* { dg-error "built-in function" } */
60 p = __builtin_trap - 0; /* { dg-error "built-in function" } */
61 a = __builtin_trap - p; /* { dg-error "built-in function" } */
62 a = p - __builtin_trap; /* { dg-error "built-in function" } */
63
64 /* Relational operators. */
65 a = __builtin_trap < p; /* { dg-error "built-in function" } */
66 a = p < __builtin_trap; /* { dg-error "built-in function" } */
67
68 a = __builtin_trap <= p; /* { dg-error "built-in function" } */
69 a = p <= __builtin_trap; /* { dg-error "built-in function" } */
70
71 a = __builtin_trap > p; /* { dg-error "built-in function" } */
72 a = p > __builtin_trap; /* { dg-error "built-in function" } */
73
74 a = __builtin_trap > p; /* { dg-error "built-in function" } */
75 a = p > __builtin_trap; /* { dg-error "built-in function" } */
76
77 a = __builtin_trap <= p; /* { dg-error "built-in function" } */
78 a = p <= __builtin_trap; /* { dg-error "built-in function" } */
79
80 a = __builtin_trap <= p; /* { dg-error "built-in function" } */
81 a = p <= __builtin_trap; /* { dg-error "built-in function" } */
82
83 /* Equality operators. */
84 a = __builtin_trap == p; /* { dg-error "built-in function" } */
85 a = p == __builtin_trap; /* { dg-error "built-in function" } */
86 a = __builtin_trap != p; /* { dg-error "built-in function" } */
87 a = p != __builtin_trap; /* { dg-error "built-in function" } */
88
89 /* Logical AND and OR. */
90 a = __builtin_trap && p; /* { dg-error "built-in function" } */
91 a = p && __builtin_trap; /* { dg-error "built-in function" } */
92
93 a = __builtin_trap || p; /* { dg-error "built-in function" } */
94 a = p || __builtin_trap; /* { dg-error "built-in function" } */
95
96 /* Conditional operator. */
97 a = __builtin_trap ? 1 : 0; /* { dg-error "built-in function" } */
98 p = a ? __builtin_trap : 0; /* { dg-error "built-in function" } */
99 p = a ? 0 : __builtin_trap; /* { dg-error "built-in function" } */
100
101 /* Assignment operator. */
102 p = __builtin_trap; /* { dg-error "built-in function" } */
103
104 q = __builtin_trap; /* { dg-error "built-in function" } */
105 a = __builtin_trap; /* { dg-error "built-in function" } */
106
107 /* Passing as an argument. */
108 func_arg (__builtin_trap); /* { dg-error "built-in function" } */
109
110 /* Passing through the ellipsis. */
111 func_arg (0, __builtin_trap); /* { dg-error "built-in function" } */
112
113 /* Return statement. */
114 return __builtin_trap; /* { dg-error "built-in function" } */
115
116 (void)a;
117 (void)p;
118 (void)q;
119 }
120
121 /* Helper declarations to verify that it's possible to take the address
122 of a user-declared function that's also a GCC built-in. */
123 extern int abs (int);
124
125 extern __SIZE_TYPE__ strlen (const char*);
126
127 /* Taking the address of a builtin with a library "fallback" must be
128 allowed, either using the __builtin_xxx form or the xxx form, when
129 the library fallback is declared either explicitly or implicitly
130 by virtue of first calling the function. */
131 void test_taking_address_of_library_builtin (int i)
132 {
133 {
134 typedef int F (int);
135
136 /* Compute the address of libc's abs using the implicitly declared
137 __builtin_abs form (all expressions are valid). */
138 F *p = __builtin_abs;
139 p = &__builtin_abs;
140 p = *__builtin_abs;
141
142 /* Compute the address of libc's abs declared above. */
143 p = abs;
144 p = &abs;
145 p = *abs;
146 (void)p;
147 }
148
149 {
150 typedef __SIZE_TYPE__ size_t;
151 typedef size_t F (const char*);
152
153 /* Compute the address of libc's strlen using the implicitly
154 declared __builtin_strlen form. */
155 F *p = __builtin_strlen;
156 p = &__builtin_strlen;
157 p = *__builtin_strlen;
158
159 /* Compute the address of libc's strlen declared above. */
160 p = strlen;
161 p = &strlen;
162 p = *strlen;
163 (void)p;
164 }
165
166 {
167 typedef int F (int);
168
169 /* Compute the address of libc's isxxx functions using the implicitly
170 declared __builtin_xxx form. */
171 F *p = __builtin_isalnum;
172 p = &__builtin_isalpha;
173 p = *__builtin_iscntrl;
174
175 /* According to C90 (see also the discussion in c/67386):
176 If the expression that precedes the parenthesized argument list
177 in a function call consists solely of an identifier, and if no
178 declaration is visible for this identifier, the identifier is
179 implicitly declared exactly as if, in the innermost block
180 containing the function call, the declaration
181 extern int identifier();
182 appeared. */
183
184 /* Call the functions first to have their declarations "injected"
185 into the enclosing block. Suppress warnings. */
186 #pragma GCC diagnostic push
187 #pragma GCC diagnostic ignored "-Wimplicit-function-declaration"
188 i = isalnum (i) || isalpha (i) || iscntrl (i);
189 #pragma GCC diagnostic pop
190
191 /* Take the address of the functions relying on their declarations
192 having been implicitly provided by the calls above. */
193 p = isalnum;
194 p = &isalpha;
195 p = *iscntrl;
196 (void)p;
197 }
198 }