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