OSDN Git Service

2adfcc70af81fe483f8a366730db8da9d38bc17d
[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, 97-99, 2000 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 /* If we have a "global" #pragma pack(<n>) if effect when the first
55    #pragma push(pack,<n>) is encountered, this stores the the value of 
56    maximum_field_alignment in effect.  When the final pop_alignment() 
57    happens, we restore the value to this, not to a value of 0 for
58    maximum_field_alignment.  Value is in bits. */
59 static int  default_alignment;
60
61 static int  push_alignment PARAMS ((int, tree));
62 static int  pop_alignment  PARAMS ((tree));
63
64 /* Push an alignment value onto the stack.  */
65 static int
66 push_alignment (alignment, id)
67      int alignment;
68      tree id;
69 {
70   switch (alignment)
71     {
72     case 0:
73     case 1:
74     case 2:
75     case 4:
76     case 8:
77     case 16:
78       break;
79     default:
80       warning ("\
81 Alignment must be a small power of two, not %d, in #pragma pack",
82                alignment);
83       return 0;
84     }
85   
86   if (alignment_stack == NULL
87       || alignment_stack->alignment != alignment
88       || id != NULL_TREE)
89     {
90       align_stack * entry;
91
92       entry = (align_stack *) xmalloc (sizeof (* entry));
93
94       entry->alignment  = alignment;
95       entry->num_pushes = 1;
96       entry->id         = id;
97       entry->prev       = alignment_stack;
98       
99       /* The current value of maximum_field_alignment is not necessarily 
100          0 since there may be a #pragma pack(<n>) in effect; remember it 
101          so that we can restore it after the final #pragma pop(). */
102       if (alignment_stack == NULL)
103         default_alignment = maximum_field_alignment;
104       
105       alignment_stack = entry;
106
107       maximum_field_alignment = alignment * 8;
108     }
109   else
110     alignment_stack->num_pushes ++;
111
112   return 1;
113 }
114
115 /* Undo a push of an alignment onto the stack.  */
116 static int
117 pop_alignment (id)
118      tree id;
119 {
120   align_stack * entry;
121       
122   if (alignment_stack == NULL)
123     {
124       warning ("\
125 #pragma pack (pop) encountered without matching #pragma pack (push, <n>)"
126                );
127       return 0;
128     }
129
130   /* If we got an identifier, strip away everything above the target
131      entry so that the next step will restore the state just below it.  */
132   if (id)
133     {
134       for (entry = alignment_stack; entry; entry = entry->prev)
135         if (entry->id == id)
136           {
137             entry->num_pushes = 1;
138             alignment_stack = entry;
139             break;
140           }
141       if (entry == NULL)
142         warning ("\
143 #pragma pack(pop, %s) encountered without matching #pragma pack(push, %s, <n>)"
144                  , IDENTIFIER_POINTER (id), IDENTIFIER_POINTER (id));
145     }
146
147   if (-- alignment_stack->num_pushes == 0)
148     {
149       entry = alignment_stack->prev;
150
151       if (entry == NULL)
152         maximum_field_alignment = default_alignment;
153       else
154         maximum_field_alignment = entry->alignment * 8;
155
156       free (alignment_stack);
157
158       alignment_stack = entry;
159     }
160
161   return 1;
162 }
163 #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
164 \f
165 /* Handle one token of a pragma directive.  TOKEN is the current token, and
166    STRING is its printable form.  Some front ends do not support generating
167    tokens, and will only pass in a STRING.  Also some front ends will reuse
168    the buffer containing STRING, so it must be copied to a local buffer if
169    it needs to be preserved.
170
171    If STRING is non-NULL, then the return value will be ignored, and there
172    will be futher calls to handle_pragma_token() in order to handle the rest of
173    the line containing the #pragma directive.  If STRING is NULL, the entire
174    line has now been presented to handle_pragma_token() and the return value
175    should be zero if the pragma flawed in some way, or if the pragma was not
176    recognised, and non-zero if it was successfully handled.  */
177
178 int
179 handle_pragma_token (string, token)
180      const char * string;
181      tree token;
182 {
183   static enum pragma_state state = ps_start;
184   static enum pragma_state type;
185 #ifdef HANDLE_PRAGMA_WEAK
186   static char * name;
187   static char * value;
188 #endif
189 #if defined(HANDLE_PRAGMA_PACK) || defined(HANDLE_PRAGMA_PACK_PUSH_POP)
190   static int align;
191 #endif
192   static tree id;
193
194   /* If we have reached the end of the #pragma directive then
195      determine what value we should return.  */
196   
197   if (string == NULL)
198     {
199       int ret_val = 0;
200
201       switch (type)
202         {
203         default:
204           abort ();
205           break;
206
207         case ps_done:
208           /* The pragma was not recognised.  */
209           break;
210           
211 #ifdef HANDLE_PRAGMA_PACK         
212         case ps_pack:
213           if (state == ps_right)
214             {
215               maximum_field_alignment = align * 8;
216 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
217               default_alignment = maximum_field_alignment;
218 #endif
219               ret_val = 1;
220             }
221           else
222             warning ("malformed `#pragma pack'");
223           break;
224 #endif /* HANDLE_PRAGMA_PACK */
225           
226 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
227         case ps_push:
228           if (state == ps_right)
229             ret_val = push_alignment (align, id);
230           else
231             warning ("malformed '#pragma pack(push[,id],<n>)'");
232           break;
233           
234         case ps_pop:
235           if (state == ps_right)
236             ret_val = pop_alignment (id);
237           else
238             warning ("malformed '#pragma pack(pop[,id])'");
239           break;
240 #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
241           
242 #ifdef HANDLE_PRAGMA_WEAK
243         case ps_weak:
244           if (HANDLE_PRAGMA_WEAK)
245             {
246               if (state == ps_name)
247                 ret_val = add_weak (name, NULL);
248               else if (state == ps_value)
249                 ret_val = add_weak (name, value);
250               else
251                 warning ("malformed `#pragma weak'");
252             }
253           else
254             ret_val = 1; /* Ignore the pragma.  */
255           break;
256 #endif /* HANDLE_PRAGMA_WEAK */
257
258         case ps_poison:
259           ret_val = 1;
260           break;
261         }
262
263       type = state = ps_start;
264       id = NULL_TREE;
265       
266       return ret_val;
267     }
268
269   /* If we have been given a token, but it is not an identifier,
270      or a small constant, then something has gone wrong.  */
271   if (token)
272     {
273       switch (TREE_CODE (token))
274         {
275         case IDENTIFIER_NODE:
276           break;
277           
278         case INTEGER_CST:
279           if (TREE_INT_CST_HIGH (token) != 0)
280             return 0;
281           break;
282           
283         default:
284           return 0;
285         }
286     }
287       
288   switch (state)
289     {
290     case ps_start:
291       type = state = ps_done;
292 #ifdef HANDLE_PRAGMA_PACK
293       if (strcmp (string, "pack") == 0)
294         type = state = ps_pack;
295 #endif
296 #ifdef HANDLE_PRAGMA_WEAK
297       if (strcmp (string, "weak") == 0)
298         type = state = ps_weak;
299 #endif
300       if (strcmp (string, "poison") == 0)
301         type = state = ps_poison;
302       break;
303
304 #ifdef HANDLE_PRAGMA_WEAK
305     case ps_weak:
306       name = xstrdup (string);
307       state = ps_name;
308       break;
309       
310     case ps_name:
311       state = (strcmp (string, "=") ? ps_bad : ps_equals);
312       break;
313
314     case ps_equals:
315       value = xstrdup (string);
316       state = ps_value;
317       break;
318
319     case ps_value:
320       state = ps_bad;
321       break;
322 #endif /* HANDLE_PRAGMA_WEAK */
323       
324 #ifdef HANDLE_PRAGMA_PACK
325     case ps_pack:
326       state = (strcmp (string, "(") ? ps_bad : ps_left);
327       break;
328
329     case ps_left:
330
331       if (token == NULL_TREE)
332         {
333           /* #pragma pack () resets packing rules to their
334              defaults.  */
335           if (strcmp (string, ")") == 0)
336             {
337               align = 0;
338               state = ps_right;
339             }
340           else
341             state = ps_bad;
342         }
343       else if (TREE_CODE (token) == INTEGER_CST)
344         goto handle_align;
345
346 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
347       else if (TREE_CODE (token) == IDENTIFIER_NODE)
348         {
349           if (strcmp (string, "push") == 0)
350             type = state = ps_push;
351           else if (strcmp (string, "pop") == 0)
352             type = state = ps_pop;
353           else
354             state = ps_bad;
355         }
356 #endif
357       else
358         state = ps_bad;
359       break;
360
361     handle_align:
362       align = TREE_INT_CST_LOW (token);
363       switch (align)
364         {
365         case 1:
366         case 2:
367         case 4:
368         case 8:
369         case 16:
370           state = ps_align;
371           break;
372
373         default:
374           state = ps_bad;
375           break;
376         }
377       break;
378
379     case ps_align:
380       state = (strcmp (string, ")") ? ps_bad : ps_right);
381       break;
382
383     case ps_right:
384       state = ps_bad;
385       break;
386 #endif /* HANDLE_PRAGMA_PACK */
387
388 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
389     case ps_push:
390       state = (strcmp (string, ",") ? ps_bad : ps_pushcomma);
391       break;
392
393     case ps_pushid:
394       state = (strcmp (string, ",") ? ps_bad : ps_pushcomma2);
395       break;
396
397     case ps_pushcomma:
398       if (token && TREE_CODE (token) == IDENTIFIER_NODE)
399         {
400           id = token;
401           state = ps_pushid;
402           break;
403         }
404
405       /* else fall through */
406     case ps_pushcomma2:
407       if (token && TREE_CODE (token) == INTEGER_CST)
408         goto handle_align;
409       else
410         state = ps_bad;
411       break;
412
413     case ps_pop:
414       if (strcmp (string, ",") == 0)
415         state = ps_popcomma;
416       else
417         state = (strcmp (string, ")") ? ps_bad : ps_right);
418       break;
419
420     case ps_popcomma:
421       if (token && TREE_CODE (token) == IDENTIFIER_NODE)
422         {
423           id = token;
424           state = ps_align;
425         }
426       else
427         state = ps_bad;
428       break;
429 #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
430
431     case ps_poison:
432       if (token && TREE_CODE (token) != IDENTIFIER_NODE)
433         state = ps_bad;
434       break;
435
436     case ps_bad:
437     case ps_done:
438       break;
439
440     default:
441       abort ();
442     }
443
444   return 1;
445 }
446 #endif /* HANDLE_GENERIC_PRAGMAS */
447 \f
448 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
449 static void
450 mark_align_stack (p)
451     void *p;
452 {
453   align_stack *a = *(align_stack **) p;
454
455   while (a)
456     {
457       ggc_mark_tree (a->id);
458       a = a->prev;
459     }
460 }
461 #endif
462
463 void
464 init_pragma ()
465 {
466 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
467   ggc_add_root (&alignment_stack, 1, sizeof(alignment_stack),
468                 mark_align_stack);
469 #endif
470 }