OSDN Git Service

ba0c83673908d3fcd4792067bbc4031deaa31a60
[pf3gnuchains/gcc-fork.git] / gcc / c-pragma.c
1 /* Handle #pragma, system V.4 style.  Supports #pragma weak and #pragma pack.
2    Copyright (C) 1992, 1997, 1998, 1999 Free Software Foundation, Inc.
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
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  */
20
21 #include "config.h"
22 #include "system.h"
23 #include "rtl.h"
24 #include "tree.h"
25 #include "function.h"
26 #include "defaults.h"
27 #include "c-pragma.h"
28 #include "flags.h"
29 #include "toplev.h"
30
31 #ifdef HANDLE_GENERIC_PRAGMAS
32
33 #ifdef HANDLE_PRAGMA_PACK
34 /* When structure field packing is in effect, this variable is the
35    number of bits to use as the maximum alignment.  When packing is not
36    in effect, this is zero.  */
37
38 extern int maximum_field_alignment;
39 #endif
40
41
42 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
43 typedef struct align_stack
44 {
45   int                  alignment;
46   unsigned int         num_pushes;
47   tree                 id;
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, tree));
54 static int  pop_alignment  PROTO((tree));
55
56 /* Push an alignment value onto the stack.  */
57 static int
58 push_alignment (alignment, id)
59      int alignment;
60      tree id;
61 {
62   switch (alignment)
63     {
64     case 0:
65     case 1:
66     case 2:
67     case 4:
68     case 8:
69     case 16:
70       break;
71     default:
72       warning ("\
73 Alignment must be a small power of two, not %d, in #pragma pack",
74                alignment);
75       return 0;
76     }
77   
78   if (alignment_stack == NULL
79       || alignment_stack->alignment != alignment
80       || id != NULL_TREE)
81     {
82       align_stack * entry;
83
84       entry = (align_stack *) xmalloc (sizeof (* entry));
85
86       if (entry == NULL)
87         {
88           warning ("Out of memory pushing #pragma pack");
89           return 0;
90         }
91
92       entry->alignment  = alignment;
93       entry->num_pushes = 1;
94       entry->id         = id;
95       entry->prev       = alignment_stack;
96       
97       alignment_stack = entry;
98
99       maximum_field_alignment = alignment * 8;
100     }
101   else
102     alignment_stack->num_pushes ++;
103
104   return 1;
105 }
106
107 /* Undo a push of an alignment onto the stack.  */
108 static int
109 pop_alignment (id)
110      tree id;
111 {
112   align_stack * entry;
113       
114   if (alignment_stack == NULL)
115     {
116       warning ("\
117 #pragma pack (pop) encountered without matching #pragma pack (push, <n>)"
118                );
119       return 0;
120     }
121
122   /* If we got an identifier, strip away everything above the target
123      entry so that the next step will restore the state just below it.  */
124   if (id)
125     {
126       for (entry = alignment_stack; entry; entry = entry->prev)
127         if (entry->id == id)
128           {
129             entry->num_pushes = 1;
130             alignment_stack = entry;
131             break;
132           }
133       if (entry == NULL)
134         warning ("\
135 #pragma pack(pop, %s) encountered without matching #pragma pack(push, %s, <n>)"
136                  , IDENTIFIER_POINTER (id), IDENTIFIER_POINTER (id));
137     }
138
139   if (-- alignment_stack->num_pushes == 0)
140     {
141       entry = alignment_stack->prev;
142
143       if (entry == NULL)
144         maximum_field_alignment = 0;
145       else
146         maximum_field_alignment = entry->alignment * 8;
147
148       free (alignment_stack);
149
150       alignment_stack = entry;
151     }
152
153   return 1;
154 }
155
156 /* Generate 'packed' and 'aligned' attributes for decls whilst a
157    #pragma pack(push... is in effect.  */
158 void
159 insert_pack_attributes (node, attributes, prefix)
160      tree node;
161      tree * attributes;
162      tree * prefix;
163 {
164   tree a;
165   int field_alignment;
166
167   /* If we are not packing, then there is nothing to do.  */
168   if (maximum_field_alignment == 0
169       || alignment_stack == NULL)
170     return;
171
172   /* We are only interested in fields.  */
173   if (TREE_CODE_CLASS (TREE_CODE (node)) != 'd'
174       || TREE_CODE (node) != FIELD_DECL)
175     return;
176   
177   field_alignment = TYPE_ALIGN (TREE_TYPE (node));
178   if (field_alignment <= 0 || field_alignment > maximum_field_alignment)
179     field_alignment = maximum_field_alignment;
180
181   /* Add a 'packed' attribute.  */
182   * attributes = tree_cons (get_identifier ("packed"), NULL, * attributes);
183   
184   /* If the alignment is > 8 then add an alignment attribute as well.  */
185   if (field_alignment > 8)
186     {
187       /* If the aligned attribute is already present then do not override it.  */
188       for (a = * attributes; a; a = TREE_CHAIN (a))
189         {
190           tree name = TREE_PURPOSE (a);
191           if (strcmp (IDENTIFIER_POINTER (name), "aligned") == 0)
192             break;
193         }
194       
195       if (a == NULL)
196         for (a = * prefix; a; a = TREE_CHAIN (a))
197           {
198             tree name = TREE_PURPOSE (a);
199             if (strcmp (IDENTIFIER_POINTER (name), "aligned") == 0)
200               break;
201           }
202   
203       if (a == NULL)
204         {
205           * attributes = tree_cons
206               (get_identifier ("aligned"),
207                tree_cons (NULL,
208                           build_int_2 (field_alignment / 8, 0),
209                           NULL),
210                * attributes);
211         }
212     }
213
214   return;
215 }
216 #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
217 \f
218 /* Handle one token of a pragma directive.  TOKEN is the current token, and
219    STRING is its printable form.  Some front ends do not support generating
220    tokens, and will only pass in a STRING.  Also some front ends will reuse
221    the buffer containing STRING, so it must be copied to a local buffer if
222    it needs to be preserved.
223
224    If STRING is non-NULL, then the return value will be ignored, and there
225    will be futher calls to handle_pragma_token() in order to handle the rest of
226    the line containing the #pragma directive.  If STRING is NULL, the entire
227    line has now been presented to handle_pragma_token() and the return value
228    should be zero if the pragma flawed in some way, or if the pragma was not
229    recognised, and non-zero if it was successfully handled.  */
230
231 int
232 handle_pragma_token (string, token)
233      const char * string;
234      tree token;
235 {
236   static enum pragma_state state = ps_start;
237   static enum pragma_state type;
238 #ifdef HANDLE_PRAGMA_WEAK
239   static char * name;
240   static char * value;
241 #endif
242 #if defined(HANDLE_PRAGMA_PACK) || defined(HANDLE_PRAGMA_PACK_PUSH_POP)
243   static int align;
244 #endif
245   static tree id;
246
247   /* If we have reached the end of the #pragma directive then
248      determine what value we should return.  */
249   
250   if (string == NULL)
251     {
252       int ret_val = 0;
253
254       switch (type)
255         {
256         default:
257           abort ();
258           break;
259
260         case ps_done:
261           /* The pragma was not recognised.  */
262           break;
263           
264 #ifdef HANDLE_PRAGMA_PACK         
265         case ps_pack:
266           if (state == ps_right)
267             {
268               maximum_field_alignment = align * 8;
269               ret_val = 1;
270             }
271           else
272             warning ("malformed `#pragma pack'");
273           break;
274 #endif /* HANDLE_PRAGMA_PACK */
275           
276 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
277         case ps_push:
278           if (state == ps_right)
279             ret_val = push_alignment (align, id);
280           else
281             warning ("malformed '#pragma pack(push[,id],<n>)'");
282           break;
283           
284         case ps_pop:
285           if (state == ps_right)
286             ret_val = pop_alignment (id);
287           else
288             warning ("malformed '#pragma pack(pop[,id])'");
289           break;
290 #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
291           
292 #ifdef HANDLE_PRAGMA_WEAK
293         case ps_weak:
294           if (HANDLE_PRAGMA_WEAK)
295             {
296               if (state == ps_name)
297                 ret_val = add_weak (name, NULL);
298               else if (state == ps_value)
299                 ret_val = add_weak (name, value);
300               else
301                 warning ("malformed `#pragma weak'");
302             }
303           else
304             ret_val = 1; /* Ignore the pragma.  */
305           break;
306 #endif /* HANDLE_PRAGMA_WEAK */
307
308         case ps_poison:
309           ret_val = 1;
310           break;
311         }
312
313       type = state = ps_start;
314       id = NULL_TREE;
315       
316       return ret_val;
317     }
318
319   /* If we have been given a token, but it is not an identifier,
320      or a small constant, then something has gone wrong.  */
321   if (token)
322     {
323       switch (TREE_CODE (token))
324         {
325         case IDENTIFIER_NODE:
326           break;
327           
328         case INTEGER_CST:
329           if (TREE_INT_CST_HIGH (token) != 0)
330             return 0;
331           break;
332           
333         default:
334           return 0;
335         }
336     }
337       
338   switch (state)
339     {
340     case ps_start:
341       type = state = ps_done;
342 #ifdef HANDLE_PRAGMA_PACK
343       if (strcmp (string, "pack") == 0)
344         type = state = ps_pack;
345 #endif
346 #ifdef HANDLE_PRAGMA_WEAK
347       if (strcmp (string, "weak") == 0)
348         type = state = ps_weak;
349 #endif
350       if (strcmp (string, "poison") == 0)
351         type = state = ps_poison;
352       break;
353
354 #ifdef HANDLE_PRAGMA_WEAK
355     case ps_weak:
356       name = permalloc (strlen (string) + 1);
357       if (name == NULL)
358         {
359           warning ("Out of memory parsing #pragma weak");
360           state = ps_bad;
361         }
362       else
363         {
364           strcpy (name, string);
365           state = ps_name;
366         }
367       break;
368       
369     case ps_name:
370       state = (strcmp (string, "=") ? ps_bad : ps_equals);
371       break;
372
373     case ps_equals:
374       value = permalloc (strlen (string) + 1);
375       if (value == NULL)
376         {
377           warning ("Out of memory parsing #pragma weak");
378           state = ps_bad;
379         }
380       else
381         {
382           strcpy (value, string);
383           state = ps_value;
384         }
385       break;
386
387     case ps_value:
388       state = ps_bad;
389       break;
390 #endif /* HANDLE_PRAGMA_WEAK */
391       
392 #ifdef HANDLE_PRAGMA_PACK
393     case ps_pack:
394       state = (strcmp (string, "(") ? ps_bad : ps_left);
395       break;
396
397     case ps_left:
398
399       if (token == NULL_TREE)
400         {
401           /* #pragma pack () resets packing rules to their
402              defaults.  */
403           if (strcmp (string, ")") == 0)
404             {
405               align = 0;
406               state = ps_right;
407             }
408           else
409             state = ps_bad;
410         }
411       else if (TREE_CODE (token) == INTEGER_CST)
412         goto handle_align;
413
414 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
415       else if (TREE_CODE (token) == IDENTIFIER_NODE)
416         {
417           if (strcmp (string, "push") == 0)
418             type = state = ps_push;
419           else if (strcmp (string, "pop") == 0)
420             type = state = ps_pop;
421           else
422             state = ps_bad;
423         }
424 #endif
425       else
426         state = ps_bad;
427       break;
428
429     handle_align:
430       align = TREE_INT_CST_LOW (token);
431       switch (align)
432         {
433         case 1:
434         case 2:
435         case 4:
436         case 8:
437         case 16:
438           state = ps_align;
439           break;
440
441         default:
442           state = ps_bad;
443           break;
444         }
445       break;
446
447     case ps_align:
448       state = (strcmp (string, ")") ? ps_bad : ps_right);
449       break;
450
451     case ps_right:
452       state = ps_bad;
453       break;
454 #endif /* HANDLE_PRAGMA_PACK */
455
456 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
457     case ps_push:
458       state = (strcmp (string, ",") ? ps_bad : ps_pushcomma);
459       break;
460
461     case ps_pushid:
462       state = (strcmp (string, ",") ? ps_bad : ps_pushcomma2);
463       break;
464
465     case ps_pushcomma:
466       if (token && TREE_CODE (token) == IDENTIFIER_NODE)
467         {
468           id = token;
469           state = ps_pushid;
470           break;
471         }
472
473       /* else fall through */
474     case ps_pushcomma2:
475       if (token && TREE_CODE (token) == INTEGER_CST)
476         goto handle_align;
477       else
478         state = ps_bad;
479       break;
480
481     case ps_pop:
482       if (strcmp (string, ",") == 0)
483         state = ps_popcomma;
484       else
485         state = (strcmp (string, ")") ? ps_bad : ps_right);
486       break;
487
488     case ps_popcomma:
489       if (token && TREE_CODE (token) == IDENTIFIER_NODE)
490         {
491           id = token;
492           state = ps_align;
493         }
494       else
495         state = ps_bad;
496       break;
497 #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
498
499     case ps_poison:
500       if (token && TREE_CODE (token) != IDENTIFIER_NODE)
501         state = ps_bad;
502       break;
503
504     case ps_bad:
505     case ps_done:
506       break;
507
508     default:
509       abort ();
510     }
511
512   return 1;
513 }
514 #endif /* HANDLE_GENERIC_PRAGMAS */
515 \f
516 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
517 static void
518 mark_align_stack (p)
519     void *p;
520 {
521   align_stack *a = (align_stack *) p;
522
523   while (a)
524     {
525       ggc_mark_tree (a->id);
526       a = a->prev;
527     }
528 }
529 #endif
530
531 void
532 init_pragma ()
533 {
534 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
535   ggc_add_root (&alignment_stack, 1, sizeof(alignment_stack),
536                 mark_align_stack);
537 #endif
538 }