OSDN Git Service

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