c-pragma.c revision 52284
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
4This file is part of GNU CC.
5
6GNU CC is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU CC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU CC; see the file COPYING.  If not, write to
18the Free Software Foundation, 59 Temple Place - Suite 330,
19Boston, 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
39extern int maximum_field_alignment;
40#endif
41
42
43#ifdef HANDLE_PRAGMA_PACK_PUSH_POP
44typedef struct align_stack
45{
46  int                  alignment;
47  unsigned int         num_pushes;
48  tree                 id;
49  struct align_stack * prev;
50} align_stack;
51
52static struct align_stack * alignment_stack = NULL;
53
54static int  push_alignment PROTO((int, tree));
55static int  pop_alignment  PROTO((tree));
56
57/* Push an alignment value onto the stack.  */
58static int
59push_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 ("\
74Alignment 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.  */
109static int
110pop_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.  */
159void
160insert_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
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
232int
233handle_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  static char * name;
240  static char * value;
241  static int align;
242  static tree id;
243
244  /* If we have reached the end of the #pragma directive then
245     determine what value we should return.  */
246
247  if (string == NULL)
248    {
249      int ret_val = 0;
250
251      switch (type)
252	{
253	default:
254	  abort ();
255	  break;
256
257	case ps_done:
258	  /* The pragma was not recognised.  */
259	  break;
260
261#ifdef HANDLE_PRAGMA_PACK
262	case ps_pack:
263	  if (state == ps_right)
264	    {
265	      maximum_field_alignment = align * 8;
266	      ret_val = 1;
267	    }
268	  else
269	    warning ("malformed `#pragma pack'");
270	  break;
271#endif /* HANDLE_PRAGMA_PACK */
272
273#ifdef HANDLE_PRAGMA_PACK_PUSH_POP
274	case ps_push:
275	  if (state == ps_right)
276	    ret_val = push_alignment (align, id);
277	  else
278	    warning ("malformed '#pragma pack(push[,id],<n>)'");
279	  break;
280
281	case ps_pop:
282	  if (state == ps_right)
283	    ret_val = pop_alignment (id);
284	  else
285	    warning ("malformed '#pragma pack(pop[,id])'");
286	  break;
287#endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
288
289#ifdef HANDLE_PRAGMA_WEAK
290	case ps_weak:
291	  if (HANDLE_PRAGMA_WEAK)
292	    {
293	      if (state == ps_name)
294		ret_val = add_weak (name, NULL);
295	      else if (state == ps_value)
296		ret_val = add_weak (name, value);
297	      else
298		warning ("malformed `#pragma weak'");
299	    }
300	  else
301	    ret_val = 1; /* Ignore the pragma.  */
302	  break;
303#endif /* HANDLE_PRAGMA_WEAK */
304	}
305
306      type = state = ps_start;
307      id = NULL_TREE;
308
309      return ret_val;
310    }
311
312  /* If we have been given a token, but it is not an identifier,
313     or a small constant, then something has gone wrong.  */
314  if (token)
315    {
316      switch (TREE_CODE (token))
317	{
318	case IDENTIFIER_NODE:
319	  break;
320
321	case INTEGER_CST:
322	  if (TREE_INT_CST_HIGH (token) != 0)
323	    return 0;
324	  break;
325
326	default:
327	  return 0;
328	}
329    }
330
331  switch (state)
332    {
333    case ps_start:
334      type = state = ps_done;
335#ifdef HANDLE_PRAGMA_PACK
336      if (strcmp (string, "pack") == 0)
337	type = state = ps_pack;
338#endif
339#ifdef HANDLE_PRAGMA_WEAK
340      if (strcmp (string, "weak") == 0)
341	type = state = ps_weak;
342#endif
343      break;
344
345#ifdef HANDLE_PRAGMA_WEAK
346    case ps_weak:
347      name = permalloc (strlen (string) + 1);
348      if (name == NULL)
349	{
350	  warning ("Out of memory parsing #pragma weak");
351	  state = ps_bad;
352	}
353      else
354	{
355	  strcpy (name, string);
356	  state = ps_name;
357	}
358      break;
359
360    case ps_name:
361      state = (strcmp (string, "=") ? ps_bad : ps_equals);
362      break;
363
364    case ps_equals:
365      value = permalloc (strlen (string) + 1);
366      if (value == NULL)
367	{
368	  warning ("Out of memory parsing #pragma weak");
369	  state = ps_bad;
370	}
371      else
372	{
373	  strcpy (value, string);
374	  state = ps_value;
375	}
376      break;
377
378    case ps_value:
379      state = ps_bad;
380      break;
381#endif /* HANDLE_PRAGMA_WEAK */
382
383#ifdef HANDLE_PRAGMA_PACK
384    case ps_pack:
385      state = (strcmp (string, "(") ? ps_bad : ps_left);
386      break;
387
388    case ps_left:
389
390      if (token == NULL_TREE)
391	{
392	  /* #pragma pack () resets packing rules to their
393	     defaults.  */
394	  if (strcmp (string, ")") == 0)
395	    {
396	      align = 0;
397	      state = ps_right;
398	    }
399	  else
400	    state = ps_bad;
401	}
402      else if (TREE_CODE (token) == INTEGER_CST)
403	goto handle_align;
404
405#ifdef HANDLE_PRAGMA_PACK_PUSH_POP
406      else if (TREE_CODE (token) == IDENTIFIER_NODE)
407	{
408	  if (strcmp (string, "push") == 0)
409	    type = state = ps_push;
410	  else if (strcmp (string, "pop") == 0)
411	    type = state = ps_pop;
412	  else
413	    state = ps_bad;
414	}
415#endif
416      else
417	state = ps_bad;
418      break;
419
420    handle_align:
421      align = TREE_INT_CST_LOW (token);
422      switch (align)
423	{
424	case 1:
425	case 2:
426	case 4:
427	case 8:
428	case 16:
429	  state = ps_align;
430	  break;
431
432	default:
433	  state = ps_bad;
434	  break;
435	}
436      break;
437
438    case ps_align:
439      state = (strcmp (string, ")") ? ps_bad : ps_right);
440      break;
441
442    case ps_right:
443      state = ps_bad;
444      break;
445#endif /* HANDLE_PRAGMA_PACK */
446
447#ifdef HANDLE_PRAGMA_PACK_PUSH_POP
448    case ps_push:
449      state = (strcmp (string, ",") ? ps_bad : ps_pushcomma);
450      break;
451
452    case ps_pushid:
453      state = (strcmp (string, ",") ? ps_bad : ps_pushcomma2);
454      break;
455
456    case ps_pushcomma:
457      if (token && TREE_CODE (token) == IDENTIFIER_NODE)
458	{
459	  id = token;
460	  state = ps_pushid;
461	  break;
462	}
463
464      /* else fall through */
465    case ps_pushcomma2:
466      if (token && TREE_CODE (token) == INTEGER_CST)
467	goto handle_align;
468      else
469	state = ps_bad;
470      break;
471
472    case ps_pop:
473      if (strcmp (string, ",") == 0)
474	state = ps_popcomma;
475      else
476	state = (strcmp (string, ")") ? ps_bad : ps_right);
477      break;
478
479    case ps_popcomma:
480      if (token && TREE_CODE (token) == IDENTIFIER_NODE)
481	{
482	  id = token;
483	  state = ps_align;
484	}
485      else
486	state = ps_bad;
487      break;
488#endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
489
490    case ps_bad:
491    case ps_done:
492      break;
493
494    default:
495      abort ();
496    }
497
498  return 1;
499}
500#endif /* HANDLE_GENERIC_PRAGMAS */
501