odr_type get_odr_type (tree type, bool insert) { odr_type_d **slot; odr_type val; hashval_t hash; type = TYPE_MAIN_VARIANT (type); gcc_checking_assert (TYPE_MAIN_VARIANT (type) == type); hash = hash_type_name (type); slot = odr_hash.find_slot_with_hash (type, hash, insert ? INSERT : NO_INSERT); if (!slot) return NULL; /* See if we already have entry for type. */ if (*slot) { val = *slot; /* With LTO we need to support multiple tree representation of the same ODR type. */ if (val->type != type) add_type_duplicate (val, type); } else { tree binfo = TYPE_BINFO (type); unsigned int i; val = ggc_alloc_cleared_odr_type_d (); val->type = type; val->bases = vNULL; val->derived_types = vNULL; val->anonymous_namespace = type_in_anonymous_namespace_p (type); *slot = val; for (i = 0; i < BINFO_N_BASE_BINFOS (binfo); i++) /* For now record only polymorphic types. other are pointless for devirtualization and we can not precisely determine ODR equivalency of these during LTO. */ if (polymorphic_type_binfo_p (BINFO_BASE_BINFO (binfo, i))) { odr_type base = get_odr_type (BINFO_TYPE (BINFO_BASE_BINFO (binfo, i)), true); base->derived_types.safe_push (val); val->bases.safe_push (base); } /* First record bases, then add into array so ids are increasing. */ if (odr_types_ptr) val->id = odr_types.length (); vec_safe_push (odr_types_ptr, val); } return val; }
static tree get_pseudo_ti_init (tree type, tree var_desc) { gcc_assert (at_eof); switch (TREE_CODE (type)) { case OFFSET_TYPE: return ptm_initializer (var_desc, type); case POINTER_TYPE: return ptr_initializer (var_desc, type); case ENUMERAL_TYPE: return generic_initializer (var_desc, type); break; case FUNCTION_TYPE: return generic_initializer (var_desc, type); break; case ARRAY_TYPE: return generic_initializer (var_desc, type); break; case UNION_TYPE: case RECORD_TYPE: if (TYPE_PTRMEMFUNC_P (type)) return ptm_initializer (var_desc, type); else if (var_desc == class_desc_type_node) return class_initializer (var_desc, type, NULL_TREE); else if (var_desc == si_class_desc_type_node) { tree base_binfo = BINFO_BASE_BINFO (TYPE_BINFO (type), 0); tree tinfo = get_tinfo_ptr (BINFO_TYPE (base_binfo)); tree base_inits = tree_cons (NULL_TREE, tinfo, NULL_TREE); return class_initializer (var_desc, type, base_inits); } else { int hint = ((CLASSTYPE_REPEATED_BASE_P (type) << 0) | (CLASSTYPE_DIAMOND_SHAPED_P (type) << 1)); tree binfo = TYPE_BINFO (type); int nbases = BINFO_N_BASE_BINFOS (binfo); VEC (tree) *base_accesses = BINFO_BASE_ACCESSES (binfo); tree base_inits = NULL_TREE; int ix; /* Generate the base information initializer. */ for (ix = nbases; ix--;) { tree base_binfo = BINFO_BASE_BINFO (binfo, ix); tree base_init = NULL_TREE; int flags = 0; tree tinfo; tree offset; if (VEC_index (tree, base_accesses, ix) == access_public_node) flags |= 2; tinfo = get_tinfo_ptr (BINFO_TYPE (base_binfo)); if (BINFO_VIRTUAL_P (base_binfo)) { /* We store the vtable offset at which the virtual base offset can be found. */ offset = BINFO_VPTR_FIELD (base_binfo); offset = convert (sizetype, offset); flags |= 1; } else offset = BINFO_OFFSET (base_binfo); /* Combine offset and flags into one field. */ offset = cp_build_binary_op (LSHIFT_EXPR, offset, build_int_cst (NULL_TREE, 8)); offset = cp_build_binary_op (BIT_IOR_EXPR, offset, build_int_cst (NULL_TREE, flags)); base_init = tree_cons (NULL_TREE, offset, base_init); base_init = tree_cons (NULL_TREE, tinfo, base_init); base_init = build_constructor (NULL_TREE, base_init); base_inits = tree_cons (NULL_TREE, base_init, base_inits); } base_inits = build_constructor (NULL_TREE, base_inits); base_inits = tree_cons (NULL_TREE, base_inits, NULL_TREE); /* Prepend the number of bases. */ base_inits = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, nbases), base_inits); /* Prepend the hint flags. */ base_inits = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, hint), base_inits); return class_initializer (var_desc, type, base_inits); } break; default: return generic_initializer (var_desc, type); } }
static tree get_pseudo_ti_desc (tree type) { switch (TREE_CODE (type)) { case OFFSET_TYPE: return ptm_desc_type_node; case POINTER_TYPE: return ptr_desc_type_node; case ENUMERAL_TYPE: return enum_desc_type_node; case FUNCTION_TYPE: return func_desc_type_node; case ARRAY_TYPE: return ary_desc_type_node; case UNION_TYPE: case RECORD_TYPE: if (TYPE_PTRMEMFUNC_P (type)) return ptm_desc_type_node; else if (!COMPLETE_TYPE_P (type)) { if (!at_eof) cxx_incomplete_type_error (NULL_TREE, type); return class_desc_type_node; } else if (!BINFO_N_BASE_BINFOS (TYPE_BINFO (type))) return class_desc_type_node; else { tree binfo = TYPE_BINFO (type); VEC (tree) *base_accesses = BINFO_BASE_ACCESSES (binfo); tree base_binfo = BINFO_BASE_BINFO (binfo, 0); int num_bases = BINFO_N_BASE_BINFOS (binfo); if (num_bases == 1 && VEC_index (tree, base_accesses, 0) == access_public_node && !BINFO_VIRTUAL_P (base_binfo) && integer_zerop (BINFO_OFFSET (base_binfo))) /* single non-virtual public. */ return si_class_desc_type_node; else { tree var_desc; tree array_domain, base_array; if (TREE_VEC_LENGTH (vmi_class_desc_type_node) <= num_bases) { int ix; tree extend = make_tree_vec (num_bases + 5); for (ix = TREE_VEC_LENGTH (vmi_class_desc_type_node); ix--;) TREE_VEC_ELT (extend, ix) = TREE_VEC_ELT (vmi_class_desc_type_node, ix); vmi_class_desc_type_node = extend; } var_desc = TREE_VEC_ELT (vmi_class_desc_type_node, num_bases); if (var_desc) return var_desc; /* Create the array of __base_class_type_info entries. G++ 3.2 allocated an array that had one too many entries, and then filled that extra entries with zeros. */ if (abi_version_at_least (2)) array_domain = build_index_type (size_int (num_bases - 1)); else array_domain = build_index_type (size_int (num_bases)); base_array = build_array_type (base_desc_type_node, array_domain); push_nested_namespace (abi_node); var_desc = create_pseudo_type_info ("__vmi_class_type_info", num_bases, build_decl (FIELD_DECL, NULL_TREE, integer_type_node), build_decl (FIELD_DECL, NULL_TREE, integer_type_node), build_decl (FIELD_DECL, NULL_TREE, base_array), NULL); pop_nested_namespace (abi_node); TREE_VEC_ELT (vmi_class_desc_type_node, num_bases) = var_desc; return var_desc; } } default: return bltn_desc_type_node; } }
static tree merge_types (tree type1, tree type2) { if (type1 == type2) return type1; if (type1 == TYPE_UNKNOWN || type2 == TYPE_UNKNOWN || type1 == TYPE_RETURN_ADDR || type2 == TYPE_RETURN_ADDR) return TYPE_UNKNOWN; if (TREE_CODE (type1) == POINTER_TYPE && TREE_CODE (type2) == POINTER_TYPE) { int depth1, depth2; tree tt1, tt2; /* ptr_type_node is only used for a null reference, which is compatible with any reference type. */ if (type1 == ptr_type_node || type2 == object_ptr_type_node) return type2; if (type2 == ptr_type_node || type1 == object_ptr_type_node) return type1; tt1 = TREE_TYPE (type1); tt2 = TREE_TYPE (type2); /* If tt{1,2} haven't been properly loaded, now is a good time to do it. */ if (!TYPE_SIZE (tt1)) { load_class (tt1, 1); safe_layout_class (tt1); } if (!TYPE_SIZE (tt2)) { load_class (tt2, 1); safe_layout_class (tt2); } if (TYPE_ARRAY_P (tt1) || TYPE_ARRAY_P (tt2)) { if (TYPE_ARRAY_P (tt1) == TYPE_ARRAY_P (tt2)) { tree el_type1 = TYPE_ARRAY_ELEMENT (tt1); tree el_type2 = TYPE_ARRAY_ELEMENT (tt2); tree el_type = NULL_TREE; if (el_type1 == el_type2) el_type = el_type1; else if (TREE_CODE (el_type1) == POINTER_TYPE && TREE_CODE (el_type2) == POINTER_TYPE) el_type = merge_types (el_type1, el_type2); if (el_type != NULL_TREE) { HOST_WIDE_INT len1 = java_array_type_length (tt1); HOST_WIDE_INT len2 = java_array_type_length (tt2); if (len1 != len2) len1 = -1; else if (el_type1 == el_type2) return type1; return promote_type (build_java_array_type (el_type, len1)); } } return object_ptr_type_node; } if (CLASS_INTERFACE (TYPE_NAME (tt1))) { /* FIXME: should see if two interfaces have a common superinterface. */ if (CLASS_INTERFACE (TYPE_NAME (tt2))) { /* This is a kludge, but matches what Sun's verifier does. It can be tricked, but is safe as long as type errors (i.e. interface method calls) are caught at run-time. */ return object_ptr_type_node; } else { if (can_widen_reference_to (tt2, tt1)) return type1; else return object_ptr_type_node; } } else if (CLASS_INTERFACE (TYPE_NAME (tt2))) { if (can_widen_reference_to (tt1, tt2)) return type2; else return object_ptr_type_node; } type1 = tt1; type2 = tt2; depth1 = class_depth (type1); depth2 = class_depth (type2); for ( ; depth1 > depth2; depth1--) type1 = BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (type1), 0)); for ( ; depth2 > depth1; depth2--) type2 = BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (type2), 0)); while (type1 != type2) { type1 = BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (type1), 0)); type2 = BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (type2), 0)); } return promote_type (type1); } if (INTEGRAL_TYPE_P (type1) && INTEGRAL_TYPE_P (type2) && TYPE_PRECISION (type1) <= 32 && TYPE_PRECISION (type2) <= 32) return int_type_node; return TYPE_UNKNOWN; }
static void add_type_duplicate (odr_type val, tree type) { if (!val->types_set) val->types_set = pointer_set_create (); /* See if this duplicate is new. */ if (!pointer_set_insert (val->types_set, type)) { bool merge = true; bool base_mismatch = false; gcc_assert (in_lto_p); vec_safe_push (val->types, type); unsigned int i,j; /* First we compare memory layout. */ if (!types_compatible_p (val->type, type)) { merge = false; if (BINFO_VTABLE (TYPE_BINFO (val->type)) && warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (type)), 0, "type %qD violates one definition rule ", type)) inform (DECL_SOURCE_LOCATION (TYPE_NAME (val->type)), "a type with the same name but different layout is " "defined in another translation unit"); if (cgraph_dump_file) { fprintf (cgraph_dump_file, "ODR violation or merging or ODR type bug?\n"); print_node (cgraph_dump_file, "", val->type, 0); putc ('\n',cgraph_dump_file); print_node (cgraph_dump_file, "", type, 0); putc ('\n',cgraph_dump_file); } } /* Next sanity check that bases are the same. If not, we will end up producing wrong answers. */ for (j = 0, i = 0; i < BINFO_N_BASE_BINFOS (TYPE_BINFO (type)); i++) if (polymorphic_type_binfo_p (BINFO_BASE_BINFO (TYPE_BINFO (type), i))) { odr_type base = get_odr_type (BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (type), i)), true); if (val->bases.length () <= j || val->bases[j] != base) base_mismatch = true; j++; } if (base_mismatch) { merge = false; if (warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (type)), 0, "type %qD violates one definition rule ", type)) inform (DECL_SOURCE_LOCATION (TYPE_NAME (val->type)), "a type with the same name but different bases is " "defined in another translation unit"); if (cgraph_dump_file) { fprintf (cgraph_dump_file, "ODR bse violation or merging bug?\n"); print_node (cgraph_dump_file, "", val->type, 0); putc ('\n',cgraph_dump_file); print_node (cgraph_dump_file, "", type, 0); putc ('\n',cgraph_dump_file); } } /* Regularize things a little. During LTO same types may come with different BINFOs. Either because their virtual table was not merged by tree merging and only later at decl merging or because one type comes with external vtable, while other with internal. We want to merge equivalent binfos to conserve memory and streaming overhead. The external vtables are more harmful: they contain references to external declarations of methods that may be defined in the merged LTO unit. For this reason we absolutely need to remove them and replace by internal variants. Not doing so will lead to incomplete answers from possible_polymorphic_call_targets. */ if (!flag_ltrans && merge) { tree master_binfo = TYPE_BINFO (val->type); tree v1 = BINFO_VTABLE (master_binfo); tree v2 = BINFO_VTABLE (TYPE_BINFO (type)); if (TREE_CODE (v1) == POINTER_PLUS_EXPR) { gcc_assert (TREE_CODE (v2) == POINTER_PLUS_EXPR && operand_equal_p (TREE_OPERAND (v1, 1), TREE_OPERAND (v2, 1), 0)); v1 = TREE_OPERAND (TREE_OPERAND (v1, 0), 0); v2 = TREE_OPERAND (TREE_OPERAND (v2, 0), 0); } gcc_assert (DECL_ASSEMBLER_NAME (v1) == DECL_ASSEMBLER_NAME (v2)); if (DECL_EXTERNAL (v1) && !DECL_EXTERNAL (v2)) { unsigned int i; TYPE_BINFO (val->type) = TYPE_BINFO (type); for (i = 0; i < val->types->length (); i++) { if (TYPE_BINFO ((*val->types)[i]) == master_binfo) TYPE_BINFO ((*val->types)[i]) = TYPE_BINFO (type); } } else TYPE_BINFO (type) = master_binfo; } } }