c-pragma.c revision 90075
1/* Handle #pragma, system V.4 style. Supports #pragma weak and #pragma pack. 2 Copyright (C) 1992, 1997, 1998, 1999, 2000, 2001 3 Free Software Foundation, Inc. 4 5This file is part of GCC. 6 7GCC is free software; you can redistribute it and/or modify it under 8the terms of the GNU General Public License as published by the Free 9Software Foundation; either version 2, or (at your option) any later 10version. 11 12GCC is distributed in the hope that it will be useful, but WITHOUT ANY 13WARRANTY; without even the implied warranty of MERCHANTABILITY or 14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15for more details. 16 17You should have received a copy of the GNU General Public License 18along with GCC; see the file COPYING. If not, write to the Free 19Software Foundation, 59 Temple Place - Suite 330, Boston, MA 2002111-1307, USA. */ 21 22#include "config.h" 23#include "system.h" 24#include "rtl.h" 25#include "tree.h" 26#include "function.h" 27#include "cpplib.h" 28#include "c-pragma.h" 29#include "flags.h" 30#include "toplev.h" 31#include "ggc.h" 32#include "c-lex.h" 33#include "output.h" 34#include "tm_p.h" 35 36#define GCC_BAD(msgid) do { warning (msgid); return; } while (0) 37#define GCC_BAD2(msgid, arg) do { warning (msgid, arg); return; } while (0) 38 39#ifdef HANDLE_PRAGMA_PACK 40static void handle_pragma_pack PARAMS ((cpp_reader *)); 41 42#ifdef HANDLE_PRAGMA_PACK_PUSH_POP 43typedef struct align_stack 44{ 45 int alignment; 46 unsigned int num_pushes; 47 tree id; 48 struct align_stack * prev; 49} align_stack; 50 51static struct align_stack * alignment_stack = NULL; 52 53/* If we have a "global" #pragma pack(<n>) in effect when the first 54 #pragma pack(push,<n>) is encountered, this stores the value of 55 maximum_field_alignment in effect. When the final pop_alignment() 56 happens, we restore the value to this, not to a value of 0 for 57 maximum_field_alignment. Value is in bits. */ 58static int default_alignment; 59#define SET_GLOBAL_ALIGNMENT(ALIGN) \ 60(default_alignment = maximum_field_alignment = (ALIGN)) 61 62static void push_alignment PARAMS ((int, tree)); 63static void pop_alignment PARAMS ((tree)); 64static void mark_align_stack PARAMS ((void *)); 65 66/* Push an alignment value onto the stack. */ 67static void 68push_alignment (alignment, id) 69 int alignment; 70 tree id; 71{ 72 73 if (alignment_stack == NULL 74 || alignment_stack->alignment != alignment 75 || id != NULL_TREE) 76 { 77 align_stack * entry; 78 79 entry = (align_stack *) xmalloc (sizeof (* entry)); 80 81 entry->alignment = alignment; 82 entry->num_pushes = 1; 83 entry->id = id; 84 entry->prev = alignment_stack; 85 86 /* The current value of maximum_field_alignment is not necessarily 87 0 since there may be a #pragma pack(<n>) in effect; remember it 88 so that we can restore it after the final #pragma pop(). */ 89 if (alignment_stack == NULL) 90 default_alignment = maximum_field_alignment; 91 92 alignment_stack = entry; 93 94 maximum_field_alignment = alignment; 95 } 96 else 97 alignment_stack->num_pushes ++; 98} 99 100/* Undo a push of an alignment onto the stack. */ 101static void 102pop_alignment (id) 103 tree id; 104{ 105 align_stack * entry; 106 107 if (alignment_stack == NULL) 108 { 109 warning ("\ 110#pragma pack (pop) encountered without matching #pragma pack (push, <n>)" 111 ); 112 return; 113 } 114 115 /* If we got an identifier, strip away everything above the target 116 entry so that the next step will restore the state just below it. */ 117 if (id) 118 { 119 for (entry = alignment_stack; entry; entry = entry->prev) 120 if (entry->id == id) 121 { 122 entry->num_pushes = 1; 123 alignment_stack = entry; 124 break; 125 } 126 if (entry == NULL) 127 warning ("\ 128#pragma pack(pop, %s) encountered without matching #pragma pack(push, %s, <n>)" 129 , IDENTIFIER_POINTER (id), IDENTIFIER_POINTER (id)); 130 } 131 132 if (-- alignment_stack->num_pushes == 0) 133 { 134 entry = alignment_stack->prev; 135 136 if (entry == NULL) 137 maximum_field_alignment = default_alignment; 138 else 139 maximum_field_alignment = entry->alignment; 140 141 free (alignment_stack); 142 143 alignment_stack = entry; 144 } 145} 146 147static void 148mark_align_stack (p) 149 void *p; 150{ 151 align_stack *a = *(align_stack **) p; 152 153 while (a) 154 { 155 ggc_mark_tree (a->id); 156 a = a->prev; 157 } 158} 159#else /* not HANDLE_PRAGMA_PACK_PUSH_POP */ 160#define SET_GLOBAL_ALIGNMENT(ALIGN) (maximum_field_alignment = (ALIGN)) 161#define push_alignment(ID, N) \ 162 GCC_BAD("#pragma pack(push[, id], <n>) is not supported on this target") 163#define pop_alignment(ID) \ 164 GCC_BAD("#pragma pack(pop[, id], <n>) is not supported on this target") 165#endif /* HANDLE_PRAGMA_PACK_PUSH_POP */ 166 167/* #pragma pack () 168 #pragma pack (N) 169 170 #pragma pack (push, N) 171 #pragma pack (push, ID, N) 172 #pragma pack (pop) 173 #pragma pack (pop, ID) */ 174static void 175handle_pragma_pack (dummy) 176 cpp_reader *dummy ATTRIBUTE_UNUSED; 177{ 178 tree x, id = 0; 179 int align = -1; 180 enum cpp_ttype token; 181 enum { set, push, pop } action; 182 183 if (c_lex (&x) != CPP_OPEN_PAREN) 184 GCC_BAD ("missing '(' after '#pragma pack' - ignored"); 185 186 token = c_lex (&x); 187 if (token == CPP_CLOSE_PAREN) 188 { 189 action = set; 190 align = 0; 191 } 192 else if (token == CPP_NUMBER) 193 { 194 align = TREE_INT_CST_LOW (x); 195 action = set; 196 if (c_lex (&x) != CPP_CLOSE_PAREN) 197 GCC_BAD ("malformed '#pragma pack' - ignored"); 198 } 199 else if (token == CPP_NAME) 200 { 201#define GCC_BAD_ACTION do { if (action == push) \ 202 GCC_BAD ("malformed '#pragma pack(push[, id], <n>)' - ignored"); \ 203 else \ 204 GCC_BAD ("malformed '#pragma pack(pop[, id])' - ignored"); \ 205 } while (0) 206 207 const char *op = IDENTIFIER_POINTER (x); 208 if (!strcmp (op, "push")) 209 action = push; 210 else if (!strcmp (op, "pop")) 211 action = pop; 212 else 213 GCC_BAD2 ("unknown action '%s' for '#pragma pack' - ignored", op); 214 215 token = c_lex (&x); 216 if (token != CPP_COMMA && action == push) 217 GCC_BAD_ACTION; 218 219 if (token == CPP_COMMA) 220 { 221 token = c_lex (&x); 222 if (token == CPP_NAME) 223 { 224 id = x; 225 if (action == push && c_lex (&x) != CPP_COMMA) 226 GCC_BAD_ACTION; 227 token = c_lex (&x); 228 } 229 230 if (action == push) 231 { 232 if (token == CPP_NUMBER) 233 { 234 align = TREE_INT_CST_LOW (x); 235 token = c_lex (&x); 236 } 237 else 238 GCC_BAD_ACTION; 239 } 240 } 241 242 if (token != CPP_CLOSE_PAREN) 243 GCC_BAD_ACTION; 244#undef GCC_BAD_ACTION 245 } 246 else 247 GCC_BAD ("malformed '#pragma pack' - ignored"); 248 249 if (c_lex (&x) != CPP_EOF) 250 warning ("junk at end of '#pragma pack'"); 251 252 if (action != pop) 253 switch (align) 254 { 255 case 0: 256 case 1: 257 case 2: 258 case 4: 259 case 8: 260 case 16: 261 align *= BITS_PER_UNIT; 262 break; 263 default: 264 GCC_BAD2 ("alignment must be a small power of two, not %d", align); 265 } 266 267 switch (action) 268 { 269 case set: SET_GLOBAL_ALIGNMENT (align); break; 270 case push: push_alignment (align, id); break; 271 case pop: pop_alignment (id); break; 272 } 273} 274#endif /* HANDLE_PRAGMA_PACK */ 275 276#ifdef HANDLE_PRAGMA_WEAK 277static void handle_pragma_weak PARAMS ((cpp_reader *)); 278 279/* #pragma weak name [= value] */ 280static void 281handle_pragma_weak (dummy) 282 cpp_reader *dummy ATTRIBUTE_UNUSED; 283{ 284 tree name, value, x; 285 enum cpp_ttype t; 286 287 value = 0; 288 289 if (c_lex (&name) != CPP_NAME) 290 GCC_BAD ("malformed #pragma weak, ignored"); 291 t = c_lex (&x); 292 if (t == CPP_EQ) 293 { 294 if (c_lex (&value) != CPP_NAME) 295 GCC_BAD ("malformed #pragma weak, ignored"); 296 t = c_lex (&x); 297 } 298 if (t != CPP_EOF) 299 warning ("junk at end of #pragma weak"); 300 301 add_weak (IDENTIFIER_POINTER (name), value ? IDENTIFIER_POINTER (value) : 0); 302} 303#endif 304 305void 306init_pragma () 307{ 308#ifdef HANDLE_PRAGMA_PACK 309 cpp_register_pragma (parse_in, 0, "pack", handle_pragma_pack); 310#endif 311#ifdef HANDLE_PRAGMA_WEAK 312 cpp_register_pragma (parse_in, 0, "weak", handle_pragma_weak); 313#endif 314#ifdef REGISTER_TARGET_PRAGMAS 315 REGISTER_TARGET_PRAGMAS (parse_in); 316#endif 317 318#ifdef HANDLE_PRAGMA_PACK_PUSH_POP 319 ggc_add_root (&alignment_stack, 1, sizeof(alignment_stack), 320 mark_align_stack); 321#endif 322} 323