OSDN Git Service

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