]>
Commit | Line | Data |
---|---|---|
a187ac95 | 1 | /* Handle #pragma, system V.4 style. Supports #pragma weak and #pragma pack. |
f09db6e0 | 2 | Copyright (C) 1992, 1997, 1998 Free Software Foundation, Inc. |
a187ac95 RS |
3 | |
4 | This file is part of GNU CC. | |
5 | ||
6 | GNU CC is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 2, or (at your option) | |
9 | any later version. | |
10 | ||
11 | GNU CC is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with GNU CC; see the file COPYING. If not, write to | |
940d9d63 RK |
18 | the Free Software Foundation, 59 Temple Place - Suite 330, |
19 | Boston, MA 02111-1307, USA. */ | |
a187ac95 | 20 | |
4b578ebf | 21 | #include "config.h" |
670ee920 | 22 | #include "system.h" |
d05a5492 | 23 | #include "rtl.h" |
4b578ebf | 24 | #include "tree.h" |
1ef08c63 | 25 | #include "except.h" |
ca695ac9 | 26 | #include "function.h" |
6be160ff | 27 | #include "defaults.h" |
3d6f7931 | 28 | #include "c-pragma.h" |
750caf0d | 29 | #include "flags.h" |
5f6da302 | 30 | #include "toplev.h" |
4b578ebf | 31 | |
e2af664c | 32 | #ifdef HANDLE_GENERIC_PRAGMAS |
a187ac95 | 33 | |
e2af664c | 34 | #ifdef HANDLE_PRAGMA_PACK |
a187ac95 RS |
35 | /* When structure field packing is in effect, this variable is the |
36 | number of bits to use as the maximum alignment. When packing is not | |
0f41302f | 37 | in effect, this is zero. */ |
a187ac95 RS |
38 | |
39 | extern int maximum_field_alignment; | |
e2af664c NC |
40 | #endif |
41 | ||
42 | ||
43 | #ifdef HANDLE_PRAGMA_PACK_PUSH_POP | |
44 | typedef struct align_stack | |
45 | { | |
46 | int alignment; | |
47 | unsigned int num_pushes; | |
48 | struct align_stack * prev; | |
49 | } align_stack; | |
50 | ||
51 | static struct align_stack * alignment_stack = NULL; | |
52 | ||
53 | static int push_alignment PROTO((int)); | |
54 | static int pop_alignment PROTO((void)); | |
55 | ||
56 | /* Push an alignment value onto the stack. */ | |
57 | static int | |
58 | push_alignment (alignment) | |
59 | int alignment; | |
60 | { | |
61 | switch (alignment) | |
62 | { | |
63 | case 0: | |
64 | case 1: | |
65 | case 2: | |
66 | case 4: | |
67 | case 8: | |
68 | case 16: | |
69 | break; | |
70 | default: | |
71 | warning ("\ | |
72 | Alignment must be a small power of two, not %d, in #pragma pack", | |
73 | alignment); | |
74 | return 0; | |
75 | } | |
76 | ||
77 | if (alignment_stack == NULL | |
78 | || alignment_stack->alignment != alignment) | |
79 | { | |
80 | align_stack * entry; | |
81 | ||
82 | entry = (align_stack *) xmalloc (sizeof (* entry)); | |
83 | ||
84 | if (entry == NULL) | |
85 | { | |
86 | warning ("Out of memory pushing #pragma pack"); | |
87 | return 0; | |
88 | } | |
89 | ||
90 | entry->alignment = alignment; | |
91 | entry->num_pushes = 1; | |
92 | entry->prev = alignment_stack; | |
93 | ||
94 | alignment_stack = entry; | |
95 | ||
96 | if (alignment < 8) | |
97 | maximum_field_alignment = alignment * 8; | |
98 | else | |
99 | /* MSVC ignores alignments > 4. */ | |
100 | maximum_field_alignment = 0; | |
101 | } | |
102 | else | |
103 | alignment_stack->num_pushes ++; | |
104 | ||
105 | return 1; | |
106 | } | |
107 | ||
108 | /* Undo a push of an alignment onto the stack. */ | |
109 | static int | |
110 | pop_alignment () | |
111 | { | |
112 | if (alignment_stack == NULL) | |
113 | { | |
114 | warning ("\ | |
115 | #pragma pack(pop) encountered without corresponding #pragma pack(push,<n>)"); | |
116 | return 0; | |
117 | } | |
118 | ||
119 | if (-- alignment_stack->num_pushes == 0) | |
120 | { | |
121 | align_stack * entry; | |
122 | ||
123 | entry = alignment_stack->prev; | |
124 | ||
125 | if (entry == NULL || entry->alignment > 4) | |
126 | maximum_field_alignment = 0; | |
127 | else | |
128 | maximum_field_alignment = entry->alignment * 8; | |
129 | ||
130 | free (alignment_stack); | |
131 | ||
132 | alignment_stack = entry; | |
133 | } | |
134 | ||
135 | return 1; | |
136 | } | |
137 | ||
138 | /* Generate 'packed' and 'aligned' attributes for decls whilst a | |
139 | #pragma pack(push... is in effect. */ | |
140 | void | |
141 | insert_pack_attributes (node, attributes, prefix) | |
142 | tree node; | |
143 | tree * attributes; | |
144 | tree * prefix; | |
145 | { | |
146 | tree a; | |
147 | ||
148 | /* If we are not packing, then there is nothing to do. */ | |
14ab9f52 NC |
149 | if (maximum_field_alignment == 0 |
150 | || alignment_stack == NULL) | |
e2af664c NC |
151 | return; |
152 | ||
153 | /* We are only interested in fields. */ | |
154 | if (TREE_CODE_CLASS (TREE_CODE (node)) != 'd' | |
155 | || TREE_CODE (node) != FIELD_DECL) | |
156 | return; | |
157 | ||
158 | /* Add a 'packed' attribute. */ | |
159 | * attributes = tree_cons (get_identifier ("packed"), NULL, * attributes); | |
160 | ||
161 | /* If the alignment is > 8 then add an alignment attribute as well. */ | |
162 | if (maximum_field_alignment > 8) | |
163 | { | |
164 | /* If the aligned attribute is already present then do not override it. */ | |
165 | for (a = * attributes; a; a = TREE_CHAIN (a)) | |
166 | { | |
167 | tree name = TREE_PURPOSE (a); | |
168 | if (strcmp (IDENTIFIER_POINTER (name), "aligned") == 0) | |
169 | break; | |
170 | } | |
171 | ||
172 | if (a == NULL) | |
173 | for (a = * prefix; a; a = TREE_CHAIN (a)) | |
174 | { | |
175 | tree name = TREE_PURPOSE (a); | |
176 | if (strcmp (IDENTIFIER_POINTER (name), "aligned") == 0) | |
177 | break; | |
178 | } | |
179 | ||
180 | if (a == NULL) | |
181 | { | |
182 | * attributes = tree_cons | |
183 | (get_identifier ("aligned"), | |
184 | tree_cons (NULL, | |
185 | build_int_2 (maximum_field_alignment / 8, 0), | |
186 | NULL), | |
187 | * attributes); | |
188 | } | |
189 | } | |
190 | ||
191 | return; | |
192 | } | |
193 | #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */ | |
194 | \f | |
195 | #ifdef HANDLE_PRAGMA_WEAK | |
196 | static int add_weak PROTO((char *, char *)); | |
197 | ||
198 | static int | |
199 | add_weak (name, value) | |
200 | char * name; | |
201 | char * value; | |
202 | { | |
203 | struct weak_syms * weak; | |
a187ac95 | 204 | |
e2af664c NC |
205 | weak = (struct weak_syms *) permalloc (sizeof (struct weak_syms)); |
206 | ||
207 | if (weak == NULL) | |
208 | return 0; | |
209 | ||
210 | weak->next = weak_decls; | |
211 | weak->name = name; | |
212 | weak->value = value; | |
213 | weak_decls = weak; | |
214 | ||
215 | return 1; | |
216 | } | |
217 | #endif /* HANDLE_PRAGMA_WEAK */ | |
218 | \f | |
219 | /* Handle one token of a pragma directive. TOKEN is the current token, and | |
220 | STRING is its printable form. Some front ends do not support generating | |
221 | tokens, and will only pass in a STRING. Also some front ends will reuse | |
222 | the buffer containing STRING, so it must be copied to a local buffer if | |
223 | it needs to be preserved. | |
224 | ||
225 | If STRING is non-NULL, then the return value will be ignored, and there | |
226 | will be futher calls to handle_pragma_token() in order to handle the rest of | |
227 | the line containing the #pragma directive. If STRING is NULL, the entire | |
228 | line has now been presented to handle_pragma_token() and the return value | |
229 | should be zero if the pragma flawed in some way, or if the pragma was not | |
230 | recognised, and non-zero if it was successfully handled. */ | |
a187ac95 | 231 | |
f09db6e0 | 232 | int |
a187ac95 | 233 | handle_pragma_token (string, token) |
e2af664c | 234 | char * string; |
a187ac95 RS |
235 | tree token; |
236 | { | |
e2af664c NC |
237 | static enum pragma_state state = ps_start; |
238 | static enum pragma_state type; | |
239 | static char * name; | |
240 | static char * value; | |
a187ac95 RS |
241 | static int align; |
242 | ||
e2af664c NC |
243 | /* If we have reached the end of the #pragma directive then |
244 | determine what value we should return. */ | |
245 | ||
f09db6e0 | 246 | if (string == NULL) |
a187ac95 | 247 | { |
e2af664c NC |
248 | int ret_val = 0; |
249 | ||
250 | switch (type) | |
a187ac95 | 251 | { |
e2af664c NC |
252 | default: |
253 | abort (); | |
254 | break; | |
255 | ||
256 | case ps_done: | |
257 | /* The pragma was not recognised. */ | |
258 | break; | |
259 | ||
260 | #ifdef HANDLE_PRAGMA_PACK | |
261 | case ps_pack: | |
a187ac95 | 262 | if (state == ps_right) |
f09db6e0 | 263 | { |
e2af664c NC |
264 | maximum_field_alignment = align * 8; |
265 | ret_val = 1; | |
f09db6e0 | 266 | } |
e2af664c NC |
267 | else |
268 | warning ("malformed `#pragma pack'"); | |
269 | break; | |
270 | #endif /* HANDLE_PRAGMA_PACK */ | |
271 | ||
272 | #ifdef HANDLE_PRAGMA_PACK_PUSH_POP | |
273 | case ps_push: | |
274 | if (state == ps_right) | |
275 | ret_val = push_alignment (align); | |
276 | else | |
277 | warning ("incomplete '#pragma pack(push,<n>)'"); | |
278 | break; | |
279 | ||
280 | case ps_pop: | |
281 | if (state == ps_right) | |
282 | ret_val = pop_alignment (); | |
283 | else | |
284 | warning ("missing closing parenthesis in '#pragma pack(pop)'"); | |
285 | break; | |
286 | #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */ | |
287 | ||
a3100298 | 288 | #ifdef HANDLE_PRAGMA_WEAK |
e2af664c | 289 | case ps_weak: |
a3100298 | 290 | if (HANDLE_PRAGMA_WEAK) |
e2af664c NC |
291 | { |
292 | if (state == ps_name) | |
293 | ret_val = add_weak (name, NULL); | |
294 | else if (state == ps_value) | |
295 | ret_val = add_weak (name, value); | |
296 | else | |
297 | warning ("malformed `#pragma weak'"); | |
298 | } | |
299 | else | |
300 | ret_val = 1; /* Ignore the pragma. */ | |
301 | break; | |
d300e551 | 302 | #endif /* HANDLE_PRAGMA_WEAK */ |
a187ac95 | 303 | } |
a187ac95 RS |
304 | |
305 | type = state = ps_start; | |
f09db6e0 NC |
306 | |
307 | return ret_val; | |
a187ac95 RS |
308 | } |
309 | ||
e2af664c NC |
310 | /* If we have been given a token, but it is not an identifier, |
311 | or a small constant, then something has gone wrong. */ | |
312 | if (token) | |
313 | { | |
314 | switch (TREE_CODE (token)) | |
315 | { | |
316 | case IDENTIFIER_NODE: | |
317 | break; | |
318 | ||
319 | case INTEGER_CST: | |
320 | if (TREE_INT_CST_HIGH (token) != 0) | |
321 | return 0; | |
322 | break; | |
323 | ||
324 | default: | |
325 | return 0; | |
326 | } | |
327 | } | |
328 | ||
a187ac95 RS |
329 | switch (state) |
330 | { | |
331 | case ps_start: | |
e2af664c NC |
332 | type = state = ps_done; |
333 | #ifdef HANDLE_PRAGMA_PACK | |
334 | if (strcmp (string, "pack") == 0) | |
335 | type = state = ps_pack; | |
336 | #endif | |
f09db6e0 | 337 | #ifdef HANDLE_PRAGMA_WEAK |
e2af664c NC |
338 | if (strcmp (string, "weak") == 0) |
339 | type = state = ps_weak; | |
f09db6e0 | 340 | #endif |
a187ac95 | 341 | break; |
f09db6e0 NC |
342 | |
343 | #ifdef HANDLE_PRAGMA_WEAK | |
a187ac95 | 344 | case ps_weak: |
e2af664c NC |
345 | name = permalloc (strlen (string) + 1); |
346 | if (name == NULL) | |
a187ac95 | 347 | { |
e2af664c NC |
348 | warning ("Out of memory parsing #pragma weak"); |
349 | state = ps_bad; | |
a187ac95 RS |
350 | } |
351 | else | |
e2af664c NC |
352 | { |
353 | strcpy (name, string); | |
354 | state = ps_name; | |
355 | } | |
a187ac95 | 356 | break; |
f09db6e0 | 357 | |
a187ac95 RS |
358 | case ps_name: |
359 | state = (strcmp (string, "=") ? ps_bad : ps_equals); | |
360 | break; | |
361 | ||
362 | case ps_equals: | |
e2af664c NC |
363 | value = permalloc (strlen (string) + 1); |
364 | if (value == NULL) | |
a187ac95 | 365 | { |
e2af664c NC |
366 | warning ("Out of memory parsing #pragma weak"); |
367 | state = ps_bad; | |
a187ac95 RS |
368 | } |
369 | else | |
e2af664c NC |
370 | { |
371 | strcpy (value, string); | |
372 | state = ps_value; | |
373 | } | |
a187ac95 RS |
374 | break; |
375 | ||
376 | case ps_value: | |
377 | state = ps_bad; | |
378 | break; | |
e2af664c NC |
379 | #endif /* HANDLE_PRAGMA_WEAK */ |
380 | ||
381 | #ifdef HANDLE_PRAGMA_PACK | |
a187ac95 | 382 | case ps_pack: |
e2af664c | 383 | state = (strcmp (string, "(") ? ps_bad : ps_left); |
a187ac95 RS |
384 | break; |
385 | ||
386 | case ps_left: | |
e2af664c NC |
387 | align = atoi (string); |
388 | switch (align) | |
a187ac95 | 389 | { |
e2af664c NC |
390 | case 1: |
391 | case 2: | |
392 | case 4: | |
393 | state = ps_align; | |
394 | break; | |
395 | ||
396 | case 0: | |
397 | state = (strcmp (string, ")") ? ps_bad : ps_right); | |
398 | #ifdef HANDLE_PRAGMA_PACK_PUSH_POP | |
399 | if (state == ps_bad) | |
400 | { | |
401 | if (strcmp (string, "push") == 0) | |
402 | type = state = ps_push; | |
403 | else if (strcmp (string, "pop") == 0) | |
404 | type = state = ps_pop; | |
405 | } | |
406 | #endif | |
407 | break; | |
408 | ||
409 | default: | |
410 | state = ps_bad; | |
411 | break; | |
a187ac95 | 412 | } |
a187ac95 RS |
413 | break; |
414 | ||
e2af664c NC |
415 | #ifdef HANDLE_PRAGMA_PACK_PUSH_POP |
416 | case ps_pop: | |
417 | #endif | |
a187ac95 | 418 | case ps_align: |
e2af664c | 419 | state = (strcmp (string, ")") ? ps_bad : ps_right); |
a187ac95 RS |
420 | break; |
421 | ||
422 | case ps_right: | |
423 | state = ps_bad; | |
424 | break; | |
e2af664c | 425 | #endif /* HANDLE_PRAGMA_PACK */ |
a187ac95 | 426 | |
e2af664c NC |
427 | #ifdef HANDLE_PRAGMA_PACK_PUSH_POP |
428 | case ps_push: | |
429 | state = (strcmp (string, ",") ? ps_bad : ps_comma); | |
430 | break; | |
431 | ||
432 | case ps_comma: | |
433 | align = atoi (string); | |
434 | state = ps_align; | |
435 | break; | |
436 | #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */ | |
437 | ||
a187ac95 RS |
438 | case ps_bad: |
439 | case ps_done: | |
440 | break; | |
441 | ||
442 | default: | |
443 | abort (); | |
444 | } | |
f09db6e0 NC |
445 | |
446 | return 1; | |
a187ac95 | 447 | } |
e2af664c | 448 | #endif /* HANDLE_GENERIC_PRAGMAS */ |