|
|
1.1 ! root 1: /* Language-dependent node constructors for parse phase of GNU compiler. ! 2: Copyright (C) 1987, 1988, 1992, 1993 Free Software Foundation, Inc. ! 3: Hacked by Michael Tiemann ([email protected]) ! 4: ! 5: This file is part of GNU CC. ! 6: ! 7: GNU CC is free software; you can redistribute it and/or modify ! 8: it under the terms of the GNU General Public License as published by ! 9: the Free Software Foundation; either version 2, or (at your option) ! 10: any later version. ! 11: ! 12: GNU CC is distributed in the hope that it will be useful, ! 13: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 15: GNU General Public License for more details. ! 16: ! 17: You should have received a copy of the GNU General Public License ! 18: along with GNU CC; see the file COPYING. If not, write to ! 19: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 20: ! 21: #include "config.h" ! 22: #include <stdio.h> ! 23: #include "obstack.h" ! 24: #include "tree.h" ! 25: #include "cp-tree.h" ! 26: #include "flags.h" ! 27: ! 28: #define CEIL(x,y) (((x) + (y) - 1) / (y)) ! 29: ! 30: /* Return nonzero if REF is an lvalue valid for this language. ! 31: Lvalues can be assigned, unless they have TREE_READONLY. ! 32: Lvalues can have their address taken, unless they have DECL_REGISTER. */ ! 33: ! 34: int ! 35: lvalue_p (ref) ! 36: tree ref; ! 37: { ! 38: register enum tree_code code = TREE_CODE (ref); ! 39: ! 40: if (language_lvalue_valid (ref)) ! 41: switch (code) ! 42: { ! 43: /* preincrements and predecrements are valid lvals, provided ! 44: what they refer to are valid lvals. */ ! 45: case PREINCREMENT_EXPR: ! 46: case PREDECREMENT_EXPR: ! 47: case COMPONENT_REF: ! 48: case SAVE_EXPR: ! 49: return lvalue_p (TREE_OPERAND (ref, 0)); ! 50: ! 51: case STRING_CST: ! 52: return 1; ! 53: ! 54: case VAR_DECL: ! 55: if (TREE_READONLY (ref) && ! TREE_STATIC (ref) ! 56: && DECL_LANG_SPECIFIC (ref) ! 57: && DECL_IN_AGGR_P (ref)) ! 58: return 0; ! 59: case INDIRECT_REF: ! 60: case ARRAY_REF: ! 61: case PARM_DECL: ! 62: case RESULT_DECL: ! 63: case ERROR_MARK: ! 64: if (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE ! 65: && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE) ! 66: return 1; ! 67: break; ! 68: ! 69: case TARGET_EXPR: ! 70: case WITH_CLEANUP_EXPR: ! 71: return 1; ! 72: ! 73: case CALL_EXPR: ! 74: if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE ! 75: /* unary_complex_lvalue knows how to deal with this case. */ ! 76: || TREE_ADDRESSABLE (TREE_TYPE (ref))) ! 77: return 1; ! 78: break; ! 79: ! 80: /* A currently unresolved scope ref. */ ! 81: case SCOPE_REF: ! 82: my_friendly_abort (103); ! 83: case OFFSET_REF: ! 84: if (TREE_CODE (TREE_OPERAND (ref, 1)) == FUNCTION_DECL) ! 85: return 1; ! 86: if (TREE_CODE (TREE_OPERAND (ref, 1)) == VAR_DECL) ! 87: if (TREE_READONLY (ref) && ! TREE_STATIC (ref) ! 88: && DECL_LANG_SPECIFIC (ref) ! 89: && DECL_IN_AGGR_P (ref)) ! 90: return 0; ! 91: else ! 92: return 1; ! 93: break; ! 94: ! 95: case ADDR_EXPR: ! 96: /* ANSI C++ June 5 1992 WP 5.4.14. The result of a cast to a ! 97: reference is an lvalue. */ ! 98: if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE) ! 99: return 1; ! 100: break; ! 101: } ! 102: return 0; ! 103: } ! 104: ! 105: /* Return nonzero if REF is an lvalue valid for this language; ! 106: otherwise, print an error message and return zero. */ ! 107: ! 108: int ! 109: lvalue_or_else (ref, string) ! 110: tree ref; ! 111: char *string; ! 112: { ! 113: int win = lvalue_p (ref); ! 114: if (! win) ! 115: error ("invalid lvalue in %s", string); ! 116: return win; ! 117: } ! 118: ! 119: /* INIT is a CALL_EXPR which needs info about its target. ! 120: TYPE is the type that this initialization should appear to have. ! 121: ! 122: Build an encapsulation of the initialization to perform ! 123: and return it so that it can be processed by language-independent ! 124: and language-specific expression expanders. ! 125: ! 126: If WITH_CLEANUP_P is nonzero, we build a cleanup for this expression. ! 127: Otherwise, cleanups are not built here. For example, when building ! 128: an initialization for a stack slot, since the called function handles ! 129: the cleanup, we would not want to do it here. */ ! 130: tree ! 131: build_cplus_new (type, init, with_cleanup_p) ! 132: tree type; ! 133: tree init; ! 134: int with_cleanup_p; ! 135: { ! 136: tree slot = build (VAR_DECL, type); ! 137: tree rval = build (NEW_EXPR, type, ! 138: TREE_OPERAND (init, 0), TREE_OPERAND (init, 1), slot); ! 139: TREE_SIDE_EFFECTS (rval) = 1; ! 140: TREE_ADDRESSABLE (rval) = 1; ! 141: rval = build (TARGET_EXPR, type, slot, rval, 0); ! 142: TREE_SIDE_EFFECTS (rval) = 1; ! 143: TREE_ADDRESSABLE (rval) = 1; ! 144: ! 145: if (with_cleanup_p && TYPE_NEEDS_DESTRUCTOR (type)) ! 146: { ! 147: rval = build (WITH_CLEANUP_EXPR, type, rval, 0, ! 148: build_delete (TYPE_POINTER_TO (type), ! 149: build_unary_op (ADDR_EXPR, slot, 0), ! 150: integer_two_node, ! 151: LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0)); ! 152: TREE_SIDE_EFFECTS (rval) = 1; ! 153: } ! 154: return rval; ! 155: } ! 156: ! 157: /* Recursively search EXP for CALL_EXPRs that need cleanups and replace ! 158: these CALL_EXPRs with tree nodes that will perform the cleanups. */ ! 159: ! 160: tree ! 161: break_out_cleanups (exp) ! 162: tree exp; ! 163: { ! 164: tree tmp = exp; ! 165: ! 166: if (TREE_CODE (tmp) == CALL_EXPR ! 167: && TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (tmp))) ! 168: return build_cplus_new (TREE_TYPE (tmp), tmp, 1); ! 169: ! 170: while (TREE_CODE (tmp) == NOP_EXPR ! 171: || TREE_CODE (tmp) == CONVERT_EXPR ! 172: || TREE_CODE (tmp) == NON_LVALUE_EXPR) ! 173: { ! 174: if (TREE_CODE (TREE_OPERAND (tmp, 0)) == CALL_EXPR ! 175: && TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (TREE_OPERAND (tmp, 0)))) ! 176: { ! 177: TREE_OPERAND (tmp, 0) ! 178: = build_cplus_new (TREE_TYPE (TREE_OPERAND (tmp, 0)), ! 179: TREE_OPERAND (tmp, 0), 1); ! 180: break; ! 181: } ! 182: else ! 183: tmp = TREE_OPERAND (tmp, 0); ! 184: } ! 185: return exp; ! 186: } ! 187: ! 188: /* Recursively perform a preorder search EXP for CALL_EXPRs, making ! 189: copies where they are found. Returns a deep copy all nodes transitively ! 190: containing CALL_EXPRs. */ ! 191: ! 192: tree ! 193: break_out_calls (exp) ! 194: tree exp; ! 195: { ! 196: register tree t1, t2; ! 197: register enum tree_code code; ! 198: register int changed = 0; ! 199: register int i; ! 200: ! 201: if (exp == NULL_TREE) ! 202: return exp; ! 203: ! 204: code = TREE_CODE (exp); ! 205: ! 206: if (code == CALL_EXPR) ! 207: return copy_node (exp); ! 208: ! 209: /* Don't try and defeat a save_expr, as it should only be done once. */ ! 210: if (code == SAVE_EXPR) ! 211: return exp; ! 212: ! 213: switch (TREE_CODE_CLASS (code)) ! 214: { ! 215: default: ! 216: abort (); ! 217: ! 218: case 'c': /* a constant */ ! 219: case 't': /* a type node */ ! 220: case 'x': /* something random, like an identifier or an ERROR_MARK. */ ! 221: return exp; ! 222: ! 223: case 'd': /* A decl node */ ! 224: t1 = break_out_calls (DECL_INITIAL (exp)); ! 225: if (t1 != DECL_INITIAL (exp)) ! 226: { ! 227: exp = copy_node (exp); ! 228: DECL_INITIAL (exp) = t1; ! 229: } ! 230: return exp; ! 231: ! 232: case 'b': /* A block node */ ! 233: { ! 234: /* Don't know how to handle these correctly yet. Must do a ! 235: break_out_calls on all DECL_INITIAL values for local variables, ! 236: and also break_out_calls on all sub-blocks and sub-statements. */ ! 237: abort (); ! 238: } ! 239: return exp; ! 240: ! 241: case 'e': /* an expression */ ! 242: case 'r': /* a reference */ ! 243: case 's': /* an expression with side effects */ ! 244: for (i = tree_code_length[(int) code] - 1; i >= 0; i--) ! 245: { ! 246: t1 = break_out_calls (TREE_OPERAND (exp, i)); ! 247: if (t1 != TREE_OPERAND (exp, i)) ! 248: { ! 249: exp = copy_node (exp); ! 250: TREE_OPERAND (exp, i) = t1; ! 251: } ! 252: } ! 253: return exp; ! 254: ! 255: case '<': /* a comparison expression */ ! 256: case '2': /* a binary arithmetic expression */ ! 257: t2 = break_out_calls (TREE_OPERAND (exp, 1)); ! 258: if (t2 != TREE_OPERAND (exp, 1)) ! 259: changed = 1; ! 260: case '1': /* a unary arithmetic expression */ ! 261: t1 = break_out_calls (TREE_OPERAND (exp, 0)); ! 262: if (t1 != TREE_OPERAND (exp, 0)) ! 263: changed = 1; ! 264: if (changed) ! 265: { ! 266: if (tree_code_length[(int) code] == 1) ! 267: return build1 (code, TREE_TYPE (exp), t1); ! 268: else ! 269: return build (code, TREE_TYPE (exp), t1, t2); ! 270: } ! 271: return exp; ! 272: } ! 273: ! 274: } ! 275: ! 276: extern struct obstack *current_obstack; ! 277: extern struct obstack permanent_obstack, class_obstack; ! 278: extern struct obstack *saveable_obstack; ! 279: ! 280: /* Here is how primitive or already-canonicalized types' hash ! 281: codes are made. MUST BE CONSISTENT WITH tree.c !!! */ ! 282: #define TYPE_HASH(TYPE) ((HOST_WIDE_INT) (TYPE) & 0777777) ! 283: ! 284: /* Construct, lay out and return the type of methods belonging to class ! 285: BASETYPE and whose arguments are described by ARGTYPES and whose values ! 286: are described by RETTYPE. If each type exists already, reuse it. */ ! 287: tree ! 288: build_cplus_method_type (basetype, rettype, argtypes) ! 289: tree basetype, rettype, argtypes; ! 290: { ! 291: register tree t; ! 292: tree ptype = build_pointer_type (basetype); ! 293: int hashcode; ! 294: ! 295: /* Make a node of the sort we want. */ ! 296: t = make_node (METHOD_TYPE); ! 297: ! 298: TYPE_METHOD_BASETYPE (t) = TYPE_MAIN_VARIANT (basetype); ! 299: TREE_TYPE (t) = rettype; ! 300: #if 0 ! 301: /* it is wrong to flag the object the pointer points to as readonly ! 302: when flag_this_is_variable is 0. */ ! 303: ptype = build_type_variant (ptype, flag_this_is_variable <= 0, 0); ! 304: #else ! 305: ptype = build_type_variant (ptype, 0, 0); ! 306: #endif ! 307: /* The actual arglist for this function includes a "hidden" argument ! 308: which is "this". Put it into the list of argument types. */ ! 309: ! 310: argtypes = tree_cons (NULL_TREE, ptype, argtypes); ! 311: TYPE_ARG_TYPES (t) = argtypes; ! 312: TREE_SIDE_EFFECTS (argtypes) = 1; /* Mark first argtype as "artificial". */ ! 313: ! 314: /* If we already have such a type, use the old one and free this one. ! 315: Note that it also frees up the above cons cell if found. */ ! 316: hashcode = TYPE_HASH (basetype) + TYPE_HASH (rettype) + type_hash_list (argtypes); ! 317: t = type_hash_canon (hashcode, t); ! 318: ! 319: if (TYPE_SIZE (t) == 0) ! 320: layout_type (t); ! 321: ! 322: return t; ! 323: } ! 324: ! 325: tree ! 326: build_cplus_staticfn_type (basetype, rettype, argtypes) ! 327: tree basetype, rettype, argtypes; ! 328: { ! 329: register tree t; ! 330: int hashcode; ! 331: ! 332: /* Make a node of the sort we want. */ ! 333: t = make_node (FUNCTION_TYPE); ! 334: ! 335: TYPE_METHOD_BASETYPE (t) = TYPE_MAIN_VARIANT (basetype); ! 336: TREE_TYPE (t) = rettype; ! 337: ! 338: /* The actual arglist for this function includes a "hidden" argument ! 339: which is "this". Put it into the list of argument types. */ ! 340: ! 341: TYPE_ARG_TYPES (t) = argtypes; ! 342: ! 343: /* If we already have such a type, use the old one and free this one. ! 344: Note that it also frees up the above cons cell if found. */ ! 345: hashcode = TYPE_HASH (basetype) + TYPE_HASH (rettype) + type_hash_list (argtypes); ! 346: t = type_hash_canon (hashcode, t); ! 347: ! 348: if (TYPE_SIZE (t) == 0) ! 349: layout_type (t); ! 350: ! 351: return t; ! 352: } ! 353: ! 354: tree ! 355: build_cplus_array_type (elt_type, index_type) ! 356: tree elt_type; ! 357: tree index_type; ! 358: { ! 359: register struct obstack *ambient_obstack = current_obstack; ! 360: register struct obstack *ambient_saveable_obstack = saveable_obstack; ! 361: tree t; ! 362: ! 363: /* We need a new one. If both ELT_TYPE and INDEX_TYPE are permanent, ! 364: make this permanent too. */ ! 365: if (TREE_PERMANENT (elt_type) ! 366: && (index_type == 0 || TREE_PERMANENT (index_type))) ! 367: { ! 368: current_obstack = &permanent_obstack; ! 369: saveable_obstack = &permanent_obstack; ! 370: } ! 371: ! 372: t = build_array_type (elt_type, index_type); ! 373: ! 374: /* Push these needs up so that initialization takes place ! 375: more easily. */ ! 376: TYPE_NEEDS_CONSTRUCTING (t) = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (elt_type)); ! 377: TYPE_NEEDS_DESTRUCTOR (t) = TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (elt_type)); ! 378: current_obstack = ambient_obstack; ! 379: saveable_obstack = ambient_saveable_obstack; ! 380: return t; ! 381: } ! 382: ! 383: /* Add OFFSET to all base types of T. ! 384: ! 385: OFFSET, which is a type offset, is number of bytes. ! 386: ! 387: Note that we don't have to worry about having two paths to the ! 388: same base type, since this type owns its association list. */ ! 389: void ! 390: propagate_binfo_offsets (binfo, offset) ! 391: tree binfo; ! 392: tree offset; ! 393: { ! 394: tree binfos = BINFO_BASETYPES (binfo); ! 395: int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0; ! 396: ! 397: for (i = 0; i < n_baselinks; /* note increment is done in the loop. */) ! 398: { ! 399: tree base_binfo = TREE_VEC_ELT (binfos, i); ! 400: ! 401: if (TREE_VIA_VIRTUAL (base_binfo)) ! 402: i += 1; ! 403: else ! 404: { ! 405: int j; ! 406: tree base_binfos = BINFO_BASETYPES (base_binfo); ! 407: tree delta; ! 408: ! 409: for (j = i+1; j < n_baselinks; j++) ! 410: if (! TREE_VIA_VIRTUAL (TREE_VEC_ELT (binfos, j))) ! 411: { ! 412: /* The next basetype offset must take into account the space ! 413: between the classes, not just the size of each class. */ ! 414: delta = size_binop (MINUS_EXPR, ! 415: BINFO_OFFSET (TREE_VEC_ELT (binfos, j)), ! 416: BINFO_OFFSET (base_binfo)); ! 417: break; ! 418: } ! 419: ! 420: #if 0 ! 421: if (BINFO_OFFSET_ZEROP (base_binfo)) ! 422: BINFO_OFFSET (base_binfo) = offset; ! 423: else ! 424: BINFO_OFFSET (base_binfo) ! 425: = size_binop (PLUS_EXPR, BINFO_OFFSET (base_binfo), offset); ! 426: #else ! 427: BINFO_OFFSET (base_binfo) = offset; ! 428: #endif ! 429: if (base_binfos) ! 430: { ! 431: int k; ! 432: tree chain = NULL_TREE; ! 433: ! 434: /* Now unshare the structure beneath BASE_BINFO. */ ! 435: for (k = TREE_VEC_LENGTH (base_binfos)-1; ! 436: k >= 0; k--) ! 437: { ! 438: tree base_base_binfo = TREE_VEC_ELT (base_binfos, k); ! 439: if (! TREE_VIA_VIRTUAL (base_base_binfo)) ! 440: TREE_VEC_ELT (base_binfos, k) ! 441: = make_binfo (BINFO_OFFSET (base_base_binfo), ! 442: BINFO_TYPE (base_base_binfo), ! 443: BINFO_VTABLE (base_base_binfo), ! 444: BINFO_VIRTUALS (base_base_binfo), ! 445: chain); ! 446: chain = TREE_VEC_ELT (base_binfos, k); ! 447: TREE_VIA_PUBLIC (chain) = TREE_VIA_PUBLIC (base_base_binfo); ! 448: TREE_VIA_PROTECTED (chain) = TREE_VIA_PROTECTED (base_base_binfo); ! 449: } ! 450: /* Now propagate the offset to the base types. */ ! 451: propagate_binfo_offsets (base_binfo, offset); ! 452: } ! 453: ! 454: /* Go to our next class that counts for offset propagation. */ ! 455: i = j; ! 456: if (i < n_baselinks) ! 457: offset = size_binop (PLUS_EXPR, offset, delta); ! 458: } ! 459: } ! 460: } ! 461: ! 462: /* Compute the actual offsets that our virtual base classes ! 463: will have *for this type*. This must be performed after ! 464: the fields are laid out, since virtual baseclasses must ! 465: lay down at the end of the record. ! 466: ! 467: Returns the maximum number of virtual functions any of the virtual ! 468: baseclasses provide. */ ! 469: int ! 470: layout_vbasetypes (rec, max) ! 471: tree rec; ! 472: int max; ! 473: { ! 474: /* Get all the virtual base types that this type uses. ! 475: The TREE_VALUE slot holds the virtual baseclass type. */ ! 476: tree vbase_types = get_vbase_types (rec); ! 477: ! 478: #ifdef STRUCTURE_SIZE_BOUNDARY ! 479: unsigned record_align = MAX (STRUCTURE_SIZE_BOUNDARY, TYPE_ALIGN (rec)); ! 480: #else ! 481: unsigned record_align = MAX (BITS_PER_UNIT, TYPE_ALIGN (rec)); ! 482: #endif ! 483: ! 484: /* Record size so far is CONST_SIZE + VAR_SIZE bits, ! 485: where CONST_SIZE is an integer ! 486: and VAR_SIZE is a tree expression. ! 487: If VAR_SIZE is null, the size is just CONST_SIZE. ! 488: Naturally we try to avoid using VAR_SIZE. */ ! 489: register unsigned const_size = 0; ! 490: register tree var_size = 0; ! 491: int nonvirtual_const_size; ! 492: tree nonvirtual_var_size; ! 493: ! 494: CLASSTYPE_VBASECLASSES (rec) = vbase_types; ! 495: ! 496: if (TREE_CODE (TYPE_SIZE (rec)) == INTEGER_CST) ! 497: const_size = TREE_INT_CST_LOW (TYPE_SIZE (rec)); ! 498: else ! 499: var_size = TYPE_SIZE (rec); ! 500: ! 501: nonvirtual_const_size = const_size; ! 502: nonvirtual_var_size = var_size; ! 503: ! 504: while (vbase_types) ! 505: { ! 506: tree basetype = BINFO_TYPE (vbase_types); ! 507: tree offset; ! 508: ! 509: if (const_size == 0) ! 510: offset = integer_zero_node; ! 511: else ! 512: offset = size_int ((const_size + BITS_PER_UNIT - 1) / BITS_PER_UNIT); ! 513: ! 514: if (CLASSTYPE_VSIZE (basetype) > max) ! 515: max = CLASSTYPE_VSIZE (basetype); ! 516: BINFO_OFFSET (vbase_types) = offset; ! 517: ! 518: if (TREE_CODE (TYPE_SIZE (basetype)) == INTEGER_CST) ! 519: const_size += MAX (record_align, ! 520: TREE_INT_CST_LOW (TYPE_SIZE (basetype)) ! 521: - TREE_INT_CST_LOW (CLASSTYPE_VBASE_SIZE (basetype))); ! 522: else if (var_size == 0) ! 523: var_size = TYPE_SIZE (basetype); ! 524: else ! 525: var_size = size_binop (PLUS_EXPR, var_size, TYPE_SIZE (basetype)); ! 526: ! 527: vbase_types = TREE_CHAIN (vbase_types); ! 528: } ! 529: ! 530: if (const_size != nonvirtual_const_size) ! 531: { ! 532: CLASSTYPE_VBASE_SIZE (rec) ! 533: = size_int (const_size - nonvirtual_const_size); ! 534: TYPE_SIZE (rec) = size_int (const_size); ! 535: } ! 536: ! 537: /* Now propagate offset information throughout the lattice ! 538: under the vbase type. */ ! 539: for (vbase_types = CLASSTYPE_VBASECLASSES (rec); vbase_types; ! 540: vbase_types = TREE_CHAIN (vbase_types)) ! 541: { ! 542: tree base_binfos = BINFO_BASETYPES (vbase_types); ! 543: ! 544: if (base_binfos) ! 545: { ! 546: tree chain = NULL_TREE; ! 547: int j; ! 548: /* Now unshare the structure beneath BASE_BINFO. */ ! 549: ! 550: for (j = TREE_VEC_LENGTH (base_binfos)-1; ! 551: j >= 0; j--) ! 552: { ! 553: tree base_base_binfo = TREE_VEC_ELT (base_binfos, j); ! 554: if (! TREE_VIA_VIRTUAL (base_base_binfo)) ! 555: TREE_VEC_ELT (base_binfos, j) ! 556: = make_binfo (BINFO_OFFSET (base_base_binfo), ! 557: BINFO_TYPE (base_base_binfo), ! 558: BINFO_VTABLE (base_base_binfo), ! 559: BINFO_VIRTUALS (base_base_binfo), ! 560: chain); ! 561: chain = TREE_VEC_ELT (base_binfos, j); ! 562: TREE_VIA_PUBLIC (chain) = TREE_VIA_PUBLIC (base_base_binfo); ! 563: TREE_VIA_PROTECTED (chain) = TREE_VIA_PROTECTED (base_base_binfo); ! 564: } ! 565: ! 566: propagate_binfo_offsets (vbase_types, BINFO_OFFSET (vbase_types)); ! 567: } ! 568: } ! 569: ! 570: return max; ! 571: } ! 572: ! 573: /* Lay out the base types of a record type, REC. ! 574: Tentatively set the size and alignment of REC ! 575: according to the base types alone. ! 576: ! 577: Offsets for immediate nonvirtual baseclasses are also computed here. ! 578: ! 579: Returns list of virtual base classes in a FIELD_DECL chain. */ ! 580: tree ! 581: layout_basetypes (rec, binfos) ! 582: tree rec, binfos; ! 583: { ! 584: /* Chain to hold all the new FIELD_DECLs which point at virtual ! 585: base classes. */ ! 586: tree vbase_decls = NULL_TREE; ! 587: ! 588: #ifdef STRUCTURE_SIZE_BOUNDARY ! 589: unsigned record_align = MAX (STRUCTURE_SIZE_BOUNDARY, TYPE_ALIGN (rec)); ! 590: #else ! 591: unsigned record_align = MAX (BITS_PER_UNIT, TYPE_ALIGN (rec)); ! 592: #endif ! 593: ! 594: /* Record size so far is CONST_SIZE + VAR_SIZE bits, ! 595: where CONST_SIZE is an integer ! 596: and VAR_SIZE is a tree expression. ! 597: If VAR_SIZE is null, the size is just CONST_SIZE. ! 598: Naturally we try to avoid using VAR_SIZE. */ ! 599: register unsigned const_size = 0; ! 600: register tree var_size = 0; ! 601: int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0; ! 602: ! 603: /* Handle basetypes almost like fields, but record their ! 604: offsets differently. */ ! 605: ! 606: for (i = 0; i < n_baseclasses; i++) ! 607: { ! 608: int inc, desired_align, int_vbase_size; ! 609: register tree base_binfo = TREE_VEC_ELT (binfos, i); ! 610: register tree basetype = BINFO_TYPE (base_binfo); ! 611: tree decl, offset; ! 612: ! 613: if (TYPE_SIZE (basetype) == 0) ! 614: { ! 615: #if 0 ! 616: /* This error is now reported in xref_tag, thus giving better ! 617: location information. */ ! 618: error_with_aggr_type (base_binfo, ! 619: "base class `%s' has incomplete type"); ! 620: ! 621: TREE_VIA_PUBLIC (base_binfo) = 1; ! 622: TREE_VIA_PROTECTED (base_binfo) = 0; ! 623: TREE_VIA_VIRTUAL (base_binfo) = 0; ! 624: ! 625: /* Should handle this better so that ! 626: ! 627: class A; ! 628: class B: private A { virtual void F(); }; ! 629: ! 630: does not dump core when compiled. */ ! 631: my_friendly_abort (121); ! 632: #endif ! 633: continue; ! 634: } ! 635: ! 636: /* All basetypes are recorded in the association list of the ! 637: derived type. */ ! 638: ! 639: if (TREE_VIA_VIRTUAL (base_binfo)) ! 640: { ! 641: int j; ! 642: char *name = (char *)alloca (TYPE_NAME_LENGTH (basetype) ! 643: + sizeof (VBASE_NAME) + 1); ! 644: ! 645: /* The offset for a virtual base class is only used in computing ! 646: virtual function tables and for initializing virtual base ! 647: pointers. It is built once `get_vbase_types' is called. */ ! 648: ! 649: /* If this basetype can come from another vbase pointer ! 650: without an additional indirection, we will share ! 651: that pointer. If an indirection is involved, we ! 652: make our own pointer. */ ! 653: for (j = 0; j < n_baseclasses; j++) ! 654: { ! 655: tree other_base_binfo = TREE_VEC_ELT (binfos, j); ! 656: if (! TREE_VIA_VIRTUAL (other_base_binfo) ! 657: && binfo_member (basetype, ! 658: CLASSTYPE_VBASECLASSES (BINFO_TYPE (other_base_binfo)))) ! 659: goto got_it; ! 660: } ! 661: sprintf (name, VBASE_NAME_FORMAT, TYPE_NAME_STRING (basetype)); ! 662: decl = build_lang_decl (FIELD_DECL, get_identifier (name), ! 663: build_pointer_type (basetype)); ! 664: /* If you change any of the below, take a look at all the ! 665: other VFIELD_BASEs and VTABLE_BASEs in the code, and change ! 666: them too. */ ! 667: DECL_ASSEMBLER_NAME (decl) = get_identifier (VTABLE_BASE); ! 668: DECL_VIRTUAL_P (decl) = 1; ! 669: DECL_FIELD_CONTEXT (decl) = rec; ! 670: DECL_CLASS_CONTEXT (decl) = rec; ! 671: DECL_FCONTEXT (decl) = basetype; ! 672: DECL_FIELD_SIZE (decl) = 0; ! 673: DECL_ALIGN (decl) = TYPE_ALIGN (ptr_type_node); ! 674: TREE_CHAIN (decl) = vbase_decls; ! 675: BINFO_VPTR_FIELD (base_binfo) = decl; ! 676: vbase_decls = decl; ! 677: ! 678: if (warn_nonvdtor && TYPE_HAS_DESTRUCTOR (basetype) ! 679: && DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0)) == NULL_TREE) ! 680: { ! 681: warning_with_decl (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0), ! 682: "destructor `%s' non-virtual"); ! 683: warning ("in inheritance relationship `%s: virtual %s'", ! 684: TYPE_NAME_STRING (rec), ! 685: TYPE_NAME_STRING (basetype)); ! 686: } ! 687: got_it: ! 688: /* The space this decl occupies has already been accounted for. */ ! 689: continue; ! 690: } ! 691: ! 692: if (const_size == 0) ! 693: offset = integer_zero_node; ! 694: else ! 695: { ! 696: /* Give each base type the alignment it wants. */ ! 697: const_size = CEIL (const_size, TYPE_ALIGN (basetype)) ! 698: * TYPE_ALIGN (basetype); ! 699: offset = size_int ((const_size + BITS_PER_UNIT - 1) / BITS_PER_UNIT); ! 700: ! 701: #if 0 ! 702: /* bpk: Disabled this check until someone is willing to ! 703: claim it as theirs and explain exactly what circumstances ! 704: warrant the warning. */ ! 705: if (warn_nonvdtor && TYPE_HAS_DESTRUCTOR (basetype) ! 706: && DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0)) == NULL_TREE) ! 707: { ! 708: warning_with_decl (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0), ! 709: "destructor `%s' non-virtual"); ! 710: warning ("in inheritance relationship `%s:%s %s'", ! 711: TYPE_NAME_STRING (rec), ! 712: TREE_VIA_VIRTUAL (base_binfo) ? " virtual" : "", ! 713: TYPE_NAME_STRING (basetype)); ! 714: } ! 715: #endif ! 716: } ! 717: BINFO_OFFSET (base_binfo) = offset; ! 718: if (CLASSTYPE_VSIZE (basetype)) ! 719: { ! 720: BINFO_VTABLE (base_binfo) = TYPE_BINFO_VTABLE (basetype); ! 721: BINFO_VIRTUALS (base_binfo) = TYPE_BINFO_VIRTUALS (basetype); ! 722: } ! 723: TREE_CHAIN (base_binfo) = TYPE_BINFO (rec); ! 724: TYPE_BINFO (rec) = base_binfo; ! 725: ! 726: /* Add only the amount of storage not present in ! 727: the virtual baseclasses. */ ! 728: ! 729: int_vbase_size = TREE_INT_CST_LOW (CLASSTYPE_VBASE_SIZE (basetype)); ! 730: if (TREE_INT_CST_LOW (TYPE_SIZE (basetype)) > int_vbase_size) ! 731: { ! 732: inc = MAX (record_align, ! 733: (TREE_INT_CST_LOW (TYPE_SIZE (basetype)) ! 734: - int_vbase_size)); ! 735: ! 736: /* Record must have at least as much alignment as any field. */ ! 737: desired_align = TYPE_ALIGN (basetype); ! 738: record_align = MAX (record_align, desired_align); ! 739: ! 740: const_size += inc; ! 741: } ! 742: } ! 743: ! 744: if (const_size) ! 745: CLASSTYPE_SIZE (rec) = size_int (const_size); ! 746: else ! 747: CLASSTYPE_SIZE (rec) = integer_zero_node; ! 748: CLASSTYPE_ALIGN (rec) = record_align; ! 749: ! 750: return vbase_decls; ! 751: } ! 752: ! 753: /* Hashing of lists so that we don't make duplicates. ! 754: The entry point is `list_hash_canon'. */ ! 755: ! 756: /* Each hash table slot is a bucket containing a chain ! 757: of these structures. */ ! 758: ! 759: struct list_hash ! 760: { ! 761: struct list_hash *next; /* Next structure in the bucket. */ ! 762: int hashcode; /* Hash code of this list. */ ! 763: tree list; /* The list recorded here. */ ! 764: }; ! 765: ! 766: /* Now here is the hash table. When recording a list, it is added ! 767: to the slot whose index is the hash code mod the table size. ! 768: Note that the hash table is used for several kinds of lists. ! 769: While all these live in the same table, they are completely independent, ! 770: and the hash code is computed differently for each of these. */ ! 771: ! 772: #define TYPE_HASH_SIZE 59 ! 773: struct list_hash *list_hash_table[TYPE_HASH_SIZE]; ! 774: ! 775: /* Compute a hash code for a list (chain of TREE_LIST nodes ! 776: with goodies in the TREE_PURPOSE, TREE_VALUE, and bits of the ! 777: TREE_COMMON slots), by adding the hash codes of the individual entries. */ ! 778: ! 779: int ! 780: list_hash (list) ! 781: tree list; ! 782: { ! 783: register int hashcode = 0; ! 784: ! 785: if (TREE_CHAIN (list)) ! 786: hashcode += TYPE_HASH (TREE_CHAIN (list)); ! 787: ! 788: if (TREE_VALUE (list)) ! 789: hashcode += TYPE_HASH (TREE_VALUE (list)); ! 790: else ! 791: hashcode += 1007; ! 792: if (TREE_PURPOSE (list)) ! 793: hashcode += TYPE_HASH (TREE_PURPOSE (list)); ! 794: else ! 795: hashcode += 1009; ! 796: return hashcode; ! 797: } ! 798: ! 799: /* Look in the type hash table for a type isomorphic to TYPE. ! 800: If one is found, return it. Otherwise return 0. */ ! 801: ! 802: tree ! 803: list_hash_lookup (hashcode, list) ! 804: int hashcode; ! 805: tree list; ! 806: { ! 807: register struct list_hash *h; ! 808: for (h = list_hash_table[hashcode % TYPE_HASH_SIZE]; h; h = h->next) ! 809: if (h->hashcode == hashcode ! 810: && TREE_VIA_VIRTUAL (h->list) == TREE_VIA_VIRTUAL (list) ! 811: && TREE_VIA_PUBLIC (h->list) == TREE_VIA_PUBLIC (list) ! 812: && TREE_VIA_PROTECTED (h->list) == TREE_VIA_PROTECTED (list) ! 813: && TREE_PURPOSE (h->list) == TREE_PURPOSE (list) ! 814: && TREE_VALUE (h->list) == TREE_VALUE (list) ! 815: && TREE_CHAIN (h->list) == TREE_CHAIN (list)) ! 816: { ! 817: my_friendly_assert (TREE_TYPE (h->list) == TREE_TYPE (list), 299); ! 818: return h->list; ! 819: } ! 820: return 0; ! 821: } ! 822: ! 823: /* Add an entry to the list-hash-table ! 824: for a list TYPE whose hash code is HASHCODE. */ ! 825: ! 826: void ! 827: list_hash_add (hashcode, list) ! 828: int hashcode; ! 829: tree list; ! 830: { ! 831: register struct list_hash *h; ! 832: ! 833: h = (struct list_hash *) obstack_alloc (&class_obstack, sizeof (struct list_hash)); ! 834: h->hashcode = hashcode; ! 835: h->list = list; ! 836: h->next = list_hash_table[hashcode % TYPE_HASH_SIZE]; ! 837: list_hash_table[hashcode % TYPE_HASH_SIZE] = h; ! 838: } ! 839: ! 840: /* Given TYPE, and HASHCODE its hash code, return the canonical ! 841: object for an identical list if one already exists. ! 842: Otherwise, return TYPE, and record it as the canonical object ! 843: if it is a permanent object. ! 844: ! 845: To use this function, first create a list of the sort you want. ! 846: Then compute its hash code from the fields of the list that ! 847: make it different from other similar lists. ! 848: Then call this function and use the value. ! 849: This function frees the list you pass in if it is a duplicate. */ ! 850: ! 851: /* Set to 1 to debug without canonicalization. Never set by program. */ ! 852: int debug_no_list_hash = 0; ! 853: ! 854: tree ! 855: list_hash_canon (hashcode, list) ! 856: int hashcode; ! 857: tree list; ! 858: { ! 859: tree t1; ! 860: ! 861: if (debug_no_list_hash) ! 862: return list; ! 863: ! 864: t1 = list_hash_lookup (hashcode, list); ! 865: if (t1 != 0) ! 866: { ! 867: obstack_free (&class_obstack, list); ! 868: return t1; ! 869: } ! 870: ! 871: /* If this is a new list, record it for later reuse. */ ! 872: list_hash_add (hashcode, list); ! 873: ! 874: return list; ! 875: } ! 876: ! 877: tree ! 878: hash_tree_cons (via_public, via_virtual, via_protected, purpose, value, chain) ! 879: int via_public, via_virtual, via_protected; ! 880: tree purpose, value, chain; ! 881: { ! 882: struct obstack *ambient_obstack = current_obstack; ! 883: tree t; ! 884: int hashcode; ! 885: ! 886: current_obstack = &class_obstack; ! 887: t = tree_cons (purpose, value, chain); ! 888: TREE_VIA_PUBLIC (t) = via_public; ! 889: TREE_VIA_PROTECTED (t) = via_protected; ! 890: TREE_VIA_VIRTUAL (t) = via_virtual; ! 891: hashcode = list_hash (t); ! 892: t = list_hash_canon (hashcode, t); ! 893: current_obstack = ambient_obstack; ! 894: return t; ! 895: } ! 896: ! 897: /* Constructor for hashed lists. */ ! 898: tree ! 899: hash_tree_chain (value, chain) ! 900: tree value, chain; ! 901: { ! 902: struct obstack *ambient_obstack = current_obstack; ! 903: tree t; ! 904: int hashcode; ! 905: ! 906: current_obstack = &class_obstack; ! 907: t = tree_cons (NULL_TREE, value, chain); ! 908: hashcode = list_hash (t); ! 909: t = list_hash_canon (hashcode, t); ! 910: current_obstack = ambient_obstack; ! 911: return t; ! 912: } ! 913: ! 914: /* Similar, but used for concatenating two lists. */ ! 915: tree ! 916: hash_chainon (list1, list2) ! 917: tree list1, list2; ! 918: { ! 919: if (list2 == 0) ! 920: return list1; ! 921: if (list1 == 0) ! 922: return list2; ! 923: if (TREE_CHAIN (list1) == NULL_TREE) ! 924: return hash_tree_chain (TREE_VALUE (list1), list2); ! 925: return hash_tree_chain (TREE_VALUE (list1), ! 926: hash_chainon (TREE_CHAIN (list1), list2)); ! 927: } ! 928: ! 929: tree ! 930: get_decl_list (value) ! 931: tree value; ! 932: { ! 933: tree list = NULL_TREE; ! 934: ! 935: if (TREE_CODE (value) == IDENTIFIER_NODE) ! 936: { ! 937: list = IDENTIFIER_AS_LIST (value); ! 938: if (list != NULL_TREE ! 939: && (TREE_CODE (list) != TREE_LIST ! 940: || TREE_VALUE (list) != value)) ! 941: list = NULL_TREE; ! 942: else if (IDENTIFIER_HAS_TYPE_VALUE (value) ! 943: && TREE_CODE (IDENTIFIER_TYPE_VALUE (value)) == RECORD_TYPE) ! 944: { ! 945: register tree id; ! 946: tree type = IDENTIFIER_TYPE_VALUE (value); ! 947: ! 948: /* This will return the correct thing for regular types, ! 949: nested types, and templates. Yay! */ ! 950: if (DECL_NESTED_TYPENAME (TYPE_NAME (type))) ! 951: value = DECL_NESTED_TYPENAME (TYPE_NAME (type)); ! 952: id = value; ! 953: ! 954: if (CLASSTYPE_ID_AS_LIST (type) == NULL_TREE) ! 955: CLASSTYPE_ID_AS_LIST (type) = perm_tree_cons (NULL_TREE, ! 956: id, NULL_TREE); ! 957: list = CLASSTYPE_ID_AS_LIST (type); ! 958: } ! 959: } ! 960: else if (TREE_CODE (value) == RECORD_TYPE ! 961: && TYPE_LANG_SPECIFIC (value)) ! 962: list = CLASSTYPE_AS_LIST (value); ! 963: ! 964: if (list != NULL_TREE) ! 965: { ! 966: my_friendly_assert (TREE_CHAIN (list) == NULL_TREE, 301); ! 967: return list; ! 968: } ! 969: ! 970: #ifdef OBJCPLUS ! 971: return build_tree_list (NULL_TREE, value); ! 972: #else ! 973: return build_decl_list (NULL_TREE, value); ! 974: #endif ! 975: } ! 976: ! 977: /* Look in the type hash table for a type isomorphic to ! 978: `build_tree_list (NULL_TREE, VALUE)'. ! 979: If one is found, return it. Otherwise return 0. */ ! 980: ! 981: tree ! 982: list_hash_lookup_or_cons (value) ! 983: tree value; ! 984: { ! 985: register int hashcode = TYPE_HASH (value); ! 986: register struct list_hash *h; ! 987: struct obstack *ambient_obstack; ! 988: tree list = NULL_TREE; ! 989: ! 990: if (TREE_CODE (value) == IDENTIFIER_NODE) ! 991: { ! 992: list = IDENTIFIER_AS_LIST (value); ! 993: if (list != NULL_TREE ! 994: && (TREE_CODE (list) != TREE_LIST ! 995: || TREE_VALUE (list) != value)) ! 996: list = NULL_TREE; ! 997: else if (IDENTIFIER_HAS_TYPE_VALUE (value) ! 998: && TREE_CODE (IDENTIFIER_TYPE_VALUE (value)) == RECORD_TYPE) ! 999: { ! 1000: /* If the type name and constructor name are different, don't ! 1001: write constructor name into type. */ ! 1002: if (identifier_typedecl_value (value) ! 1003: && identifier_typedecl_value (value) != constructor_name (value)) ! 1004: list = tree_cons (NULL_TREE, value, NULL_TREE); ! 1005: else ! 1006: { ! 1007: tree type = IDENTIFIER_TYPE_VALUE (value); ! 1008: if (CLASSTYPE_ID_AS_LIST (type) == NULL_TREE) ! 1009: { ! 1010: /* Not just `value', which could be a template parm. */ ! 1011: tree id = DECL_NAME (TYPE_NAME (type)); ! 1012: CLASSTYPE_ID_AS_LIST (type) = ! 1013: perm_tree_cons (NULL_TREE, id, NULL_TREE); ! 1014: } ! 1015: list = CLASSTYPE_ID_AS_LIST (type); ! 1016: } ! 1017: } ! 1018: } ! 1019: else if (TREE_CODE (value) == TYPE_DECL ! 1020: && TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE ! 1021: && TYPE_LANG_SPECIFIC (TREE_TYPE (value))) ! 1022: list = CLASSTYPE_ID_AS_LIST (TREE_TYPE (value)); ! 1023: else if (TREE_CODE (value) == RECORD_TYPE ! 1024: && TYPE_LANG_SPECIFIC (value)) ! 1025: list = CLASSTYPE_AS_LIST (value); ! 1026: ! 1027: if (list != NULL_TREE) ! 1028: { ! 1029: my_friendly_assert (TREE_CHAIN (list) == NULL_TREE, 302); ! 1030: return list; ! 1031: } ! 1032: ! 1033: if (debug_no_list_hash) ! 1034: return hash_tree_chain (value, NULL_TREE); ! 1035: ! 1036: for (h = list_hash_table[hashcode % TYPE_HASH_SIZE]; h; h = h->next) ! 1037: if (h->hashcode == hashcode ! 1038: && TREE_VIA_VIRTUAL (h->list) == 0 ! 1039: && TREE_VIA_PUBLIC (h->list) == 0 ! 1040: && TREE_VIA_PROTECTED (h->list) == 0 ! 1041: && TREE_PURPOSE (h->list) == 0 ! 1042: && TREE_VALUE (h->list) == value) ! 1043: { ! 1044: my_friendly_assert (TREE_TYPE (h->list) == 0, 303); ! 1045: my_friendly_assert (TREE_CHAIN (h->list) == 0, 304); ! 1046: return h->list; ! 1047: } ! 1048: ! 1049: ambient_obstack = current_obstack; ! 1050: current_obstack = &class_obstack; ! 1051: list = build_tree_list (NULL_TREE, value); ! 1052: list_hash_add (hashcode, list); ! 1053: current_obstack = ambient_obstack; ! 1054: return list; ! 1055: } ! 1056: ! 1057: /* Build an association between TYPE and some parameters: ! 1058: ! 1059: OFFSET is the offset added to `this' to convert it to a pointer ! 1060: of type `TYPE *' ! 1061: ! 1062: VTABLE is the virtual function table with which to initialize ! 1063: sub-objects of type TYPE. ! 1064: ! 1065: VIRTUALS are the virtual functions sitting in VTABLE. ! 1066: ! 1067: CHAIN are more associations we must retain. */ ! 1068: ! 1069: tree ! 1070: make_binfo (offset, type, vtable, virtuals, chain) ! 1071: tree offset, type; ! 1072: tree vtable, virtuals; ! 1073: tree chain; ! 1074: { ! 1075: tree binfo = make_tree_vec (6); ! 1076: tree old_binfo = TYPE_BINFO (type); ! 1077: tree last; ! 1078: ! 1079: TREE_CHAIN (binfo) = chain; ! 1080: if (chain) ! 1081: TREE_USED (binfo) = TREE_USED (chain); ! 1082: ! 1083: TREE_TYPE (binfo) = TYPE_MAIN_VARIANT (type); ! 1084: BINFO_OFFSET (binfo) = offset; ! 1085: BINFO_VTABLE (binfo) = vtable; ! 1086: BINFO_VIRTUALS (binfo) = virtuals; ! 1087: BINFO_VPTR_FIELD (binfo) = NULL_TREE; ! 1088: ! 1089: last = binfo; ! 1090: if (old_binfo != NULL_TREE ! 1091: && BINFO_BASETYPES (old_binfo) != NULL_TREE) ! 1092: { ! 1093: int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (type); ! 1094: tree binfos = TYPE_BINFO_BASETYPES (type); ! 1095: ! 1096: BINFO_BASETYPES (binfo) = make_tree_vec (n_baseclasses); ! 1097: for (i = 0; i < n_baseclasses; i++) ! 1098: { ! 1099: tree base_binfo = TREE_VEC_ELT (binfos, i); ! 1100: tree old_base_binfo = old_binfo ? BINFO_BASETYPE (old_binfo, i) : 0; ! 1101: BINFO_BASETYPE (binfo, i) = base_binfo; ! 1102: if (old_binfo) ! 1103: { ! 1104: TREE_VIA_PUBLIC (base_binfo) = TREE_VIA_PUBLIC (old_base_binfo); ! 1105: TREE_VIA_PROTECTED (base_binfo) = TREE_VIA_PROTECTED (old_base_binfo); ! 1106: TREE_VIA_VIRTUAL (base_binfo) = TREE_VIA_VIRTUAL (old_base_binfo); ! 1107: } ! 1108: } ! 1109: } ! 1110: return binfo; ! 1111: } ! 1112: ! 1113: tree ! 1114: copy_binfo (list) ! 1115: tree list; ! 1116: { ! 1117: tree binfo = copy_list (list); ! 1118: tree rval = binfo; ! 1119: while (binfo) ! 1120: { ! 1121: TREE_USED (binfo) = 0; ! 1122: if (BINFO_BASETYPES (binfo)) ! 1123: BINFO_BASETYPES (binfo) = copy_node (BINFO_BASETYPES (binfo)); ! 1124: binfo = TREE_CHAIN (binfo); ! 1125: } ! 1126: return rval; ! 1127: } ! 1128: ! 1129: /* Return the binfo value for ELEM in TYPE. */ ! 1130: ! 1131: tree ! 1132: binfo_value (elem, type) ! 1133: tree elem; ! 1134: tree type; ! 1135: { ! 1136: if (get_base_distance (elem, type, 0, (tree *)0) == -2) ! 1137: compiler_error ("base class `%s' ambiguous in binfo_value", ! 1138: TYPE_NAME_STRING (elem)); ! 1139: if (elem == type) ! 1140: return TYPE_BINFO (type); ! 1141: if (TREE_CODE (elem) == RECORD_TYPE && TYPE_BINFO (elem) == type) ! 1142: return type; ! 1143: return get_binfo (elem, type, 0); ! 1144: } ! 1145: ! 1146: tree ! 1147: reverse_path (path) ! 1148: tree path; ! 1149: { ! 1150: register tree prev = 0, tmp, next; ! 1151: for (tmp = path; tmp; tmp = next) ! 1152: { ! 1153: next = BINFO_INHERITANCE_CHAIN (tmp); ! 1154: BINFO_INHERITANCE_CHAIN (tmp) = prev; ! 1155: prev = tmp; ! 1156: } ! 1157: return prev; ! 1158: } ! 1159: ! 1160: tree ! 1161: virtual_member (elem, list) ! 1162: tree elem; ! 1163: tree list; ! 1164: { ! 1165: tree t; ! 1166: tree rval, nval; ! 1167: ! 1168: for (t = list; t; t = TREE_CHAIN (t)) ! 1169: if (elem == BINFO_TYPE (t)) ! 1170: return t; ! 1171: rval = 0; ! 1172: for (t = list; t; t = TREE_CHAIN (t)) ! 1173: { ! 1174: tree binfos = BINFO_BASETYPES (t); ! 1175: int i; ! 1176: ! 1177: if (binfos != NULL_TREE) ! 1178: for (i = TREE_VEC_LENGTH (binfos)-1; i >= 0; i--) ! 1179: { ! 1180: nval = binfo_value (elem, BINFO_TYPE (TREE_VEC_ELT (binfos, i))); ! 1181: if (nval) ! 1182: { ! 1183: if (rval && BINFO_OFFSET (nval) != BINFO_OFFSET (rval)) ! 1184: my_friendly_abort (104); ! 1185: rval = nval; ! 1186: } ! 1187: } ! 1188: } ! 1189: return rval; ! 1190: } ! 1191: ! 1192: /* Return the offset (as an INTEGER_CST) for ELEM in LIST. ! 1193: INITIAL_OFFSET is the value to add to the offset that ELEM's ! 1194: binfo entry in LIST provides. ! 1195: ! 1196: Returns NULL if ELEM does not have an binfo value in LIST. */ ! 1197: ! 1198: tree ! 1199: virtual_offset (elem, list, initial_offset) ! 1200: tree elem; ! 1201: tree list; ! 1202: tree initial_offset; ! 1203: { ! 1204: tree vb, offset; ! 1205: tree rval, nval; ! 1206: ! 1207: for (vb = list; vb; vb = TREE_CHAIN (vb)) ! 1208: if (elem == BINFO_TYPE (vb)) ! 1209: return size_binop (PLUS_EXPR, initial_offset, BINFO_OFFSET (vb)); ! 1210: rval = 0; ! 1211: for (vb = list; vb; vb = TREE_CHAIN (vb)) ! 1212: { ! 1213: tree binfos = BINFO_BASETYPES (vb); ! 1214: int i; ! 1215: ! 1216: if (binfos == NULL_TREE) ! 1217: continue; ! 1218: ! 1219: for (i = TREE_VEC_LENGTH (binfos)-1; i >= 0; i--) ! 1220: { ! 1221: nval = binfo_value (elem, BINFO_TYPE (TREE_VEC_ELT (binfos, i))); ! 1222: if (nval) ! 1223: { ! 1224: if (rval && BINFO_OFFSET (nval) != BINFO_OFFSET (rval)) ! 1225: my_friendly_abort (105); ! 1226: offset = BINFO_OFFSET (vb); ! 1227: rval = nval; ! 1228: } ! 1229: } ! 1230: } ! 1231: if (rval == NULL_TREE) ! 1232: return rval; ! 1233: return size_binop (PLUS_EXPR, offset, BINFO_OFFSET (rval)); ! 1234: } ! 1235: ! 1236: void ! 1237: debug_binfo (elem) ! 1238: tree elem; ! 1239: { ! 1240: int i; ! 1241: tree virtuals; ! 1242: ! 1243: fprintf (stderr, "type \"%s\"; offset = %d\n", ! 1244: TYPE_NAME_STRING (BINFO_TYPE (elem)), ! 1245: TREE_INT_CST_LOW (BINFO_OFFSET (elem))); ! 1246: fprintf (stderr, "vtable type:\n"); ! 1247: debug_tree (BINFO_TYPE (elem)); ! 1248: if (BINFO_VTABLE (elem)) ! 1249: fprintf (stderr, "vtable decl \"%s\"\n", IDENTIFIER_POINTER (DECL_NAME (BINFO_VTABLE (elem)))); ! 1250: else ! 1251: fprintf (stderr, "no vtable decl yet\n"); ! 1252: fprintf (stderr, "virtuals:\n"); ! 1253: virtuals = BINFO_VIRTUALS (elem); ! 1254: if (virtuals != 0) ! 1255: { ! 1256: virtuals = TREE_CHAIN (virtuals); ! 1257: if (flag_dossier) ! 1258: virtuals = TREE_CHAIN (virtuals); ! 1259: } ! 1260: i = 1; ! 1261: while (virtuals) ! 1262: { ! 1263: tree fndecl = TREE_OPERAND (FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals)), 0); ! 1264: fprintf (stderr, "%s [%d =? %d]\n", ! 1265: IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)), ! 1266: i, TREE_INT_CST_LOW (DECL_VINDEX (fndecl))); ! 1267: virtuals = TREE_CHAIN (virtuals); ! 1268: i += 1; ! 1269: } ! 1270: } ! 1271: ! 1272: /* Return the length of a chain of nodes chained through DECL_CHAIN. ! 1273: We expect a null pointer to mark the end of the chain. ! 1274: This is the Lisp primitive `length'. */ ! 1275: ! 1276: int ! 1277: decl_list_length (t) ! 1278: tree t; ! 1279: { ! 1280: register tree tail; ! 1281: register int len = 0; ! 1282: ! 1283: my_friendly_assert (TREE_CODE (t) == FUNCTION_DECL, 300); ! 1284: for (tail = t; tail; tail = DECL_CHAIN (tail)) ! 1285: len++; ! 1286: ! 1287: return len; ! 1288: } ! 1289: ! 1290: int ! 1291: count_functions (t) ! 1292: tree t; ! 1293: { ! 1294: if (TREE_CODE (t) == FUNCTION_DECL) ! 1295: return 1; ! 1296: ! 1297: return decl_list_length (TREE_VALUE (t)); ! 1298: } ! 1299: ! 1300: tree ! 1301: fnaddr_from_vtable_entry (entry) ! 1302: tree entry; ! 1303: { ! 1304: return TREE_VALUE (TREE_CHAIN (TREE_CHAIN (CONSTRUCTOR_ELTS (entry)))); ! 1305: } ! 1306: ! 1307: void ! 1308: set_fnaddr_from_vtable_entry (entry, value) ! 1309: tree entry, value; ! 1310: { ! 1311: TREE_VALUE (TREE_CHAIN (TREE_CHAIN (CONSTRUCTOR_ELTS (entry)))) = value; ! 1312: } ! 1313: ! 1314: tree ! 1315: function_arg_chain (t) ! 1316: tree t; ! 1317: { ! 1318: return TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (t))); ! 1319: } ! 1320: ! 1321: int ! 1322: promotes_to_aggr_type (t, code) ! 1323: tree t; ! 1324: enum tree_code code; ! 1325: { ! 1326: if (TREE_CODE (t) == code) ! 1327: t = TREE_TYPE (t); ! 1328: return IS_AGGR_TYPE (t); ! 1329: } ! 1330: ! 1331: int ! 1332: is_aggr_type_2 (t1, t2) ! 1333: tree t1, t2; ! 1334: { ! 1335: if (TREE_CODE (t1) != TREE_CODE (t2)) ! 1336: return 0; ! 1337: return IS_AGGR_TYPE (t1) && IS_AGGR_TYPE (t2); ! 1338: } ! 1339: ! 1340: /* Give message using types TYPE1 and TYPE2 as arguments. ! 1341: PFN is the function which will print the message; ! 1342: S is the format string for PFN to use. */ ! 1343: void ! 1344: message_2_types (pfn, s, type1, type2) ! 1345: void (*pfn) (); ! 1346: char *s; ! 1347: tree type1, type2; ! 1348: { ! 1349: tree name1 = TYPE_NAME (type1); ! 1350: tree name2 = TYPE_NAME (type2); ! 1351: if (TREE_CODE (name1) == TYPE_DECL) ! 1352: name1 = DECL_NAME (name1); ! 1353: if (TREE_CODE (name2) == TYPE_DECL) ! 1354: name2 = DECL_NAME (name2); ! 1355: (*pfn) (s, IDENTIFIER_POINTER (name1), IDENTIFIER_POINTER (name2)); ! 1356: } ! 1357: ! 1358: #define PRINT_RING_SIZE 4 ! 1359: ! 1360: char * ! 1361: lang_printable_name (decl) ! 1362: tree decl; ! 1363: { ! 1364: static tree decl_ring[PRINT_RING_SIZE]; ! 1365: static char *print_ring[PRINT_RING_SIZE]; ! 1366: static int ring_counter; ! 1367: int i; ! 1368: ! 1369: /* Only cache functions. */ ! 1370: if (TREE_CODE (decl) != FUNCTION_DECL ! 1371: || DECL_LANG_SPECIFIC (decl) == 0) ! 1372: return decl_as_string (decl, 1); ! 1373: ! 1374: /* See if this print name is lying around. */ ! 1375: for (i = 0; i < PRINT_RING_SIZE; i++) ! 1376: if (decl_ring[i] == decl) ! 1377: /* yes, so return it. */ ! 1378: return print_ring[i]; ! 1379: ! 1380: if (++ring_counter == PRINT_RING_SIZE) ! 1381: ring_counter = 0; ! 1382: ! 1383: if (current_function_decl != NULL_TREE) ! 1384: { ! 1385: if (decl_ring[ring_counter] == current_function_decl) ! 1386: ring_counter += 1; ! 1387: if (ring_counter == PRINT_RING_SIZE) ! 1388: ring_counter = 0; ! 1389: if (decl_ring[ring_counter] == current_function_decl) ! 1390: my_friendly_abort (106); ! 1391: } ! 1392: ! 1393: if (print_ring[ring_counter]) ! 1394: free (print_ring[ring_counter]); ! 1395: ! 1396: { ! 1397: int print_ret_type_p ! 1398: = (!DECL_CONSTRUCTOR_P (decl) ! 1399: && !DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl))); ! 1400: ! 1401: char *name = (char *)decl_as_string (decl, print_ret_type_p); ! 1402: print_ring[ring_counter] = (char *)malloc (strlen (name) + 1); ! 1403: strcpy (print_ring[ring_counter], name); ! 1404: decl_ring[ring_counter] = decl; ! 1405: } ! 1406: return print_ring[ring_counter]; ! 1407: } ! 1408: ! 1409: /* Comparison function for sorting identifiers in RAISES lists. ! 1410: Note that because IDENTIFIER_NODEs are unique, we can sort ! 1411: them by address, saving an indirection. */ ! 1412: static int ! 1413: id_cmp (p1, p2) ! 1414: tree *p1, *p2; ! 1415: { ! 1416: return (HOST_WIDE_INT)TREE_VALUE (*p1) - (HOST_WIDE_INT)TREE_VALUE (*p2); ! 1417: } ! 1418: ! 1419: /* Build the FUNCTION_TYPE or METHOD_TYPE which may raise exceptions ! 1420: listed in RAISES. */ ! 1421: tree ! 1422: build_exception_variant (ctype, type, raises) ! 1423: tree ctype, type; ! 1424: tree raises; ! 1425: { ! 1426: int i; ! 1427: tree v = TYPE_MAIN_VARIANT (type); ! 1428: tree t, t2, cname; ! 1429: tree *a = (tree *)alloca ((list_length (raises)+1) * sizeof (tree)); ! 1430: int constp = TYPE_READONLY (type); ! 1431: int volatilep = TYPE_VOLATILE (type); ! 1432: ! 1433: if (raises && TREE_CHAIN (raises)) ! 1434: { ! 1435: for (i = 0, t = raises; t; t = TREE_CHAIN (t), i++) ! 1436: a[i] = t; ! 1437: /* NULL terminator for list. */ ! 1438: a[i] = NULL_TREE; ! 1439: qsort (a, i, sizeof (tree), id_cmp); ! 1440: while (i--) ! 1441: TREE_CHAIN (a[i]) = a[i+1]; ! 1442: raises = a[0]; ! 1443: } ! 1444: else if (raises) ! 1445: /* do nothing. */; ! 1446: else ! 1447: return build_type_variant (v, constp, volatilep); ! 1448: ! 1449: if (ctype) ! 1450: { ! 1451: cname = TYPE_NAME (ctype); ! 1452: if (TREE_CODE (cname) == TYPE_DECL) ! 1453: cname = DECL_NAME (cname); ! 1454: } ! 1455: else ! 1456: cname = NULL_TREE; ! 1457: ! 1458: for (t = raises; t; t = TREE_CHAIN (t)) ! 1459: { ! 1460: /* See that all the exceptions we are thinking about ! 1461: raising have been declared. */ ! 1462: tree this_cname = lookup_exception_cname (ctype, cname, t); ! 1463: tree decl = lookup_exception_object (this_cname, TREE_VALUE (t), 1); ! 1464: ! 1465: if (decl == NULL_TREE) ! 1466: decl = lookup_exception_object (this_cname, TREE_VALUE (t), 0); ! 1467: /* Place canonical exception decl into TREE_TYPE of RAISES list. */ ! 1468: TREE_TYPE (t) = decl; ! 1469: } ! 1470: ! 1471: for (v = TYPE_NEXT_VARIANT (v); v; v = TYPE_NEXT_VARIANT (v)) ! 1472: { ! 1473: if (TYPE_READONLY (v) != constp ! 1474: || TYPE_VOLATILE (v) != volatilep) ! 1475: continue; ! 1476: ! 1477: t = raises; ! 1478: t2 = TYPE_RAISES_EXCEPTIONS (v); ! 1479: while (t && t2) ! 1480: { ! 1481: if (TREE_TYPE (t) == TREE_TYPE (t2)) ! 1482: { ! 1483: t = TREE_CHAIN (t); ! 1484: t2 = TREE_CHAIN (t2); ! 1485: } ! 1486: else break; ! 1487: } ! 1488: if (t || t2) ! 1489: continue; ! 1490: /* List of exceptions raised matches previously found list. ! 1491: ! 1492: @@ Nice to free up storage used in consing up the ! 1493: @@ list of exceptions raised. */ ! 1494: return v; ! 1495: } ! 1496: ! 1497: /* Need to build a new variant. */ ! 1498: v = copy_node (type); ! 1499: TYPE_NEXT_VARIANT (v) = TYPE_NEXT_VARIANT (type); ! 1500: TYPE_NEXT_VARIANT (type) = v; ! 1501: if (raises && ! TREE_PERMANENT (raises)) ! 1502: { ! 1503: push_obstacks_nochange (); ! 1504: end_temporary_allocation (); ! 1505: raises = copy_list (raises); ! 1506: pop_obstacks (); ! 1507: } ! 1508: TYPE_RAISES_EXCEPTIONS (v) = raises; ! 1509: return v; ! 1510: } ! 1511: ! 1512: /* Subroutine of copy_to_permanent ! 1513: ! 1514: Assuming T is a node build bottom-up, make it all exist on ! 1515: permanent obstack, if it is not permanent already. */ ! 1516: static tree ! 1517: make_deep_copy (t) ! 1518: tree t; ! 1519: { ! 1520: enum tree_code code; ! 1521: ! 1522: if (t == NULL_TREE || TREE_PERMANENT (t)) ! 1523: return t; ! 1524: ! 1525: switch (code = TREE_CODE (t)) ! 1526: { ! 1527: case ERROR_MARK: ! 1528: return error_mark_node; ! 1529: ! 1530: case VAR_DECL: ! 1531: case FUNCTION_DECL: ! 1532: case CONST_DECL: ! 1533: break; ! 1534: ! 1535: case PARM_DECL: ! 1536: { ! 1537: tree chain = TREE_CHAIN (t); ! 1538: t = copy_node (t); ! 1539: TREE_CHAIN (t) = make_deep_copy (chain); ! 1540: TREE_TYPE (t) = make_deep_copy (TREE_TYPE (t)); ! 1541: DECL_INITIAL (t) = make_deep_copy (DECL_INITIAL (t)); ! 1542: DECL_SIZE (t) = make_deep_copy (DECL_SIZE (t)); ! 1543: return t; ! 1544: } ! 1545: ! 1546: case TREE_LIST: ! 1547: { ! 1548: tree chain = TREE_CHAIN (t); ! 1549: t = copy_node (t); ! 1550: TREE_PURPOSE (t) = make_deep_copy (TREE_PURPOSE (t)); ! 1551: TREE_VALUE (t) = make_deep_copy (TREE_VALUE (t)); ! 1552: TREE_CHAIN (t) = make_deep_copy (chain); ! 1553: return t; ! 1554: } ! 1555: ! 1556: case TREE_VEC: ! 1557: { ! 1558: int len = TREE_VEC_LENGTH (t); ! 1559: ! 1560: t = copy_node (t); ! 1561: while (len--) ! 1562: TREE_VEC_ELT (t, len) = make_deep_copy (TREE_VEC_ELT (t, len)); ! 1563: return t; ! 1564: } ! 1565: ! 1566: case INTEGER_CST: ! 1567: case REAL_CST: ! 1568: case STRING_CST: ! 1569: return copy_node (t); ! 1570: ! 1571: case COND_EXPR: ! 1572: case TARGET_EXPR: ! 1573: case NEW_EXPR: ! 1574: t = copy_node (t); ! 1575: TREE_OPERAND (t, 0) = make_deep_copy (TREE_OPERAND (t, 0)); ! 1576: TREE_OPERAND (t, 1) = make_deep_copy (TREE_OPERAND (t, 1)); ! 1577: TREE_OPERAND (t, 2) = make_deep_copy (TREE_OPERAND (t, 2)); ! 1578: return t; ! 1579: ! 1580: case SAVE_EXPR: ! 1581: t = copy_node (t); ! 1582: TREE_OPERAND (t, 0) = make_deep_copy (TREE_OPERAND (t, 0)); ! 1583: return t; ! 1584: ! 1585: case MODIFY_EXPR: ! 1586: case PLUS_EXPR: ! 1587: case MINUS_EXPR: ! 1588: case MULT_EXPR: ! 1589: case TRUNC_DIV_EXPR: ! 1590: case TRUNC_MOD_EXPR: ! 1591: case MIN_EXPR: ! 1592: case MAX_EXPR: ! 1593: case LSHIFT_EXPR: ! 1594: case RSHIFT_EXPR: ! 1595: case BIT_IOR_EXPR: ! 1596: case BIT_XOR_EXPR: ! 1597: case BIT_AND_EXPR: ! 1598: case BIT_ANDTC_EXPR: ! 1599: case TRUTH_ANDIF_EXPR: ! 1600: case TRUTH_ORIF_EXPR: ! 1601: case LT_EXPR: ! 1602: case LE_EXPR: ! 1603: case GT_EXPR: ! 1604: case GE_EXPR: ! 1605: case EQ_EXPR: ! 1606: case NE_EXPR: ! 1607: case CEIL_DIV_EXPR: ! 1608: case FLOOR_DIV_EXPR: ! 1609: case ROUND_DIV_EXPR: ! 1610: case CEIL_MOD_EXPR: ! 1611: case FLOOR_MOD_EXPR: ! 1612: case ROUND_MOD_EXPR: ! 1613: case COMPOUND_EXPR: ! 1614: case PREDECREMENT_EXPR: ! 1615: case PREINCREMENT_EXPR: ! 1616: case POSTDECREMENT_EXPR: ! 1617: case POSTINCREMENT_EXPR: ! 1618: case CALL_EXPR: ! 1619: t = copy_node (t); ! 1620: TREE_OPERAND (t, 0) = make_deep_copy (TREE_OPERAND (t, 0)); ! 1621: TREE_OPERAND (t, 1) = make_deep_copy (TREE_OPERAND (t, 1)); ! 1622: return t; ! 1623: ! 1624: case CONVERT_EXPR: ! 1625: case ADDR_EXPR: ! 1626: case INDIRECT_REF: ! 1627: case NEGATE_EXPR: ! 1628: case BIT_NOT_EXPR: ! 1629: case TRUTH_NOT_EXPR: ! 1630: case NOP_EXPR: ! 1631: case COMPONENT_REF: ! 1632: t = copy_node (t); ! 1633: TREE_OPERAND (t, 0) = make_deep_copy (TREE_OPERAND (t, 0)); ! 1634: return t; ! 1635: ! 1636: /* This list is incomplete, but should suffice for now. ! 1637: It is very important that `sorry' does not call ! 1638: `report_error_function'. That could cause an infinite loop. */ ! 1639: default: ! 1640: sorry ("initializer contains unrecognized tree code"); ! 1641: return error_mark_node; ! 1642: ! 1643: } ! 1644: my_friendly_abort (107); ! 1645: /* NOTREACHED */ ! 1646: return NULL_TREE; ! 1647: } ! 1648: ! 1649: /* Assuming T is a node built bottom-up, make it all exist on ! 1650: permanent obstack, if it is not permanent already. */ ! 1651: tree ! 1652: copy_to_permanent (t) ! 1653: tree t; ! 1654: { ! 1655: register struct obstack *ambient_obstack = current_obstack; ! 1656: register struct obstack *ambient_saveable_obstack = saveable_obstack; ! 1657: ! 1658: if (t == NULL_TREE || TREE_PERMANENT (t)) ! 1659: return t; ! 1660: ! 1661: saveable_obstack = &permanent_obstack; ! 1662: current_obstack = saveable_obstack; ! 1663: ! 1664: t = make_deep_copy (t); ! 1665: ! 1666: current_obstack = ambient_obstack; ! 1667: saveable_obstack = ambient_saveable_obstack; ! 1668: ! 1669: return t; ! 1670: } ! 1671: ! 1672: void ! 1673: print_lang_statistics () ! 1674: { ! 1675: extern struct obstack maybepermanent_obstack; ! 1676: print_obstack_statistics ("class_obstack", &class_obstack); ! 1677: print_obstack_statistics ("permanent_obstack", &permanent_obstack); ! 1678: print_obstack_statistics ("maybepermanent_obstack", &maybepermanent_obstack); ! 1679: print_search_statistics (); ! 1680: print_class_statistics (); ! 1681: } ! 1682: ! 1683: /* This is used by the `assert' macro. It is provided in libgcc.a, ! 1684: which `cc' doesn't know how to link. Note that the C++ front-end ! 1685: no longer actually uses the `assert' macro (instead, it calls ! 1686: my_friendly_assert). But all of the back-end files still need this. */ ! 1687: void ! 1688: __eprintf (string, expression, line, filename) ! 1689: #ifdef __STDC__ ! 1690: const char *string; ! 1691: const char *expression; ! 1692: unsigned line; ! 1693: const char *filename; ! 1694: #else ! 1695: char *string; ! 1696: char *expression; ! 1697: unsigned line; ! 1698: char *filename; ! 1699: #endif ! 1700: { ! 1701: fprintf (stderr, string, expression, line, filename); ! 1702: fflush (stderr); ! 1703: abort (); ! 1704: } ! 1705: ! 1706: /* Return, as an INTEGER_CST node, the number of elements for ! 1707: TYPE (which is an ARRAY_TYPE). This counts only elements of the top array. */ ! 1708: ! 1709: tree ! 1710: array_type_nelts_top (type) ! 1711: tree type; ! 1712: { ! 1713: return fold (build (PLUS_EXPR, integer_type_node, ! 1714: array_type_nelts (type), ! 1715: integer_one_node)); ! 1716: } ! 1717: ! 1718: /* Return, as an INTEGER_CST node, the number of elements for ! 1719: TYPE (which is an ARRAY_TYPE). This one is a recursive count of all ! 1720: ARRAY_TYPEs that are clumped together. */ ! 1721: ! 1722: tree ! 1723: array_type_nelts_total (type) ! 1724: tree type; ! 1725: { ! 1726: tree sz = array_type_nelts_top (type); ! 1727: type = TREE_TYPE (type); ! 1728: while (TREE_CODE (type) == ARRAY_TYPE) ! 1729: { ! 1730: tree n = array_type_nelts_top (type); ! 1731: sz = fold (build (MULT_EXPR, integer_type_node, sz, n)); ! 1732: type = TREE_TYPE (type); ! 1733: } ! 1734: return sz; ! 1735: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.