hashval_t hash_type_name (tree t) { gcc_checking_assert (TYPE_MAIN_VARIANT (t) == t); /* If not in LTO, all main variants are unique, so we can do pointer hash. */ if (!in_lto_p) return htab_hash_pointer (t); /* Anonymous types are unique. */ if (type_in_anonymous_namespace_p (t)) return htab_hash_pointer (t); /* For polymorphic types, we can simply hash the virtual table. */ if (TYPE_BINFO (t) && BINFO_VTABLE (TYPE_BINFO (t))) { tree v = BINFO_VTABLE (TYPE_BINFO (t)); hashval_t hash = 0; if (TREE_CODE (v) == POINTER_PLUS_EXPR) { hash = TREE_INT_CST_LOW (TREE_OPERAND (v, 1)); v = TREE_OPERAND (TREE_OPERAND (v, 0), 0); } v = DECL_ASSEMBLER_NAME (v); hash = iterative_hash_hashval_t (hash, htab_hash_pointer (v)); return hash; } /* Rest is not implemented yet. */ gcc_unreachable (); }
/* Search in the interfaces of SEARCHED_CLASS and its superinterfaces for a method matching METHOD_NAME and signature SIGNATURE. A private helper for lookup_do. */ static tree find_method_in_interfaces (tree searched_class, int flags, tree method_name, tree signature, tree (*signature_builder) (tree)) { int i; tree binfo, base_binfo; for (binfo = TYPE_BINFO (searched_class), i = 1; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) { tree iclass = BINFO_TYPE (base_binfo); tree method; /* If the superinterface hasn't been loaded yet, do so now. */ if (!CLASS_LOADED_P (iclass)) load_class (iclass, 1); /* First, we look in ICLASS. If that doesn't work we'll recursively look through all its superinterfaces. */ method = shallow_find_method (iclass, flags, method_name, signature, signature_builder); if (method != NULL_TREE) return method; method = find_method_in_interfaces (iclass, flags, method_name, signature, signature_builder); if (method != NULL_TREE) return method; } return NULL_TREE; }
void add_friend (tree type, tree decl, bool complain) { tree typedecl; tree list; tree name; tree ctx; if (decl == error_mark_node) return; typedecl = TYPE_MAIN_DECL (type); list = DECL_FRIENDLIST (typedecl); name = DECL_NAME (decl); type = TREE_TYPE (typedecl); while (list) { if (name == FRIEND_NAME (list)) { tree friends = FRIEND_DECLS (list); for (; friends ; friends = TREE_CHAIN (friends)) { if (decl == TREE_VALUE (friends)) { if (complain) warning (OPT_Wredundant_decls, "%qD is already a friend of class %qT", decl, type); return; } } maybe_add_class_template_decl_list (type, decl, /*friend_p=*/1); TREE_VALUE (list) = tree_cons (NULL_TREE, decl, TREE_VALUE (list)); return; } list = TREE_CHAIN (list); } ctx = DECL_CONTEXT (decl); if (ctx && CLASS_TYPE_P (ctx) && !uses_template_parms (ctx)) perform_or_defer_access_check (TYPE_BINFO (ctx), decl, decl, tf_warning_or_error); maybe_add_class_template_decl_list (type, decl, /*friend_p=*/1); DECL_FRIENDLIST (typedecl) = tree_cons (DECL_NAME (decl), build_tree_list (NULL_TREE, decl), DECL_FRIENDLIST (typedecl)); if (!uses_template_parms (type)) DECL_BEFRIENDING_CLASSES (decl) = tree_cons (NULL_TREE, type, DECL_BEFRIENDING_CLASSES (decl)); }
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 bool ok_to_generate_alias_set_for_type (tree t) { if (TYPE_PTRMEMFUNC_P (t)) return true; if (AGGREGATE_TYPE_P (t)) { if ((TREE_CODE (t) == RECORD_TYPE) || (TREE_CODE (t) == UNION_TYPE)) { tree fields; /* Backend-created structs are safe. */ if (! CLASS_TYPE_P (t)) return true; /* PODs are safe. */ if (! CLASSTYPE_NON_POD_P(t)) return true; /* Classes with virtual baseclasses are not. */ if (TYPE_USES_VIRTUAL_BASECLASSES (t)) return false; /* Recursively check the base classes. */ if (TYPE_BINFO (t) != NULL && TYPE_BINFO_BASETYPES (t) != NULL) { int i; for (i = 0; i < TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (t)); i++) { tree binfo = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (t), i); if (!ok_to_generate_alias_set_for_type (BINFO_TYPE (binfo))) return false; } } /* Check all the fields. */ for (fields = TYPE_FIELDS (t); fields; fields = TREE_CHAIN (fields)) { if (TREE_CODE (fields) != FIELD_DECL) continue; if (! ok_to_generate_alias_set_for_type (TREE_TYPE (fields))) return false; } return true; } else if (TREE_CODE (t) == ARRAY_TYPE) return ok_to_generate_alias_set_for_type (TREE_TYPE (t)); else /* This should never happen, we dealt with all the aggregate types that can appear in C++ above. */ abort (); } else return true; }
void cp_ubsan_maybe_initialize_vtbl_ptrs (tree addr) { if (!cp_ubsan_instrument_vptr_p (NULL_TREE)) return; tree type = TREE_TYPE (TREE_TYPE (addr)); tree list = build_tree_list (type, addr); /* Walk through the hierarchy, initializing the vptr in each base class to NULL. */ dfs_walk_once (TYPE_BINFO (type), cp_ubsan_dfs_initialize_vtbl_ptrs, NULL, list); }
static tree synthesize_exception_spec (tree type, tree (*extractor) (tree, void*), void *client) { tree raises = empty_except_spec; tree fields = TYPE_FIELDS (type); tree binfo, base_binfo; int i; for (binfo = TYPE_BINFO (type), i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) { tree fn = (*extractor) (BINFO_TYPE (base_binfo), client); if (fn) { tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)); raises = merge_exception_specifiers (raises, fn_raises); } } for (; fields; fields = TREE_CHAIN (fields)) { tree type = TREE_TYPE (fields); tree fn; if (TREE_CODE (fields) != FIELD_DECL || DECL_ARTIFICIAL (fields)) continue; while (TREE_CODE (type) == ARRAY_TYPE) type = TREE_TYPE (type); if (!CLASS_TYPE_P (type)) continue; fn = (*extractor) (type, client); if (fn) { tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)); raises = merge_exception_specifiers (raises, fn_raises); } } return raises; }
void cp_ubsan_maybe_initialize_vtbl_ptrs (tree addr) { if (!cp_ubsan_instrument_vptr_p (NULL_TREE)) return; tree type = TREE_TYPE (TREE_TYPE (addr)); tree list = build_tree_list (type, addr); /* We cannot rely on the vtable being set up. We have to indirect via the vtt_parm. */ int save_in_base_initializer = in_base_initializer; in_base_initializer = 1; /* Walk through the hierarchy, initializing the vptr in each base class to NULL. */ dfs_walk_once (TYPE_BINFO (type), cp_ubsan_dfs_initialize_vtbl_ptrs, NULL, list); in_base_initializer = save_in_base_initializer; }
static void possible_polymorphic_call_targets_1 (vec <cgraph_node *> &nodes, pointer_set_t *inserted, pointer_set_t *matched_vtables, tree otr_type, odr_type type, HOST_WIDE_INT otr_token) { tree binfo = TYPE_BINFO (type->type); unsigned int i; record_binfo (nodes, binfo, otr_type, binfo, otr_token, inserted, matched_vtables, type->anonymous_namespace); for (i = 0; i < type->derived_types.length(); i++) possible_polymorphic_call_targets_1 (nodes, inserted, matched_vtables, otr_type, type->derived_types[i], otr_token); }
static void write_ts_type_non_common_tree_pointers (struct output_block *ob, tree expr, bool ref_p) { if (TREE_CODE (expr) == ENUMERAL_TYPE) stream_write_tree (ob, TYPE_VALUES (expr), ref_p); else if (TREE_CODE (expr) == ARRAY_TYPE) stream_write_tree (ob, TYPE_DOMAIN (expr), ref_p); else if (RECORD_OR_UNION_TYPE_P (expr)) streamer_write_chain (ob, TYPE_FIELDS (expr), ref_p); else if (TREE_CODE (expr) == FUNCTION_TYPE || TREE_CODE (expr) == METHOD_TYPE) stream_write_tree (ob, TYPE_ARG_TYPES (expr), ref_p); if (!POINTER_TYPE_P (expr)) stream_write_tree (ob, TYPE_MINVAL (expr), ref_p); stream_write_tree (ob, TYPE_MAXVAL (expr), ref_p); if (RECORD_OR_UNION_TYPE_P (expr)) stream_write_tree (ob, TYPE_BINFO (expr), ref_p); }
static void lto_input_ts_type_non_common_tree_pointers (struct lto_input_block *ib, struct data_in *data_in, tree expr) { if (TREE_CODE (expr) == ENUMERAL_TYPE) TYPE_VALUES (expr) = stream_read_tree (ib, data_in); else if (TREE_CODE (expr) == ARRAY_TYPE) TYPE_DOMAIN (expr) = stream_read_tree (ib, data_in); else if (RECORD_OR_UNION_TYPE_P (expr)) TYPE_FIELDS (expr) = streamer_read_chain (ib, data_in); else if (TREE_CODE (expr) == FUNCTION_TYPE || TREE_CODE (expr) == METHOD_TYPE) TYPE_ARG_TYPES (expr) = stream_read_tree (ib, data_in); if (!POINTER_TYPE_P (expr)) TYPE_MINVAL (expr) = stream_read_tree (ib, data_in); TYPE_MAXVAL (expr) = stream_read_tree (ib, data_in); if (RECORD_OR_UNION_TYPE_P (expr)) TYPE_BINFO (expr) = stream_read_tree (ib, data_in); }
static void dequeue_and_dump (dump_info_p di) { dump_queue_p dq; splay_tree_node stn; dump_node_info_p dni; tree t; unsigned int index; enum tree_code code; enum tree_code_class code_class; const char* code_name; /* Get the next node from the queue. */ dq = di->queue; stn = dq->node; t = (tree) stn->key; dni = (dump_node_info_p) stn->value; index = dni->index; /* Remove the node from the queue, and put it on the free list. */ di->queue = dq->next; if (!di->queue) di->queue_end = 0; dq->next = di->free_list; di->free_list = dq; /* Print the node index. */ dump_index (di, index); /* And the type of node this is. */ if (dni->binfo_p) code_name = "binfo"; else code_name = tree_code_name[(int) TREE_CODE (t)]; fprintf (di->stream, "%-16s ", code_name); di->column = 25; /* Figure out what kind of node this is. */ code = TREE_CODE (t); code_class = TREE_CODE_CLASS (code); /* Although BINFOs are TREE_VECs, we dump them specially so as to be more informative. */ if (dni->binfo_p) { unsigned ix; tree base; VEC(tree,gc) *accesses = BINFO_BASE_ACCESSES (t); dump_child ("type", BINFO_TYPE (t)); if (BINFO_VIRTUAL_P (t)) dump_string_field (di, "spec", "virt"); dump_int (di, "bases", BINFO_N_BASE_BINFOS (t)); for (ix = 0; BINFO_BASE_ITERATE (t, ix, base); ix++) { tree access = (accesses ? VEC_index (tree, accesses, ix) : access_public_node); const char *string = NULL; if (access == access_public_node) string = "pub"; else if (access == access_protected_node) string = "prot"; else if (access == access_private_node) string = "priv"; else gcc_unreachable (); dump_string_field (di, "accs", string); queue_and_dump_index (di, "binf", base, DUMP_BINFO); } goto done; } /* We can knock off a bunch of expression nodes in exactly the same way. */ if (IS_EXPR_CODE_CLASS (code_class)) { /* If we're dumping children, dump them now. */ queue_and_dump_type (di, t); switch (code_class) { case tcc_unary: dump_child ("op 0", TREE_OPERAND (t, 0)); break; case tcc_binary: case tcc_comparison: dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); break; case tcc_expression: case tcc_reference: case tcc_statement: case tcc_vl_exp: /* These nodes are handled explicitly below. */ break; default: gcc_unreachable (); } } else if (DECL_P (t)) { expanded_location xloc; /* All declarations have names. */ if (DECL_NAME (t)) dump_child ("name", DECL_NAME (t)); if (DECL_ASSEMBLER_NAME_SET_P (t) && DECL_ASSEMBLER_NAME (t) != DECL_NAME (t)) dump_child ("mngl", DECL_ASSEMBLER_NAME (t)); if (DECL_ABSTRACT_ORIGIN (t)) dump_child ("orig", DECL_ABSTRACT_ORIGIN (t)); /* And types. */ queue_and_dump_type (di, t); dump_child ("scpe", DECL_CONTEXT (t)); /* And a source position. */ xloc = expand_location (DECL_SOURCE_LOCATION (t)); if (xloc.file) { const char *filename = lbasename (xloc.file); dump_maybe_newline (di); fprintf (di->stream, "srcp: %s:%-6d ", filename, xloc.line); di->column += 6 + strlen (filename) + 8; } /* And any declaration can be compiler-generated. */ if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_DECL_COMMON) && DECL_ARTIFICIAL (t)) dump_string_field (di, "note", "artificial"); if (DECL_CHAIN (t) && !dump_flag (di, TDF_SLIM, NULL)) dump_child ("chain", DECL_CHAIN (t)); } else if (code_class == tcc_type) { /* All types have qualifiers. */ int quals = lang_hooks.tree_dump.type_quals (t); if (quals != TYPE_UNQUALIFIED) { fprintf (di->stream, "qual: %c%c%c ", (quals & TYPE_QUAL_CONST) ? 'c' : ' ', (quals & TYPE_QUAL_VOLATILE) ? 'v' : ' ', (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' '); di->column += 14; } /* All types have associated declarations. */ dump_child ("name", TYPE_NAME (t)); /* All types have a main variant. */ if (TYPE_MAIN_VARIANT (t) != t) dump_child ("unql", TYPE_MAIN_VARIANT (t)); /* And sizes. */ dump_child ("size", TYPE_SIZE (t)); /* All types have alignments. */ dump_int (di, "algn", TYPE_ALIGN (t)); } else if (code_class == tcc_constant) /* All constants can have types. */ queue_and_dump_type (di, t); /* Give the language-specific code a chance to print something. If it's completely taken care of things, don't bother printing anything more ourselves. */ if (lang_hooks.tree_dump.dump_tree (di, t)) goto done; /* Now handle the various kinds of nodes. */ switch (code) { int i; case IDENTIFIER_NODE: dump_string_field (di, "strg", IDENTIFIER_POINTER (t)); dump_int (di, "lngt", IDENTIFIER_LENGTH (t)); break; case TREE_LIST: dump_child ("purp", TREE_PURPOSE (t)); dump_child ("valu", TREE_VALUE (t)); dump_child ("chan", TREE_CHAIN (t)); break; case STATEMENT_LIST: { tree_stmt_iterator it; for (i = 0, it = tsi_start (t); !tsi_end_p (it); tsi_next (&it), i++) { char buffer[32]; sprintf (buffer, "%u", i); dump_child (buffer, tsi_stmt (it)); } } break; case TREE_VEC: dump_int (di, "lngt", TREE_VEC_LENGTH (t)); for (i = 0; i < TREE_VEC_LENGTH (t); ++i) { char buffer[32]; sprintf (buffer, "%u", i); dump_child (buffer, TREE_VEC_ELT (t, i)); } break; case INTEGER_TYPE: case ENUMERAL_TYPE: dump_int (di, "prec", TYPE_PRECISION (t)); dump_string_field (di, "sign", TYPE_UNSIGNED (t) ? "unsigned": "signed"); dump_child ("min", TYPE_MIN_VALUE (t)); dump_child ("max", TYPE_MAX_VALUE (t)); if (code == ENUMERAL_TYPE) dump_child ("csts", TYPE_VALUES (t)); break; case REAL_TYPE: dump_int (di, "prec", TYPE_PRECISION (t)); break; case FIXED_POINT_TYPE: dump_int (di, "prec", TYPE_PRECISION (t)); dump_string_field (di, "sign", TYPE_UNSIGNED (t) ? "unsigned": "signed"); dump_string_field (di, "saturating", TYPE_SATURATING (t) ? "saturating": "non-saturating"); break; case POINTER_TYPE: dump_child ("ptd", TREE_TYPE (t)); break; case REFERENCE_TYPE: dump_child ("refd", TREE_TYPE (t)); break; case METHOD_TYPE: dump_child ("clas", TYPE_METHOD_BASETYPE (t)); /* Fall through. */ case FUNCTION_TYPE: dump_child ("retn", TREE_TYPE (t)); dump_child ("prms", TYPE_ARG_TYPES (t)); break; case ARRAY_TYPE: dump_child ("elts", TREE_TYPE (t)); dump_child ("domn", TYPE_DOMAIN (t)); break; case RECORD_TYPE: case UNION_TYPE: if (TREE_CODE (t) == RECORD_TYPE) dump_string_field (di, "tag", "struct"); else dump_string_field (di, "tag", "union"); dump_child ("flds", TYPE_FIELDS (t)); dump_child ("fncs", TYPE_METHODS (t)); queue_and_dump_index (di, "binf", TYPE_BINFO (t), DUMP_BINFO); break; case CONST_DECL: dump_child ("cnst", DECL_INITIAL (t)); break; case DEBUG_EXPR_DECL: dump_int (di, "-uid", DEBUG_TEMP_UID (t)); /* Fall through. */ case VAR_DECL: case PARM_DECL: case FIELD_DECL: case RESULT_DECL: if (TREE_CODE (t) == PARM_DECL) dump_child ("argt", DECL_ARG_TYPE (t)); else dump_child ("init", DECL_INITIAL (t)); dump_child ("size", DECL_SIZE (t)); dump_int (di, "algn", DECL_ALIGN (t)); if (TREE_CODE (t) == FIELD_DECL) { if (DECL_FIELD_OFFSET (t)) dump_child ("bpos", bit_position (t)); } else if (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == PARM_DECL) { dump_int (di, "used", TREE_USED (t)); if (DECL_REGISTER (t)) dump_string_field (di, "spec", "register"); } break; case FUNCTION_DECL: dump_child ("args", DECL_ARGUMENTS (t)); if (DECL_EXTERNAL (t)) dump_string_field (di, "body", "undefined"); if (TREE_PUBLIC (t)) dump_string_field (di, "link", "extern"); else dump_string_field (di, "link", "static"); if (DECL_SAVED_TREE (t) && !dump_flag (di, TDF_SLIM, t)) dump_child ("body", DECL_SAVED_TREE (t)); break; case INTEGER_CST: if (TREE_INT_CST_HIGH (t)) dump_int (di, "high", TREE_INT_CST_HIGH (t)); dump_int (di, "low", TREE_INT_CST_LOW (t)); break; case STRING_CST: fprintf (di->stream, "strg: %-7s ", TREE_STRING_POINTER (t)); dump_int (di, "lngt", TREE_STRING_LENGTH (t)); break; case REAL_CST: dump_real (di, "valu", TREE_REAL_CST_PTR (t)); break; case FIXED_CST: dump_fixed (di, "valu", TREE_FIXED_CST_PTR (t)); break; case TRUTH_NOT_EXPR: case ADDR_EXPR: case INDIRECT_REF: case CLEANUP_POINT_EXPR: case SAVE_EXPR: case REALPART_EXPR: case IMAGPART_EXPR: /* These nodes are unary, but do not have code class `1'. */ dump_child ("op 0", TREE_OPERAND (t, 0)); break; case TRUTH_ANDIF_EXPR: case TRUTH_ORIF_EXPR: case INIT_EXPR: case MODIFY_EXPR: case COMPOUND_EXPR: case PREDECREMENT_EXPR: case PREINCREMENT_EXPR: case POSTDECREMENT_EXPR: case POSTINCREMENT_EXPR: /* These nodes are binary, but do not have code class `2'. */ dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); break; case COMPONENT_REF: dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); dump_child ("op 2", TREE_OPERAND (t, 2)); break; case ARRAY_REF: case ARRAY_RANGE_REF: dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); dump_child ("op 2", TREE_OPERAND (t, 2)); dump_child ("op 3", TREE_OPERAND (t, 3)); break; case COND_EXPR: dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); dump_child ("op 2", TREE_OPERAND (t, 2)); break; case TRY_FINALLY_EXPR: dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); break; case CALL_EXPR: { int i = 0; tree arg; call_expr_arg_iterator iter; dump_child ("fn", CALL_EXPR_FN (t)); FOR_EACH_CALL_EXPR_ARG (arg, iter, t) { char buffer[32]; sprintf (buffer, "%u", i); dump_child (buffer, arg); i++; } } break; case CONSTRUCTOR: { unsigned HOST_WIDE_INT cnt; tree index, value; dump_int (di, "lngt", VEC_length (constructor_elt, CONSTRUCTOR_ELTS (t))); FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), cnt, index, value) { dump_child ("idx", index); dump_child ("val", value); } }
tree ocp_convert (tree type, tree expr, int convtype, int flags) { tree e = expr; enum tree_code code = TREE_CODE (type); if (error_operand_p (e) || type == error_mark_node) return error_mark_node; complete_type (type); complete_type (TREE_TYPE (expr)); e = decl_constant_value (e); if (IS_AGGR_TYPE (type) && (convtype & CONV_FORCE_TEMP) /* Some internal structures (vtable_entry_type, sigtbl_ptr_type) don't go through finish_struct, so they don't have the synthesized constructors. So don't force a temporary. */ && TYPE_HAS_CONSTRUCTOR (type)) /* We need a new temporary; don't take this shortcut. */; else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (e))) { if (same_type_p (type, TREE_TYPE (e))) /* The call to fold will not always remove the NOP_EXPR as might be expected, since if one of the types is a typedef; the comparison in fold is just equality of pointers, not a call to comptypes. We don't call fold in this case because that can result in infinite recursion; fold will call convert, which will call ocp_convert, etc. */ return e; /* For complex data types, we need to perform componentwise conversion. */ else if (TREE_CODE (type) == COMPLEX_TYPE) return fold (convert_to_complex (type, e)); else if (TREE_CODE (e) == TARGET_EXPR) { /* Don't build a NOP_EXPR of class type. Instead, change the type of the temporary. Only allow this for cv-qual changes, though. */ if (!same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (e)), TYPE_MAIN_VARIANT (type))) abort (); TREE_TYPE (e) = TREE_TYPE (TARGET_EXPR_SLOT (e)) = type; return e; } else if (TREE_ADDRESSABLE (type)) /* We shouldn't be treating objects of ADDRESSABLE type as rvalues. */ abort (); else return fold (build1 (NOP_EXPR, type, e)); } if (code == VOID_TYPE && (convtype & CONV_STATIC)) { e = convert_to_void (e, /*implicit=*/NULL); return e; } if (INTEGRAL_CODE_P (code)) { tree intype = TREE_TYPE (e); /* enum = enum, enum = int, enum = float, (enum)pointer are all errors. */ if (TREE_CODE (type) == ENUMERAL_TYPE && ((ARITHMETIC_TYPE_P (intype) && ! (convtype & CONV_STATIC)) || (TREE_CODE (intype) == POINTER_TYPE))) { pedwarn ("conversion from `%#T' to `%#T'", intype, type); if (flag_pedantic_errors) return error_mark_node; } if (IS_AGGR_TYPE (intype)) { tree rval; rval = build_type_conversion (type, e); if (rval) return rval; if (flags & LOOKUP_COMPLAIN) error ("`%#T' used where a `%T' was expected", intype, type); if (flags & LOOKUP_SPECULATIVELY) return NULL_TREE; return error_mark_node; } if (code == BOOLEAN_TYPE) return cp_truthvalue_conversion (e); return fold (convert_to_integer (type, e)); } if (POINTER_TYPE_P (type) || TYPE_PTR_TO_MEMBER_P (type)) return fold (cp_convert_to_pointer (type, e, false)); if (code == VECTOR_TYPE) return fold (convert_to_vector (type, e)); if (code == REAL_TYPE || code == COMPLEX_TYPE) { if (IS_AGGR_TYPE (TREE_TYPE (e))) { tree rval; rval = build_type_conversion (type, e); if (rval) return rval; else if (flags & LOOKUP_COMPLAIN) error ("`%#T' used where a floating point value was expected", TREE_TYPE (e)); } if (code == REAL_TYPE) return fold (convert_to_real (type, e)); else if (code == COMPLEX_TYPE) return fold (convert_to_complex (type, e)); } /* New C++ semantics: since assignment is now based on memberwise copying, if the rhs type is derived from the lhs type, then we may still do a conversion. */ if (IS_AGGR_TYPE_CODE (code)) { tree dtype = TREE_TYPE (e); tree ctor = NULL_TREE; dtype = TYPE_MAIN_VARIANT (dtype); /* Conversion between aggregate types. New C++ semantics allow objects of derived type to be cast to objects of base type. Old semantics only allowed this between pointers. There may be some ambiguity between using a constructor vs. using a type conversion operator when both apply. */ ctor = e; if (abstract_virtuals_error (NULL_TREE, type)) return error_mark_node; if ((flags & LOOKUP_ONLYCONVERTING) && ! (IS_AGGR_TYPE (dtype) && DERIVED_FROM_P (type, dtype))) /* For copy-initialization, first we create a temp of the proper type with a user-defined conversion sequence, then we direct-initialize the target with the temp (see [dcl.init]). */ ctor = build_user_type_conversion (type, ctor, flags); else ctor = build_special_member_call (NULL_TREE, complete_ctor_identifier, build_tree_list (NULL_TREE, ctor), TYPE_BINFO (type), flags); if (ctor) return build_cplus_new (type, ctor); } if (flags & LOOKUP_COMPLAIN) error ("conversion from `%T' to non-scalar type `%T' requested", TREE_TYPE (expr), type); if (flags & LOOKUP_SPECULATIVELY) return NULL_TREE; return error_mark_node; }
static void sdbout_one_type (tree type) { if (current_function_decl != NULL_TREE && DECL_SECTION_NAME (current_function_decl) != NULL_TREE) ; /* Don't change section amid function. */ else switch_to_section (text_section); switch (TREE_CODE (type)) { case RECORD_TYPE: case UNION_TYPE: case QUAL_UNION_TYPE: case ENUMERAL_TYPE: type = TYPE_MAIN_VARIANT (type); /* Don't output a type twice. */ if (TREE_ASM_WRITTEN (type)) /* James said test TREE_ASM_BEING_WRITTEN here. */ return; /* Output nothing if type is not yet defined. */ if (!COMPLETE_TYPE_P (type)) return; TREE_ASM_WRITTEN (type) = 1; /* This is reputed to cause trouble with the following case, but perhaps checking TYPE_SIZE above will fix it. */ /* Here is a testcase: struct foo { struct badstr *bbb; } forwardref; typedef struct intermediate { int aaaa; } intermediate_ref; typedef struct badstr { int ccccc; } badtype; */ /* This change, which ought to make better output, used to make the COFF assembler unhappy. Changes involving KNOWN_TYPE_TAG may fix the problem. */ /* Before really doing anything, output types we want to refer to. */ /* Note that in version 1 the following two lines are not used if forward references are in use. */ if (TREE_CODE (type) != ENUMERAL_TYPE) sdbout_field_types (type); /* Output a structure type. */ { int size = int_size_in_bytes (type); int member_scl = 0; tree tem; /* Record the type tag, but not in its permanent place just yet. */ sdbout_record_type_name (type); PUT_SDB_DEF (KNOWN_TYPE_TAG (type)); switch (TREE_CODE (type)) { case UNION_TYPE: case QUAL_UNION_TYPE: PUT_SDB_SCL (C_UNTAG); PUT_SDB_TYPE (T_UNION); member_scl = C_MOU; break; case RECORD_TYPE: PUT_SDB_SCL (C_STRTAG); PUT_SDB_TYPE (T_STRUCT); member_scl = C_MOS; break; case ENUMERAL_TYPE: PUT_SDB_SCL (C_ENTAG); PUT_SDB_TYPE (T_ENUM); member_scl = C_MOE; break; default: break; } PUT_SDB_SIZE (size); PUT_SDB_ENDEF; /* Print out the base class information with fields named after the types they hold. */ /* This is only relevant to aggregate types. TYPE_BINFO is used for other purposes in an ENUMERAL_TYPE, so we must exclude that case. */ if (TREE_CODE (type) != ENUMERAL_TYPE && TYPE_BINFO (type)) { int i; tree binfo, child; for (binfo = TYPE_BINFO (type), i = 0; BINFO_BASE_ITERATE (binfo, i, child); i++) { tree child_type = BINFO_TYPE (child); tree child_type_name; if (TYPE_NAME (child_type) == 0) continue; if (TREE_CODE (TYPE_NAME (child_type)) == IDENTIFIER_NODE) child_type_name = TYPE_NAME (child_type); else if (TREE_CODE (TYPE_NAME (child_type)) == TYPE_DECL) { child_type_name = DECL_NAME (TYPE_NAME (child_type)); if (child_type_name && template_name_p (child_type_name)) child_type_name = DECL_ASSEMBLER_NAME (TYPE_NAME (child_type)); } else continue; PUT_SDB_DEF (IDENTIFIER_POINTER (child_type_name)); PUT_SDB_INT_VAL (tree_low_cst (BINFO_OFFSET (child), 0)); PUT_SDB_SCL (member_scl); sdbout_type (BINFO_TYPE (child)); PUT_SDB_ENDEF; } } /* Output the individual fields. */ if (TREE_CODE (type) == ENUMERAL_TYPE) { for (tem = TYPE_VALUES (type); tem; tem = TREE_CHAIN (tem)) { tree value = TREE_VALUE (tem); if (TREE_CODE (value) == CONST_DECL) value = DECL_INITIAL (value); if (host_integerp (value, 0)) { PUT_SDB_DEF (IDENTIFIER_POINTER (TREE_PURPOSE (tem))); PUT_SDB_INT_VAL (tree_low_cst (value, 0)); PUT_SDB_SCL (C_MOE); PUT_SDB_TYPE (T_MOE); PUT_SDB_ENDEF; } } } else /* record or union type */ for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem)) /* Output the name, type, position (in bits), size (in bits) of each field. */ /* Omit here the nameless fields that are used to skip bits. Also omit fields with variable size or position. Also omit non FIELD_DECL nodes that GNU C++ may put here. */ if (TREE_CODE (tem) == FIELD_DECL && DECL_NAME (tem) && DECL_SIZE (tem) && host_integerp (DECL_SIZE (tem), 1) && host_integerp (bit_position (tem), 0)) { const char *name; name = IDENTIFIER_POINTER (DECL_NAME (tem)); PUT_SDB_DEF (name); if (DECL_BIT_FIELD_TYPE (tem)) { PUT_SDB_INT_VAL (int_bit_position (tem)); PUT_SDB_SCL (C_FIELD); sdbout_type (DECL_BIT_FIELD_TYPE (tem)); PUT_SDB_SIZE (tree_low_cst (DECL_SIZE (tem), 1)); } else { PUT_SDB_INT_VAL (int_bit_position (tem) / BITS_PER_UNIT); PUT_SDB_SCL (member_scl); sdbout_type (TREE_TYPE (tem)); } PUT_SDB_ENDEF; } /* Output end of a structure,union, or enumeral definition. */ PUT_SDB_PLAIN_DEF ("eos"); PUT_SDB_INT_VAL (size); PUT_SDB_SCL (C_EOS); PUT_SDB_TAG (KNOWN_TYPE_TAG (type)); PUT_SDB_SIZE (size); PUT_SDB_ENDEF; break; } default: break; } }
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 inline bool polymorphic_type_binfo_p (tree binfo) { /* See if BINFO's type has an virtual table associtated with it. */ return BINFO_VTABLE (TYPE_BINFO (BINFO_TYPE (binfo))); }
bool cp_dump_tree (void* dump_info, tree t) { enum tree_code code; dump_info_p di = (dump_info_p) dump_info; /* Figure out what kind of node this is. */ code = TREE_CODE (t); if (DECL_P (t)) { if (DECL_LANG_SPECIFIC (t) && DECL_LANGUAGE (t) != lang_cplusplus) dump_string (di, language_to_string (DECL_LANGUAGE (t))); } switch (code) { case IDENTIFIER_NODE: if (IDENTIFIER_OPNAME_P (t)) { dump_string (di, "operator"); return true; } else if (IDENTIFIER_TYPENAME_P (t)) { dump_child ("tynm", TREE_TYPE (t)); return true; } break; case OFFSET_TYPE: dump_string (di, "ptrmem"); dump_child ("ptd", TYPE_PTRMEM_POINTED_TO_TYPE (t)); dump_child ("cls", TYPE_PTRMEM_CLASS_TYPE (t)); return true; case RECORD_TYPE: if (TYPE_PTRMEMFUNC_P (t)) { dump_string (di, "ptrmem"); dump_child ("ptd", TYPE_PTRMEM_POINTED_TO_TYPE (t)); dump_child ("cls", TYPE_PTRMEM_CLASS_TYPE (t)); return true; } /* Fall through. */ case UNION_TYPE: /* Is it a type used as a base? */ if (TYPE_CONTEXT (t) && TREE_CODE (TYPE_CONTEXT (t)) == TREE_CODE (t) && CLASSTYPE_AS_BASE (TYPE_CONTEXT (t)) == t) { dump_child ("bfld", TYPE_CONTEXT (t)); return true; } if (! IS_AGGR_TYPE (t)) break; dump_child ("vfld", TYPE_VFIELD (t)); if (CLASSTYPE_TEMPLATE_SPECIALIZATION(t)) dump_string(di, "spec"); if (!dump_flag (di, TDF_SLIM, t) && TYPE_BINFO (t)) { int i; tree binfo; tree base_binfo; for (binfo = TYPE_BINFO (t), i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i) { dump_child ("base", BINFO_TYPE (base_binfo)); if (BINFO_VIRTUAL_P (base_binfo)) dump_string (di, "virtual"); dump_access (di, base_binfo); } } break; case FIELD_DECL: dump_access (di, t); if (DECL_MUTABLE_P (t)) dump_string(di, "mutable"); break; case VAR_DECL: if (TREE_CODE (CP_DECL_CONTEXT (t)) == RECORD_TYPE) dump_access (di, t); if (TREE_STATIC (t) && !TREE_PUBLIC (t)) dump_string (di, "static"); break; case FUNCTION_DECL: if (!DECL_THUNK_P (t)) { if (DECL_OVERLOADED_OPERATOR_P (t)) { dump_string (di, "operator"); dump_op (di, t); } if (DECL_FUNCTION_MEMBER_P (t)) { dump_string (di, "member"); dump_access (di, t); } if (DECL_PURE_VIRTUAL_P (t)) dump_string (di, "pure"); if (DECL_VIRTUAL_P (t)) dump_string (di, "virtual"); if (DECL_CONSTRUCTOR_P (t)) dump_string (di, "constructor"); if (DECL_DESTRUCTOR_P (t)) dump_string (di, "destructor"); if (DECL_CONV_FN_P (t)) dump_string (di, "conversion"); if (DECL_GLOBAL_CTOR_P (t)) dump_string (di, "global init"); if (DECL_GLOBAL_DTOR_P (t)) dump_string (di, "global fini"); if (DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (t)) dump_string (di, "pseudo tmpl"); } else { tree virt = THUNK_VIRTUAL_OFFSET (t); dump_string (di, "thunk"); if (DECL_THIS_THUNK_P (t)) dump_string (di, "this adjusting"); else { dump_string (di, "result adjusting"); if (virt) virt = BINFO_VPTR_FIELD (virt); } dump_int (di, "fixd", THUNK_FIXED_OFFSET (t)); if (virt) dump_int (di, "virt", tree_low_cst (virt, 0)); dump_child ("fn", DECL_INITIAL (t)); } break; case NAMESPACE_DECL: if (DECL_NAMESPACE_ALIAS (t)) dump_child ("alis", DECL_NAMESPACE_ALIAS (t)); else if (!dump_flag (di, TDF_SLIM, t)) dump_child ("dcls", cp_namespace_decls (t)); break; case TEMPLATE_DECL: dump_child ("rslt", DECL_TEMPLATE_RESULT (t)); dump_child ("inst", DECL_TEMPLATE_INSTANTIATIONS (t)); dump_child ("spcs", DECL_TEMPLATE_SPECIALIZATIONS (t)); dump_child ("prms", DECL_TEMPLATE_PARMS (t)); break; case OVERLOAD: dump_child ("crnt", OVL_CURRENT (t)); dump_child ("chan", OVL_CHAIN (t)); break; case TRY_BLOCK: dump_stmt (di, t); if (CLEANUP_P (t)) dump_string (di, "cleanup"); dump_child ("body", TRY_STMTS (t)); dump_child ("hdlr", TRY_HANDLERS (t)); break; case EH_SPEC_BLOCK: dump_stmt (di, t); dump_child ("body", EH_SPEC_STMTS (t)); dump_child ("raises", EH_SPEC_RAISES (t)); break; case PTRMEM_CST: dump_child ("clas", PTRMEM_CST_CLASS (t)); dump_child ("mbr", PTRMEM_CST_MEMBER (t)); break; case THROW_EXPR: /* These nodes are unary, but do not have code class `1'. */ dump_child ("op 0", TREE_OPERAND (t, 0)); break; case AGGR_INIT_EXPR: dump_int (di, "ctor", AGGR_INIT_VIA_CTOR_P (t)); dump_child ("fn", TREE_OPERAND (t, 0)); dump_child ("args", TREE_OPERAND (t, 1)); dump_child ("decl", TREE_OPERAND (t, 2)); break; case HANDLER: dump_stmt (di, t); dump_child ("parm", HANDLER_PARMS (t)); dump_child ("body", HANDLER_BODY (t)); break; case MUST_NOT_THROW_EXPR: dump_stmt (di, t); dump_child ("body", TREE_OPERAND (t, 0)); break; case USING_STMT: dump_stmt (di, t); dump_child ("nmsp", USING_STMT_NAMESPACE (t)); break; case CLEANUP_STMT: dump_stmt (di, t); dump_child ("decl", CLEANUP_DECL (t)); dump_child ("expr", CLEANUP_EXPR (t)); dump_child ("body", CLEANUP_BODY (t)); break; case IF_STMT: dump_stmt (di, t); dump_child ("cond", IF_COND (t)); dump_child ("then", THEN_CLAUSE (t)); dump_child ("else", ELSE_CLAUSE (t)); break; default: break; } return c_dump_tree (di, t); }
void cxx_print_type (FILE *file, tree node, int indent) { switch (TREE_CODE (node)) { case TEMPLATE_TYPE_PARM: case TEMPLATE_TEMPLATE_PARM: case BOUND_TEMPLATE_TEMPLATE_PARM: indent_to (file, indent + 3); fprintf (file, "index %d level %d orig_level %d", TEMPLATE_TYPE_IDX (node), TEMPLATE_TYPE_LEVEL (node), TEMPLATE_TYPE_ORIG_LEVEL (node)); return; case FUNCTION_TYPE: case METHOD_TYPE: if (TYPE_RAISES_EXCEPTIONS (node)) print_node (file, "throws", TYPE_RAISES_EXCEPTIONS (node), indent + 4); return; case RECORD_TYPE: case UNION_TYPE: break; case DECLTYPE_TYPE: print_node (file, "expr", DECLTYPE_TYPE_EXPR (node), indent + 4); return; case TYPENAME_TYPE: print_node (file, "fullname", TYPENAME_TYPE_FULLNAME (node), indent + 4); return; case TYPE_PACK_EXPANSION: print_node (file, "args", PACK_EXPANSION_EXTRA_ARGS (node), indent + 4); return; default: return; } if (TYPE_PTRMEMFUNC_P (node)) print_node (file, "ptrmemfunc fn type", TYPE_PTRMEMFUNC_FN_TYPE (node), indent + 4); if (! CLASS_TYPE_P (node)) return; indent_to (file, indent + 4); fprintf (file, "full-name \"%s\"", type_as_string (node, TFF_CLASS_KEY_OR_ENUM)); indent_to (file, indent + 3); if (TYPE_NEEDS_CONSTRUCTING (node)) fputs ( " needs-constructor", file); if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (node)) fputs (" needs-destructor", file); if (TYPE_HAS_DEFAULT_CONSTRUCTOR (node)) fputs (" X()", file); if (TYPE_HAS_CONVERSION (node)) fputs (" has-type-conversion", file); if (TYPE_HAS_COPY_CTOR (node)) { if (TYPE_HAS_CONST_COPY_CTOR (node)) fputs (" X(constX&)", file); else fputs (" X(X&)", file); } if (TYPE_HAS_NEW_OPERATOR (node)) fputs (" new", file); if (TYPE_HAS_ARRAY_NEW_OPERATOR (node)) fputs (" new[]", file); if (TYPE_GETS_DELETE (node) & 1) fputs (" delete", file); if (TYPE_GETS_DELETE (node) & 2) fputs (" delete[]", file); if (TYPE_HAS_COPY_ASSIGN (node)) fputs (" this=(X&)", file); if (CLASSTYPE_SORTED_FIELDS (node)) fprintf (file, " sorted-fields %p", (void *) CLASSTYPE_SORTED_FIELDS (node)); if (TREE_CODE (node) == RECORD_TYPE) { if (TYPE_BINFO (node)) fprintf (file, " n_parents=%d", BINFO_N_BASE_BINFOS (TYPE_BINFO (node))); else fprintf (file, " no-binfo"); fprintf (file, " use_template=%d", CLASSTYPE_USE_TEMPLATE (node)); if (CLASSTYPE_INTERFACE_ONLY (node)) fprintf (file, " interface-only"); if (CLASSTYPE_INTERFACE_UNKNOWN (node)) fprintf (file, " interface-unknown"); } }
static void do_build_assign_ref (tree fndecl) { tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl)); tree compound_stmt; compound_stmt = begin_compound_stmt (0); parm = convert_from_reference (parm); if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type) && is_empty_class (current_class_type)) /* Don't copy the padding byte; it might not have been allocated if *this is a base subobject. */; else if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type)) { tree t = build2 (MODIFY_EXPR, void_type_node, current_class_ref, parm); finish_expr_stmt (t); } else { tree fields; int cvquals = cp_type_quals (TREE_TYPE (parm)); int i; tree binfo, base_binfo; /* Assign to each of the direct base classes. */ for (binfo = TYPE_BINFO (current_class_type), i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) { tree converted_parm; /* We must convert PARM directly to the base class explicitly since the base class may be ambiguous. */ converted_parm = build_base_path (PLUS_EXPR, parm, base_binfo, 1); /* Call the base class assignment operator. */ finish_expr_stmt (build_special_member_call (current_class_ref, ansi_assopname (NOP_EXPR), build_tree_list (NULL_TREE, converted_parm), base_binfo, LOOKUP_NORMAL | LOOKUP_NONVIRTUAL)); } /* Assign to each of the non-static data members. */ for (fields = TYPE_FIELDS (current_class_type); fields; fields = TREE_CHAIN (fields)) { tree comp = current_class_ref; tree init = parm; tree field = fields; tree expr_type; int quals; if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field)) continue; expr_type = TREE_TYPE (field); if (CP_TYPE_CONST_P (expr_type)) { error ("non-static const member %q#D, can't use default " "assignment operator", field); continue; } else if (TREE_CODE (expr_type) == REFERENCE_TYPE) { error ("non-static reference member %q#D, can't use " "default assignment operator", field); continue; } if (DECL_NAME (field)) { if (VFIELD_NAME_P (DECL_NAME (field))) continue; } else if (ANON_AGGR_TYPE_P (expr_type) && TYPE_FIELDS (expr_type) != NULL_TREE) /* Just use the field; anonymous types can't have nontrivial copy ctors or assignment ops. */; else continue; comp = build3 (COMPONENT_REF, expr_type, comp, field, NULL_TREE); /* Compute the type of init->field */ quals = cvquals; if (DECL_MUTABLE_P (field)) quals &= ~TYPE_QUAL_CONST; expr_type = cp_build_qualified_type (expr_type, quals); init = build3 (COMPONENT_REF, expr_type, init, field, NULL_TREE); if (DECL_NAME (field)) init = build_modify_expr (comp, NOP_EXPR, init); else init = build2 (MODIFY_EXPR, TREE_TYPE (comp), comp, init); finish_expr_stmt (init); } } finish_return_stmt (current_class_ref); finish_compound_stmt (compound_stmt); }
static void do_build_copy_constructor (tree fndecl) { tree parm = FUNCTION_FIRST_USER_PARM (fndecl); parm = convert_from_reference (parm); if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type) && is_empty_class (current_class_type)) /* Don't copy the padding byte; it might not have been allocated if *this is a base subobject. */; else if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type)) { tree t = build2 (INIT_EXPR, void_type_node, current_class_ref, parm); finish_expr_stmt (t); } else { tree fields = TYPE_FIELDS (current_class_type); tree member_init_list = NULL_TREE; int cvquals = cp_type_quals (TREE_TYPE (parm)); int i; tree binfo, base_binfo; VEC(tree,gc) *vbases; /* Initialize all the base-classes with the parameter converted to their type so that we get their copy constructor and not another constructor that takes current_class_type. We must deal with the binfo's directly as a direct base might be inaccessible due to ambiguity. */ for (vbases = CLASSTYPE_VBASECLASSES (current_class_type), i = 0; VEC_iterate (tree, vbases, i, binfo); i++) { member_init_list = tree_cons (binfo, build_tree_list (NULL_TREE, build_base_path (PLUS_EXPR, parm, binfo, 1)), member_init_list); } for (binfo = TYPE_BINFO (current_class_type), i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) { if (BINFO_VIRTUAL_P (base_binfo)) continue; member_init_list = tree_cons (base_binfo, build_tree_list (NULL_TREE, build_base_path (PLUS_EXPR, parm, base_binfo, 1)), member_init_list); } for (; fields; fields = TREE_CHAIN (fields)) { tree init = parm; tree field = fields; tree expr_type; if (TREE_CODE (field) != FIELD_DECL) continue; expr_type = TREE_TYPE (field); if (DECL_NAME (field)) { if (VFIELD_NAME_P (DECL_NAME (field))) continue; } else if (ANON_AGGR_TYPE_P (expr_type) && TYPE_FIELDS (expr_type)) /* Just use the field; anonymous types can't have nontrivial copy ctors or assignment ops. */; else continue; /* Compute the type of "init->field". If the copy-constructor parameter is, for example, "const S&", and the type of the field is "T", then the type will usually be "const T". (There are no cv-qualified variants of reference types.) */ if (TREE_CODE (expr_type) != REFERENCE_TYPE) { int quals = cvquals; if (DECL_MUTABLE_P (field)) quals &= ~TYPE_QUAL_CONST; expr_type = cp_build_qualified_type (expr_type, quals); } init = build3 (COMPONENT_REF, expr_type, init, field, NULL_TREE); init = build_tree_list (NULL_TREE, init); member_init_list = tree_cons (field, init, member_init_list); } finish_mem_initializers (member_init_list); } }
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; }
void cxx_print_type (FILE *file, tree node, int indent) { switch (TREE_CODE (node)) { case TEMPLATE_TYPE_PARM: case TEMPLATE_TEMPLATE_PARM: case BOUND_TEMPLATE_TEMPLATE_PARM: indent_to (file, indent + 3); fprintf (file, "index " HOST_WIDE_INT_PRINT_DEC " level " HOST_WIDE_INT_PRINT_DEC " orig_level " HOST_WIDE_INT_PRINT_DEC, TEMPLATE_TYPE_IDX (node), TEMPLATE_TYPE_LEVEL (node), TEMPLATE_TYPE_ORIG_LEVEL (node)); return; case FUNCTION_TYPE: case METHOD_TYPE: if (TYPE_RAISES_EXCEPTIONS (node)) print_node (file, "throws", TYPE_RAISES_EXCEPTIONS (node), indent + 4); return; case RECORD_TYPE: case UNION_TYPE: break; default: return; } if (TYPE_PTRMEMFUNC_P (node)) print_node (file, "ptrmemfunc fn type", TYPE_PTRMEMFUNC_FN_TYPE (node), indent + 4); if (! CLASS_TYPE_P (node)) return; indent_to (file, indent + 3); if (TYPE_NEEDS_CONSTRUCTING (node)) fputs ( "needs-constructor", file); if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (node)) fputs (" needs-destructor", file); if (TYPE_HAS_DEFAULT_CONSTRUCTOR (node)) fputs (" X()", file); if (TYPE_HAS_CONVERSION (node)) fputs (" has-type-conversion", file); if (TYPE_HAS_INIT_REF (node)) { if (TYPE_HAS_CONST_INIT_REF (node)) fputs (" X(constX&)", file); else fputs (" X(X&)", file); } if (TYPE_HAS_NEW_OPERATOR (node)) fputs (" new", file); if (TYPE_HAS_ARRAY_NEW_OPERATOR (node)) fputs (" new[]", file); if (TYPE_GETS_DELETE (node) & 1) fputs (" delete", file); if (TYPE_GETS_DELETE (node) & 2) fputs (" delete[]", file); if (TYPE_HAS_ASSIGN_REF (node)) fputs (" this=(X&)", file); if (TREE_CODE (node) == RECORD_TYPE) { if (TYPE_BINFO (node)) fprintf (file, " n_parents=%d", BINFO_N_BASE_BINFOS (TYPE_BINFO (node))); else fprintf (file, " no-binfo"); fprintf (file, " use_template=%d", CLASSTYPE_USE_TEMPLATE (node)); if (CLASSTYPE_INTERFACE_ONLY (node)) fprintf (file, " interface-only"); if (CLASSTYPE_INTERFACE_UNKNOWN (node)) fprintf (file, " interface-unknown"); } }
tree build_throw (tree exp) { if (exp == error_mark_node) return exp; if (processing_template_decl) { if (cfun) current_function_returns_abnormally = 1; exp = build_min (THROW_EXPR, void_type_node, exp); SET_EXPR_LOCATION (exp, input_location); return exp; } if (exp && null_node_p (exp)) warning (0, "throwing NULL, which has integral, not pointer type"); if (exp != NULL_TREE) { if (!is_admissible_throw_operand_or_catch_parameter (exp, true)) return error_mark_node; } if (! doing_eh ()) return error_mark_node; if (exp) { tree throw_type; tree temp_type; tree cleanup; tree object, ptr; tree tmp; tree allocate_expr; /* The CLEANUP_TYPE is the internal type of a destructor. */ if (!cleanup_type) { tmp = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE); cleanup_type = build_pointer_type (tmp); } if (!throw_fn) { tree name = get_identifier ("__cxa_throw"); throw_fn = get_global_binding (name); if (!throw_fn) { /* Declare void __cxa_throw (void*, void*, void (*)(void*)). */ /* ??? Second argument is supposed to be "std::type_info*". */ tmp = build_function_type_list (void_type_node, ptr_type_node, ptr_type_node, cleanup_type, NULL_TREE); throw_fn = push_throw_library_fn (name, tmp); if (flag_tm) { tree itm_name = get_identifier ("_ITM_cxa_throw"); tree itm_fn = get_global_binding (itm_name); if (!itm_fn) itm_fn = push_throw_library_fn (itm_name, tmp); apply_tm_attr (itm_fn, get_identifier ("transaction_pure")); record_tm_replacement (throw_fn, itm_fn); } } } /* [except.throw] A throw-expression initializes a temporary object, the type of which is determined by removing any top-level cv-qualifiers from the static type of the operand of throw and adjusting the type from "array of T" or "function return T" to "pointer to T" or "pointer to function returning T" respectively. */ temp_type = is_bitfield_expr_with_lowered_type (exp); if (!temp_type) temp_type = cv_unqualified (type_decays_to (TREE_TYPE (exp))); /* OK, this is kind of wacky. The standard says that we call terminate when the exception handling mechanism, after completing evaluation of the expression to be thrown but before the exception is caught (_except.throw_), calls a user function that exits via an uncaught exception. So we have to protect the actual initialization of the exception object with terminate(), but evaluate the expression first. Since there could be temps in the expression, we need to handle that, too. We also expand the call to __cxa_allocate_exception first (which doesn't matter, since it can't throw). */ /* Allocate the space for the exception. */ allocate_expr = do_allocate_exception (temp_type); allocate_expr = get_target_expr (allocate_expr); ptr = TARGET_EXPR_SLOT (allocate_expr); TARGET_EXPR_CLEANUP (allocate_expr) = do_free_exception (ptr); CLEANUP_EH_ONLY (allocate_expr) = 1; object = build_nop (build_pointer_type (temp_type), ptr); object = cp_build_fold_indirect_ref (object); /* And initialize the exception object. */ if (CLASS_TYPE_P (temp_type)) { int flags = LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING; vec<tree, va_gc> *exp_vec; bool converted = false; /* Under C++0x [12.8/16 class.copy], a thrown lvalue is sometimes treated as an rvalue for the purposes of overload resolution to favor move constructors over copy constructors. */ if (/* Must be a local, automatic variable. */ VAR_P (exp) && DECL_CONTEXT (exp) == current_function_decl && ! TREE_STATIC (exp) /* The variable must not have the `volatile' qualifier. */ && !(cp_type_quals (TREE_TYPE (exp)) & TYPE_QUAL_VOLATILE)) { tree moved = move (exp); exp_vec = make_tree_vector_single (moved); moved = (build_special_member_call (object, complete_ctor_identifier, &exp_vec, TREE_TYPE (object), flags|LOOKUP_PREFER_RVALUE, tf_none)); release_tree_vector (exp_vec); if (moved != error_mark_node) { exp = moved; converted = true; } } /* Call the copy constructor. */ if (!converted) { exp_vec = make_tree_vector_single (exp); exp = (build_special_member_call (object, complete_ctor_identifier, &exp_vec, TREE_TYPE (object), flags, tf_warning_or_error)); release_tree_vector (exp_vec); } if (exp == error_mark_node) { error (" in thrown expression"); return error_mark_node; } } else { tmp = decay_conversion (exp, tf_warning_or_error); if (tmp == error_mark_node) return error_mark_node; exp = build2 (INIT_EXPR, temp_type, object, tmp); } /* Mark any cleanups from the initialization as MUST_NOT_THROW, since they are run after the exception object is initialized. */ cp_walk_tree_without_duplicates (&exp, wrap_cleanups_r, 0); /* Prepend the allocation. */ exp = build2 (COMPOUND_EXPR, TREE_TYPE (exp), allocate_expr, exp); /* Force all the cleanups to be evaluated here so that we don't have to do them during unwinding. */ exp = build1 (CLEANUP_POINT_EXPR, void_type_node, exp); throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object))); cleanup = NULL_TREE; if (type_build_dtor_call (TREE_TYPE (object))) { tree dtor_fn = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)), complete_dtor_identifier, 0); dtor_fn = BASELINK_FUNCTIONS (dtor_fn); mark_used (dtor_fn); if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (object))) { cxx_mark_addressable (dtor_fn); /* Pretend it's a normal function. */ cleanup = build1 (ADDR_EXPR, cleanup_type, dtor_fn); } } if (cleanup == NULL_TREE) cleanup = build_int_cst (cleanup_type, 0); /* ??? Indicate that this function call throws throw_type. */ tmp = cp_build_function_call_nary (throw_fn, tf_warning_or_error, ptr, throw_type, cleanup, NULL_TREE); /* Tack on the initialization stuff. */ exp = build2 (COMPOUND_EXPR, TREE_TYPE (tmp), exp, tmp); } else { /* Rethrow current exception. */ if (!rethrow_fn) { tree name = get_identifier ("__cxa_rethrow"); rethrow_fn = get_global_binding (name); if (!rethrow_fn) /* Declare void __cxa_rethrow (void). */ rethrow_fn = push_throw_library_fn (name, build_function_type_list (void_type_node, NULL_TREE)); if (flag_tm) apply_tm_attr (rethrow_fn, get_identifier ("transaction_pure")); } /* ??? Indicate that this function call allows exceptions of the type of the enclosing catch block (if known). */ exp = cp_build_function_call_vec (rethrow_fn, NULL, tf_warning_or_error); } exp = build1 (THROW_EXPR, void_type_node, exp); SET_EXPR_LOCATION (exp, input_location); return exp; }
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; } } }