OSDN Git Service

bfb6bdc6efb829cd2bbc91ec26128c518380b6f1
[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   static char * name;
239   static char * value;
240   static int align;
241   static tree id;
242
243   /* If we have reached the end of the #pragma directive then
244      determine what value we should return.  */
245   
246   if (string == NULL)
247     {
248       int ret_val = 0;
249
250       switch (type)
251         {
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:
262           if (state == ps_right)
263             {
264               maximum_field_alignment = align * 8;
265               ret_val = 1;
266             }
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, id);
276           else
277             warning ("malformed '#pragma pack(push[,id],<n>)'");
278           break;
279           
280         case ps_pop:
281           if (state == ps_right)
282             ret_val = pop_alignment (id);
283           else
284             warning ("malformed '#pragma pack(pop[,id])'");
285           break;
286 #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
287           
288 #ifdef HANDLE_PRAGMA_WEAK
289         case ps_weak:
290           if (HANDLE_PRAGMA_WEAK)
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;
302 #endif /* HANDLE_PRAGMA_WEAK */
303
304         case ps_poison:
305           ret_val = 1;
306           break;
307         }
308
309       type = state = ps_start;
310       id = NULL_TREE;
311       
312       return ret_val;
313     }
314
315   /* If we have been given a token, but it is not an identifier,
316      or a small constant, then something has gone wrong.  */
317   if (token)
318     {
319       switch (TREE_CODE (token))
320         {
321         case IDENTIFIER_NODE:
322           break;
323           
324         case INTEGER_CST:
325           if (TREE_INT_CST_HIGH (token) != 0)
326             return 0;
327           break;
328           
329         default:
330           return 0;
331         }
332     }
333       
334   switch (state)
335     {
336     case ps_start:
337       type = state = ps_done;
338 #ifdef HANDLE_PRAGMA_PACK
339       if (strcmp (string, "pack") == 0)
340         type = state = ps_pack;
341 #endif
342 #ifdef HANDLE_PRAGMA_WEAK
343       if (strcmp (string, "weak") == 0)
344         type = state = ps_weak;
345 #endif
346       if (strcmp (string, "poison") == 0)
347         type = state = ps_poison;
348       break;
349
350 #ifdef HANDLE_PRAGMA_WEAK
351     case ps_weak:
352       name = permalloc (strlen (string) + 1);
353       if (name == NULL)
354         {
355           warning ("Out of memory parsing #pragma weak");
356           state = ps_bad;
357         }
358       else
359         {
360           strcpy (name, string);
361           state = ps_name;
362         }
363       break;
364       
365     case ps_name:
366       state = (strcmp (string, "=") ? ps_bad : ps_equals);
367       break;
368
369     case ps_equals:
370       value = permalloc (strlen (string) + 1);
371       if (value == NULL)
372         {
373           warning ("Out of memory parsing #pragma weak");
374           state = ps_bad;
375         }
376       else
377         {
378           strcpy (value, string);
379           state = ps_value;
380         }
381       break;
382
383     case ps_value:
384       state = ps_bad;
385       break;
386 #endif /* HANDLE_PRAGMA_WEAK */
387       
388 #ifdef HANDLE_PRAGMA_PACK
389     case ps_pack:
390       state = (strcmp (string, "(") ? ps_bad : ps_left);
391       break;
392
393     case ps_left:
394
395       if (token == NULL_TREE)
396         {
397           /* #pragma pack () resets packing rules to their
398              defaults.  */
399           if (strcmp (string, ")") == 0)
400             {
401               align = 0;
402               state = ps_right;
403             }
404           else
405             state = ps_bad;
406         }
407       else if (TREE_CODE (token) == INTEGER_CST)
408         goto handle_align;
409
410 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
411       else if (TREE_CODE (token) == IDENTIFIER_NODE)
412         {
413           if (strcmp (string, "push") == 0)
414             type = state = ps_push;
415           else if (strcmp (string, "pop") == 0)
416             type = state = ps_pop;
417           else
418             state = ps_bad;
419         }
420 #endif
421       else
422         state = ps_bad;
423       break;
424
425     handle_align:
426       align = TREE_INT_CST_LOW (token);
427       switch (align)
428         {
429         case 1:
430         case 2:
431         case 4:
432         case 8:
433         case 16:
434           state = ps_align;
435           break;
436
437         default:
438           state = ps_bad;
439           break;
440         }
441       break;
442
443     case ps_align:
444       state = (strcmp (string, ")") ? ps_bad : ps_right);
445       break;
446
447     case ps_right:
448       state = ps_bad;
449       break;
450 #endif /* HANDLE_PRAGMA_PACK */
451
452 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
453     case ps_push:
454       state = (strcmp (string, ",") ? ps_bad : ps_pushcomma);
455       break;
456
457     case ps_pushid:
458       state = (strcmp (string, ",") ? ps_bad : ps_pushcomma2);
459       break;
460
461     case ps_pushcomma:
462       if (token && TREE_CODE (token) == IDENTIFIER_NODE)
463         {
464           id = token;
465           state = ps_pushid;
466           break;
467         }
468
469       /* else fall through */
470     case ps_pushcomma2:
471       if (token && TREE_CODE (token) == INTEGER_CST)
472         goto handle_align;
473       else
474         state = ps_bad;
475       break;
476
477     case ps_pop:
478       if (strcmp (string, ",") == 0)
479         state = ps_popcomma;
480       else
481         state = (strcmp (string, ")") ? ps_bad : ps_right);
482       break;
483
484     case ps_popcomma:
485       if (token && TREE_CODE (token) == IDENTIFIER_NODE)
486         {
487           id = token;
488           state = ps_align;
489         }
490       else
491         state = ps_bad;
492       break;
493 #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
494
495     case ps_poison:
496       if (token && TREE_CODE (token) != IDENTIFIER_NODE)
497         state = ps_bad;
498       break;
499
500     case ps_bad:
501     case ps_done:
502       break;
503
504     default:
505       abort ();
506     }
507
508   return 1;
509 }
510 #endif /* HANDLE_GENERIC_PRAGMAS */