OSDN Git Service

09fac1feaabd0e4b9cb8a8fa755724bc1cc73f4f
[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 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 "except.h"
26 #include "function.h"
27 #include "defaults.h"
28 #include "c-pragma.h"
29 #include "flags.h"
30 #include "toplev.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   struct align_stack * prev;
49 } align_stack;
50
51 static struct align_stack * alignment_stack = NULL;
52
53 static int  push_alignment PROTO((int));
54 static int  pop_alignment  PROTO((void));
55
56 /* Push an alignment value onto the stack.  */
57 static int
58 push_alignment (alignment)
59      int alignment;
60 {
61   switch (alignment)
62     {
63     case 0:
64     case 1:
65     case 2:
66     case 4:
67     case 8:
68     case 16:
69       break;
70     default:
71       warning ("\
72 Alignment must be a small power of two, not %d, in #pragma pack",
73                alignment);
74       return 0;
75     }
76   
77   if (alignment_stack == NULL
78       || alignment_stack->alignment != alignment)
79     {
80       align_stack * entry;
81
82       entry = (align_stack *) xmalloc (sizeof (* entry));
83
84       if (entry == NULL)
85         {
86           warning ("Out of memory pushing #pragma pack");
87           return 0;
88         }
89
90       entry->alignment  = alignment;
91       entry->num_pushes = 1;
92       entry->prev       = alignment_stack;
93       
94       alignment_stack = entry;
95
96       if (alignment < 8)
97         maximum_field_alignment = alignment * 8;
98       else
99         /* MSVC ignores alignments > 4.  */
100         maximum_field_alignment = 0;
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 ()
111 {
112   if (alignment_stack == NULL)
113     {
114       warning ("\
115 #pragma pack(pop) encountered without corresponding #pragma pack(push,<n>)");
116       return 0;
117     }
118
119   if (-- alignment_stack->num_pushes == 0)
120     {
121       align_stack * entry;
122       
123       entry = alignment_stack->prev;
124
125       if (entry == NULL || entry->alignment > 4)
126         maximum_field_alignment = 0;
127       else
128         maximum_field_alignment = entry->alignment * 8;
129
130       free (alignment_stack);
131
132       alignment_stack = entry;
133     }
134
135   return 1;
136 }
137
138 /* Generate 'packed' and 'aligned' attributes for decls whilst a
139    #pragma pack(push... is in effect.  */
140 void
141 insert_pack_attributes (node, attributes, prefix)
142      tree node;
143      tree * attributes;
144      tree * prefix;
145 {
146   tree a;
147
148   /* If we are not packing, then there is nothing to do.  */
149   if (maximum_field_alignment == 0
150       || alignment_stack == NULL)
151     return;
152
153   /* We are only interested in fields.  */
154   if (TREE_CODE_CLASS (TREE_CODE (node)) != 'd'
155       || TREE_CODE (node) != FIELD_DECL)
156     return;
157
158   /* Add a 'packed' attribute.  */
159   * attributes = tree_cons (get_identifier ("packed"), NULL, * attributes);
160   
161   /* If the alignment is > 8 then add an alignment attribute as well.  */
162   if (maximum_field_alignment > 8)
163     {
164       /* If the aligned attribute is already present then do not override it.  */
165       for (a = * attributes; a; a = TREE_CHAIN (a))
166         {
167           tree name = TREE_PURPOSE (a);
168           if (strcmp (IDENTIFIER_POINTER (name), "aligned") == 0)
169             break;
170         }
171       
172       if (a == NULL)
173         for (a = * prefix; a; a = TREE_CHAIN (a))
174           {
175             tree name = TREE_PURPOSE (a);
176             if (strcmp (IDENTIFIER_POINTER (name), "aligned") == 0)
177               break;
178           }
179   
180       if (a == NULL)
181         {
182           * attributes = tree_cons
183               (get_identifier ("aligned"),
184                tree_cons (NULL,
185                           build_int_2 (maximum_field_alignment / 8, 0),
186                           NULL),
187                * attributes);
188         }
189     }
190
191   return;
192 }
193 #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
194 \f
195 /* Handle one token of a pragma directive.  TOKEN is the current token, and
196    STRING is its printable form.  Some front ends do not support generating
197    tokens, and will only pass in a STRING.  Also some front ends will reuse
198    the buffer containing STRING, so it must be copied to a local buffer if
199    it needs to be preserved.
200
201    If STRING is non-NULL, then the return value will be ignored, and there
202    will be futher calls to handle_pragma_token() in order to handle the rest of
203    the line containing the #pragma directive.  If STRING is NULL, the entire
204    line has now been presented to handle_pragma_token() and the return value
205    should be zero if the pragma flawed in some way, or if the pragma was not
206    recognised, and non-zero if it was successfully handled.  */
207
208 int
209 handle_pragma_token (string, token)
210      const char * string;
211      tree token;
212 {
213   static enum pragma_state state = ps_start;
214   static enum pragma_state type;
215   static char * name;
216   static char * value;
217   static int align;
218
219   /* If we have reached the end of the #pragma directive then
220      determine what value we should return.  */
221   
222   if (string == NULL)
223     {
224       int ret_val = 0;
225
226       switch (type)
227         {
228         default:
229           abort ();
230           break;
231
232         case ps_done:
233           /* The pragma was not recognised.  */
234           break;
235           
236 #ifdef HANDLE_PRAGMA_PACK         
237         case ps_pack:
238           if (state == ps_right)
239             {
240               maximum_field_alignment = align * 8;
241               ret_val = 1;
242             }
243           else
244             warning ("malformed `#pragma pack'");
245           break;
246 #endif /* HANDLE_PRAGMA_PACK */
247           
248 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
249         case ps_push:
250           if (state == ps_right)
251             ret_val = push_alignment (align);
252           else
253             warning ("incomplete '#pragma pack(push,<n>)'");
254           break;
255           
256         case ps_pop:
257           if (state == ps_right)
258             ret_val = pop_alignment ();
259           else
260             warning ("missing closing parenthesis in '#pragma pack(pop)'");
261           break;
262 #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
263           
264 #ifdef HANDLE_PRAGMA_WEAK
265         case ps_weak:
266           if (HANDLE_PRAGMA_WEAK)
267             {
268               if (state == ps_name)
269                 ret_val = add_weak (name, NULL);
270               else if (state == ps_value)
271                 ret_val = add_weak (name, value);
272               else
273                 warning ("malformed `#pragma weak'");
274             }
275           else
276             ret_val = 1; /* Ignore the pragma.  */
277           break;
278 #endif /* HANDLE_PRAGMA_WEAK */
279         }
280
281       type = state = ps_start;
282       
283       return ret_val;
284     }
285
286   /* If we have been given a token, but it is not an identifier,
287      or a small constant, then something has gone wrong.  */
288   if (token)
289     {
290       switch (TREE_CODE (token))
291         {
292         case IDENTIFIER_NODE:
293           break;
294           
295         case INTEGER_CST:
296           if (TREE_INT_CST_HIGH (token) != 0)
297             return 0;
298           break;
299           
300         default:
301           return 0;
302         }
303     }
304       
305   switch (state)
306     {
307     case ps_start:
308       type = state = ps_done;
309 #ifdef HANDLE_PRAGMA_PACK
310       if (strcmp (string, "pack") == 0)
311         type = state = ps_pack;
312 #endif
313 #ifdef HANDLE_PRAGMA_WEAK
314       if (strcmp (string, "weak") == 0)
315         type = state = ps_weak;
316 #endif    
317       break;
318       
319 #ifdef HANDLE_PRAGMA_WEAK
320     case ps_weak:
321       name = permalloc (strlen (string) + 1);
322       if (name == NULL)
323         {
324           warning ("Out of memory parsing #pragma weak");
325           state = ps_bad;
326         }
327       else
328         {
329           strcpy (name, string);
330           state = ps_name;
331         }
332       break;
333       
334     case ps_name:
335       state = (strcmp (string, "=") ? ps_bad : ps_equals);
336       break;
337
338     case ps_equals:
339       value = permalloc (strlen (string) + 1);
340       if (value == NULL)
341         {
342           warning ("Out of memory parsing #pragma weak");
343           state = ps_bad;
344         }
345       else
346         {
347           strcpy (value, string);
348           state = ps_value;
349         }
350       break;
351
352     case ps_value:
353       state = ps_bad;
354       break;
355 #endif /* HANDLE_PRAGMA_WEAK */
356       
357 #ifdef HANDLE_PRAGMA_PACK
358     case ps_pack:
359       state = (strcmp (string, "(") ? ps_bad : ps_left);
360       break;
361
362     case ps_left:
363
364       if (token && TREE_CODE(token) == INTEGER_CST) 
365         align = TREE_INT_CST_LOW(token);
366       else
367         align = atoi (string);
368       switch (align)
369         {
370         case 1:
371         case 2:
372         case 4:
373           state = ps_align;
374           break;
375
376         case 0:
377           state = (strcmp (string, ")") ? ps_bad : ps_right);
378 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
379           if (state == ps_bad)
380             {
381               if (strcmp (string, "push") == 0)
382                 type = state = ps_push;
383               else if (strcmp (string, "pop") == 0)
384                 type = state = ps_pop;
385             }
386 #endif
387           break;
388
389         default:
390           state = ps_bad;
391           break;
392         }
393       break;
394
395 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
396     case ps_pop:
397 #endif
398     case ps_align:
399       state = (strcmp (string, ")") ? ps_bad : ps_right);
400       break;
401
402     case ps_right:
403       state = ps_bad;
404       break;
405 #endif /* HANDLE_PRAGMA_PACK */
406
407 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
408     case ps_push:
409       state = (strcmp (string, ",") ? ps_bad : ps_comma);
410       break;
411
412     case ps_comma:
413       align = atoi (string);
414       state = ps_align;
415       break;
416 #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
417       
418     case ps_bad:
419     case ps_done:
420       break;
421
422     default:
423       abort ();
424     }
425
426   return 1;
427 }
428 #endif /* HANDLE_GENERIC_PRAGMAS */