static void mf_decl_cache_locals (void) { gimple g; gimple_seq seq = NULL; /* Build the cache vars. */ mf_cache_shift_decl_l = mf_mark (create_tmp_reg (TREE_TYPE (mf_cache_shift_decl), "__mf_lookup_shift_l")); mf_cache_mask_decl_l = mf_mark (create_tmp_reg (TREE_TYPE (mf_cache_mask_decl), "__mf_lookup_mask_l")); /* Build initialization nodes for the cache vars. We just load the globals into the cache variables. */ g = gimple_build_assign (mf_cache_shift_decl_l, mf_cache_shift_decl); gimple_set_location (g, DECL_SOURCE_LOCATION (current_function_decl)); gimple_seq_add_stmt (&seq, g); g = gimple_build_assign (mf_cache_mask_decl_l, mf_cache_mask_decl); gimple_set_location (g, DECL_SOURCE_LOCATION (current_function_decl)); gimple_seq_add_stmt (&seq, g); insert_edge_copies_seq (seq, ENTRY_BLOCK_PTR); gsi_commit_edge_inserts (); }
static void lto_symtab_merge_decls_2 (symtab_node first, bool diagnosed_p) { symtab_node prevailing, e; vec<tree> mismatches = vNULL; unsigned i; tree decl; /* Nothing to do for a single entry. */ prevailing = first; if (!prevailing->symbol.next_sharing_asm_name) return; /* Try to merge each entry with the prevailing one. */ for (e = prevailing->symbol.next_sharing_asm_name; e; e = e->symbol.next_sharing_asm_name) if (TREE_PUBLIC (e->symbol.decl)) { if (!lto_symtab_merge (prevailing, e) && !diagnosed_p) mismatches.safe_push (e->symbol.decl); } if (mismatches.is_empty ()) return; /* Diagnose all mismatched re-declarations. */ FOR_EACH_VEC_ELT (mismatches, i, decl) { if (!types_compatible_p (TREE_TYPE (prevailing->symbol.decl), TREE_TYPE (decl))) diagnosed_p |= warning_at (DECL_SOURCE_LOCATION (decl), 0, "type of %qD does not match original " "declaration", decl); else if ((DECL_USER_ALIGN (prevailing->symbol.decl) && DECL_USER_ALIGN (decl)) && DECL_ALIGN (prevailing->symbol.decl) < DECL_ALIGN (decl)) { diagnosed_p |= warning_at (DECL_SOURCE_LOCATION (decl), 0, "alignment of %qD is bigger than " "original declaration", decl); } } if (diagnosed_p) inform (DECL_SOURCE_LOCATION (prevailing->symbol.decl), "previously declared here"); mismatches.release (); }
/* Used by NeXT ABI=0..2 */ void build_next_selector_translation_table (void) { tree chain; for (chain = sel_ref_chain; chain; chain = TREE_CHAIN (chain)) { tree expr; tree decl = TREE_PURPOSE (chain); if (warn_selector) { location_t loc; if (decl) loc = DECL_SOURCE_LOCATION (decl); else loc = UNKNOWN_LOCATION; diagnose_missing_method (TREE_VALUE (chain), loc); } expr = build_selector (TREE_VALUE (chain)); if (decl) { /* Entries of this form are used for references to methods. The runtime re-writes these on start-up, but the compiler can't see that and optimizes it away unless we force it. */ DECL_PRESERVE_P (decl) = 1; finish_var_decl (decl, expr); } } }
void streamer_pack_tree_bitfields (struct output_block *ob, struct bitpack_d *bp, tree expr) { enum tree_code code; code = TREE_CODE (expr); /* Note that all these functions are highly sensitive to changes in the types and sizes of each of the fields being packed. */ pack_ts_base_value_fields (bp, expr); if (CODE_CONTAINS_STRUCT (code, TS_INT_CST)) pack_ts_int_cst_value_fields (bp, expr); if (CODE_CONTAINS_STRUCT (code, TS_REAL_CST)) pack_ts_real_cst_value_fields (bp, expr); if (CODE_CONTAINS_STRUCT (code, TS_FIXED_CST)) pack_ts_fixed_cst_value_fields (bp, expr); if (CODE_CONTAINS_STRUCT (code, TS_DECL_MINIMAL)) stream_output_location (ob, bp, DECL_SOURCE_LOCATION (expr)); if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) pack_ts_decl_common_value_fields (bp, expr); if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL)) pack_ts_decl_wrtl_value_fields (bp, expr); if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)) pack_ts_decl_with_vis_value_fields (bp, expr); if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL)) pack_ts_function_decl_value_fields (bp, expr); if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON)) pack_ts_type_common_value_fields (bp, expr); if (CODE_CONTAINS_STRUCT (code, TS_EXP)) stream_output_location (ob, bp, EXPR_LOCATION (expr)); if (CODE_CONTAINS_STRUCT (code, TS_BLOCK)) pack_ts_block_value_fields (ob, bp, expr); if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL)) pack_ts_translation_unit_decl_value_fields (ob, bp, expr); if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION)) pack_ts_target_option (bp, expr); if (CODE_CONTAINS_STRUCT (code, TS_OPTIMIZATION)) pack_ts_optimization (bp, expr); if (CODE_CONTAINS_STRUCT (code, TS_BINFO)) bp_pack_var_len_unsigned (bp, vec_safe_length (BINFO_BASE_ACCESSES (expr))); if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR)) bp_pack_var_len_unsigned (bp, CONSTRUCTOR_NELTS (expr)); }
static void lto_input_ts_decl_minimal_tree_pointers (struct lto_input_block *ib, struct data_in *data_in, tree expr) { DECL_NAME (expr) = stream_read_tree (ib, data_in); DECL_CONTEXT (expr) = stream_read_tree (ib, data_in); DECL_SOURCE_LOCATION (expr) = lto_input_location (ib, data_in); }
static void write_ts_decl_minimal_tree_pointers (struct output_block *ob, tree expr, bool ref_p) { stream_write_tree (ob, DECL_NAME (expr), ref_p); stream_write_tree (ob, DECL_CONTEXT (expr), ref_p); lto_output_location (ob, DECL_SOURCE_LOCATION (expr)); }
static void lto_symtab_merge_decls_2 (void **slot, bool diagnosed_p) { lto_symtab_entry_t prevailing, e; VEC(tree, heap) *mismatches = NULL; unsigned i; tree decl; /* Nothing to do for a single entry. */ prevailing = (lto_symtab_entry_t) *slot; if (!prevailing->next) return; /* Try to merge each entry with the prevailing one. */ for (e = prevailing->next; e; e = e->next) { if (!lto_symtab_merge (prevailing, e) && !diagnosed_p) VEC_safe_push (tree, heap, mismatches, e->decl); } if (VEC_empty (tree, mismatches)) return; /* Diagnose all mismatched re-declarations. */ FOR_EACH_VEC_ELT (tree, mismatches, i, decl) { if (!types_compatible_p (TREE_TYPE (prevailing->decl), TREE_TYPE (decl))) diagnosed_p |= warning_at (DECL_SOURCE_LOCATION (decl), 0, "type of %qD does not match original " "declaration", decl); else if ((DECL_USER_ALIGN (prevailing->decl) && DECL_USER_ALIGN (decl)) && DECL_ALIGN (prevailing->decl) < DECL_ALIGN (decl)) { diagnosed_p |= warning_at (DECL_SOURCE_LOCATION (decl), 0, "alignment of %qD is bigger than " "original declaration", decl); } } if (diagnosed_p) inform (DECL_SOURCE_LOCATION (prevailing->decl), "previously declared here"); VEC_free (tree, heap, mismatches); }
static void update_cloned_parm (tree parm, tree cloned_parm, bool first) { DECL_ABSTRACT_ORIGIN (cloned_parm) = parm; /* We may have taken its address. */ TREE_ADDRESSABLE (cloned_parm) = TREE_ADDRESSABLE (parm); /* The definition might have different constness. */ TREE_READONLY (cloned_parm) = TREE_READONLY (parm); TREE_USED (cloned_parm) = !first || TREE_USED (parm); /* The name may have changed from the declaration. */ DECL_NAME (cloned_parm) = DECL_NAME (parm); DECL_SOURCE_LOCATION (cloned_parm) = DECL_SOURCE_LOCATION (parm); TREE_TYPE (cloned_parm) = TREE_TYPE (parm); }
static void mf_decl_cache_locals (void) { tree t, shift_init_stmts, mask_init_stmts; tree_stmt_iterator tsi; /* Build the cache vars. */ mf_cache_shift_decl_l = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_shift_decl), "__mf_lookup_shift_l")); mf_cache_mask_decl_l = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_mask_decl), "__mf_lookup_mask_l")); /* Build initialization nodes for the cache vars. We just load the globals into the cache variables. */ t = build2 (MODIFY_EXPR, TREE_TYPE (mf_cache_shift_decl_l), mf_cache_shift_decl_l, mf_cache_shift_decl); SET_EXPR_LOCATION (t, DECL_SOURCE_LOCATION (current_function_decl)); gimplify_to_stmt_list (&t); shift_init_stmts = t; t = build2 (MODIFY_EXPR, TREE_TYPE (mf_cache_mask_decl_l), mf_cache_mask_decl_l, mf_cache_mask_decl); SET_EXPR_LOCATION (t, DECL_SOURCE_LOCATION (current_function_decl)); gimplify_to_stmt_list (&t); mask_init_stmts = t; /* Anticipating multiple entry points, we insert the cache vars initializers in each successor of the ENTRY_BLOCK_PTR. */ for (tsi = tsi_start (shift_init_stmts); ! tsi_end_p (tsi); tsi_next (&tsi)) insert_edge_copies (tsi_stmt (tsi), ENTRY_BLOCK_PTR); for (tsi = tsi_start (mask_init_stmts); ! tsi_end_p (tsi); tsi_next (&tsi)) insert_edge_copies (tsi_stmt (tsi), ENTRY_BLOCK_PTR); bsi_commit_edge_inserts (); }
static void maybe_noexcept_warning (tree fn) { if (TREE_NOTHROW (fn)) { warning (OPT_Wnoexcept, "noexcept-expression evaluates to %<false%> " "because of a call to %qD", fn); warning_at (DECL_SOURCE_LOCATION (fn), OPT_Wnoexcept, "but %qD does not throw; perhaps " "it should be declared %<noexcept%>", fn); } }
static unsigned int cyc_complexity_execute(void) { int complexity; expanded_location xloc; /* M = E - N + 2P */ complexity = n_edges_for_fn(cfun) - n_basic_blocks_for_fn(cfun) + 2; xloc = expand_location(DECL_SOURCE_LOCATION(current_function_decl)); fprintf(log_file, "%s%s:%d:%d:%s\t%d\n", has_log_file ? "" : "Cyclomatic Complexity ", xloc.file, xloc.line, xloc.column, DECL_NAME_POINTER(current_function_decl), complexity); return 0; }
static void cp_ubsan_maybe_instrument_return (tree fndecl) { if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fndecl))) || DECL_CONSTRUCTOR_P (fndecl) || DECL_DESTRUCTOR_P (fndecl) || !targetm.warn_func_return (fndecl)) return; tree t = DECL_SAVED_TREE (fndecl); while (t) { switch (TREE_CODE (t)) { case BIND_EXPR: t = BIND_EXPR_BODY (t); continue; case TRY_FINALLY_EXPR: t = TREE_OPERAND (t, 0); continue; case STATEMENT_LIST: { tree_stmt_iterator i = tsi_last (t); if (!tsi_end_p (i)) { t = tsi_stmt (i); continue; } } break; case RETURN_EXPR: return; default: break; } break; } if (t == NULL_TREE) return; t = DECL_SAVED_TREE (fndecl); if (TREE_CODE (t) == BIND_EXPR && TREE_CODE (BIND_EXPR_BODY (t)) == STATEMENT_LIST) { tree_stmt_iterator i = tsi_last (BIND_EXPR_BODY (t)); t = ubsan_instrument_return (DECL_SOURCE_LOCATION (fndecl)); tsi_link_after (&i, t, TSI_NEW_STMT); } }
static tree build_exception_object_var (void) { tree decl = DECL_FUNCTION_EXC_OBJ (current_function_decl); if (decl == NULL) { decl = build_decl (DECL_SOURCE_LOCATION (current_function_decl), VAR_DECL, get_identifier ("#exc_obj"), ptr_type_node); DECL_IGNORED_P (decl) = 1; DECL_ARTIFICIAL (decl) = 1; DECL_FUNCTION_EXC_OBJ (current_function_decl) = decl; pushdecl_function_level (decl); } return decl; }
static void print_function(const_tree caller, const_tree callee) { expanded_location xloc; const char *caller_name, *callee_name; gcc_assert(callee != NULL_TREE); if (DECL_ABSTRACT_ORIGIN(callee) != NULL_TREE) return; callee_name = DECL_NAME_POINTER(callee); gcc_assert(caller != NULL_TREE); caller_name = DECL_NAME_POINTER(caller); xloc = expand_location(DECL_SOURCE_LOCATION(caller)); fprintf(stderr, "DUMP_CFG:%s:%s:%s\n", caller_name, callee_name, xloc.file); }
static tree create_cilk_helper_decl (struct wrapper_data *wd) { char name[20]; if (wd->type == CILK_BLOCK_FOR) sprintf (name, "_cilk_for_" HOST_WIDE_INT_PRINT_DEC, cilk_wrapper_count++); else if (wd->type == CILK_BLOCK_SPAWN) sprintf (name, "_cilk_spn_" HOST_WIDE_INT_PRINT_DEC, cilk_wrapper_count++); else gcc_unreachable (); clean_symbol_name (name); tree fndecl = build_decl (DECL_SOURCE_LOCATION (current_function_decl), FUNCTION_DECL, get_identifier (name), wd->fntype); TREE_PUBLIC (fndecl) = 0; TREE_STATIC (fndecl) = 1; TREE_USED (fndecl) = 1; DECL_ARTIFICIAL (fndecl) = 0; DECL_IGNORED_P (fndecl) = 0; DECL_EXTERNAL (fndecl) = 0; DECL_CONTEXT (fndecl) = wd->context; tree block = make_node (BLOCK); DECL_INITIAL (fndecl) = block; TREE_USED (block) = 1; BLOCK_SUPERCONTEXT (block) = fndecl; gcc_assert (!DECL_SAVED_TREE (fndecl)); /* Inlining would defeat the purpose of this wrapper. Either it secretly switches stack frames or it allocates a stable stack frame to hold function arguments even if the parent stack frame is stolen. */ DECL_UNINLINABLE (fndecl) = 1; tree result_decl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, void_type_node); DECL_ARTIFICIAL (result_decl) = 0; DECL_IGNORED_P (result_decl) = 1; DECL_CONTEXT (result_decl) = fndecl; DECL_RESULT (fndecl) = result_decl; return fndecl; }
tree copy_var_decl (tree var, tree name, tree type) { tree copy = build_decl (DECL_SOURCE_LOCATION (var), VAR_DECL, name, type); TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (var); TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (var); DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (var); DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (var); DECL_IGNORED_P (copy) = DECL_IGNORED_P (var); DECL_CONTEXT (copy) = DECL_CONTEXT (var); TREE_NO_WARNING (copy) = TREE_NO_WARNING (var); TREE_USED (copy) = 1; DECL_SEEN_IN_BIND_EXPR_P (copy) = 1; DECL_ATTRIBUTES (copy) = DECL_ATTRIBUTES (var); return copy; }
static void search_local_strs(bool initexit) { unsigned int i; tree var; FOR_EACH_LOCAL_DECL(cfun, i, var) { tree str, init_val = DECL_INITIAL(var); if (init_val == NULL_TREE) continue; if (strcmp(DECL_NAME_POINTER(var), "__func__")) continue; str = get_string_cst(init_val); gcc_assert(str); if (set_init_exit_section(var, initexit) && verbose) inform(DECL_SOURCE_LOCATION(var), "initified local var: %s: %s", DECL_NAME_POINTER(current_function_decl), TREE_STRING_POINTER(str)); }
/* Default tree printer. Handles declarations only. */ extern "C" bool default_tree_printer(pretty_printer * pp, text_info *text, const char *spec, int precision, bool wide, bool set_locus, bool hash) { tree t; /* FUTURE: %+x should set the locus. */ if(precision != 0 || wide || hash) return false; switch(*spec) { case 'D': t = va_arg(*text->args_ptr, tree); if(DECL_DEBUG_EXPR_IS_FROM(t) && DECL_DEBUG_EXPR(t)) t = DECL_DEBUG_EXPR(t); break; case 'F': case 'T': t = va_arg(*text->args_ptr, tree); break; default: return false; } if(set_locus && text->locus) *text->locus = DECL_SOURCE_LOCATION(t); if(DECL_P(t)) { const char *n = DECL_NAME(t) ? lang_hooks.decl_printable_name(t, 2) : "<anonymous>"; pp_string(pp, n); } else dump_generic_node(pp, t, 0, 0, 0); return true; }
void gen_aux_info_record (tree fndecl, int is_definition, int is_implicit, int is_prototyped) { if (flag_gen_aux_info) { static int compiled_from_record = 0; expanded_location xloc = expand_location (DECL_SOURCE_LOCATION (fndecl)); /* Each output .X file must have a header line. Write one now if we have not yet done so. */ if (!compiled_from_record++) { /* The first line tells which directory file names are relative to. Currently, -aux-info works only for files in the working directory, so just use a `.' as a placeholder for now. */ fprintf (aux_info_file, "/* compiled from: . */\n"); } /* Write the actual line of auxiliary info. */ fprintf (aux_info_file, "/* %s:%d:%c%c */ %s;", xloc.file, xloc.line, (is_implicit) ? 'I' : (is_prototyped) ? 'N' : 'O', (is_definition) ? 'F' : 'C', gen_decl (fndecl, is_definition, ansi)); /* If this is an explicit function declaration, we need to also write out an old-style (i.e. K&R) function header, just in case the user wants to run unprotoize. */ if (is_definition) { fprintf (aux_info_file, " /*%s %s*/", gen_formal_list_for_func_def (fndecl, k_and_r_names), gen_formal_list_for_func_def (fndecl, k_and_r_decls)); } fprintf (aux_info_file, "\n"); } }
tree begin_eh_spec_block (void) { tree r; location_t spec_location = DECL_SOURCE_LOCATION (current_function_decl); /* A noexcept specification (or throw() with -fnothrow-opt) is a MUST_NOT_THROW_EXPR. */ if (TYPE_NOEXCEPT_P (TREE_TYPE (current_function_decl))) { r = build_stmt (spec_location, MUST_NOT_THROW_EXPR, NULL_TREE, NULL_TREE); TREE_SIDE_EFFECTS (r) = 1; } else r = build_stmt (spec_location, EH_SPEC_BLOCK, NULL_TREE, NULL_TREE); add_stmt (r); TREE_OPERAND (r, 0) = push_stmt_list (); return r; }
void xml_location(tree x, FILE *out) { expanded_location l; if (!CAN_HAVE_LOCATION_P(x) && !DECL_P(x)) return; if (EXPR_P(x)) { l = expand_location(EXPR_LOCATION(x)); goto write; } else if (DECL_P(x)) { l = expand_location(DECL_SOURCE_LOCATION(x)); goto write; } return; write: fprintf(out, " location='%s:%d:%d'", filter_built_in(l.file), l.line, l.column); }
static void compare_and_warn (gimple stmt, tree lhs, tree rhs) { if (operand_equal_p (lhs, rhs, OEP_PURE_SAME)) { location_t location; location = (gimple_has_location (stmt) ? gimple_location (stmt) : (DECL_P (lhs) ? DECL_SOURCE_LOCATION (lhs) : input_location)); /* If LHS contains any tree node not currently supported by get_non_ssa_expr, simply emit a generic warning without specifying LHS in the message. */ lhs = get_non_ssa_expr (lhs); if (lhs) warning_at (location, 0, G_("%qE is assigned to itself"), lhs); else warning_at (location, 0, G_("self-assignment detected")); } }
tree make_alias_for (tree target, tree newid) { tree alias = build_decl (DECL_SOURCE_LOCATION (target), TREE_CODE (target), newid, TREE_TYPE (target)); DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (target); cxx_dup_lang_specific_decl (alias); DECL_CONTEXT (alias) = NULL; TREE_READONLY (alias) = TREE_READONLY (target); TREE_THIS_VOLATILE (alias) = TREE_THIS_VOLATILE (target); TREE_PUBLIC (alias) = 0; DECL_INTERFACE_KNOWN (alias) = 1; if (DECL_LANG_SPECIFIC (alias)) { DECL_NOT_REALLY_EXTERN (alias) = 1; DECL_USE_TEMPLATE (alias) = 0; DECL_TEMPLATE_INFO (alias) = NULL; } DECL_EXTERNAL (alias) = 0; DECL_ARTIFICIAL (alias) = 1; DECL_TEMPLATE_INSTANTIATED (alias) = 0; if (TREE_CODE (alias) == FUNCTION_DECL) { DECL_SAVED_FUNCTION_DATA (alias) = NULL; DECL_DESTRUCTOR_P (alias) = 0; DECL_CONSTRUCTOR_P (alias) = 0; DECL_PENDING_INLINE_P (alias) = 0; DECL_DECLARED_INLINE_P (alias) = 0; DECL_INITIAL (alias) = error_mark_node; DECL_ARGUMENTS (alias) = copy_list (DECL_ARGUMENTS (target)); } else TREE_STATIC (alias) = 1; TREE_ADDRESSABLE (alias) = 1; TREE_USED (alias) = 1; SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias)); TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias)) = 1; return alias; }
void insert_capture_proxy (tree var) { cp_binding_level *b; tree stmt_list; /* Put the capture proxy in the extra body block so that it won't clash with a later local variable. */ b = current_binding_level; for (;;) { cp_binding_level *n = b->level_chain; if (n->kind == sk_function_parms) break; b = n; } pushdecl_with_scope (var, b, false); /* And put a DECL_EXPR in the STATEMENT_LIST for the same block. */ var = build_stmt (DECL_SOURCE_LOCATION (var), DECL_EXPR, var); stmt_list = (*stmt_list_stack)[1]; gcc_assert (stmt_list); append_to_statement_list_force (var, &stmt_list); }
static struct pointer_set_t * suggest_attribute (int option, tree decl, bool known_finite, struct pointer_set_t *warned_about, const char * attrib_name) { if (!option_enabled (option, &global_options)) return warned_about; if (TREE_THIS_VOLATILE (decl) || (known_finite && function_always_visible_to_compiler_p (decl))) return warned_about; if (!warned_about) warned_about = pointer_set_create (); if (pointer_set_contains (warned_about, decl)) return warned_about; pointer_set_insert (warned_about, decl); warning_at (DECL_SOURCE_LOCATION (decl), option, known_finite ? _("function might be candidate for attribute %<%s%>") : _("function might be candidate for attribute %<%s%>" " if it is known to return normally"), attrib_name); return warned_about; }
static tree mf_varname_tree (tree decl) { const char *buf_contents; tree result; gcc_assert (decl); pretty_printer buf; /* Add FILENAME[:LINENUMBER[:COLUMNNUMBER]]. */ { expanded_location xloc = expand_location (DECL_SOURCE_LOCATION (decl)); const char *sourcefile; unsigned sourceline = xloc.line; unsigned sourcecolumn = 0; sourcecolumn = xloc.column; sourcefile = xloc.file; if (sourcefile == NULL && current_function_decl != NULL_TREE) sourcefile = DECL_SOURCE_FILE (current_function_decl); if (sourcefile == NULL) sourcefile = "<unknown file>"; pp_string (&buf, sourcefile); if (sourceline != 0) { pp_colon (&buf); pp_decimal_int (&buf, sourceline); if (sourcecolumn != 0) { pp_colon (&buf); pp_decimal_int (&buf, sourcecolumn); } } } if (current_function_decl != NULL_TREE) { /* Add (FUNCTION) */ pp_string (&buf, " ("); { const char *funcname = NULL; if (DECL_NAME (current_function_decl)) funcname = lang_hooks.decl_printable_name (current_function_decl, 1); if (funcname == NULL) funcname = "anonymous fn"; pp_string (&buf, funcname); } pp_string (&buf, ") "); } else pp_space (&buf); /* Add <variable-declaration>, possibly demangled. */ { const char *declname = NULL; if (DECL_NAME (decl) != NULL) { if (strcmp ("GNU C++", lang_hooks.name) == 0) { /* The gcc/cp decl_printable_name hook doesn't do as good a job as the libiberty demangler. */ declname = cplus_demangle (IDENTIFIER_POINTER (DECL_NAME (decl)), DMGL_AUTO | DMGL_VERBOSE); } if (declname == NULL) declname = lang_hooks.decl_printable_name (decl, 3); } if (declname == NULL) declname = "<unnamed variable>"; pp_string (&buf, declname); } /* Return the lot as a new STRING_CST. */ buf_contents = ggc_strdup (pp_formatted_text (&buf)); result = mf_build_string (buf_contents); pp_clear_output_area (&buf); return result; }
void maybe_add_lambda_conv_op (tree type) { bool nested = (cfun != NULL); bool nested_def = decl_function_context (TYPE_MAIN_DECL (type)); tree callop = lambda_function (type); if (LAMBDA_EXPR_CAPTURE_LIST (CLASSTYPE_LAMBDA_EXPR (type)) != NULL_TREE) return; if (processing_template_decl) return; bool const generic_lambda_p = (DECL_TEMPLATE_INFO (callop) && DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) == callop); if (!generic_lambda_p && DECL_INITIAL (callop) == NULL_TREE) { /* If the op() wasn't instantiated due to errors, give up. */ gcc_assert (errorcount || sorrycount); return; } /* Non-template conversion operators are defined directly with build_call_a and using DIRECT_ARGVEC for arguments (including 'this'). Templates are deferred and the CALL is built in-place. In the case of a deduced return call op, the decltype expression, DECLTYPE_CALL, used as a substitute for the return type is also built in-place. The arguments of DECLTYPE_CALL in the return expression may differ in flags from those in the body CALL. In particular, parameter pack expansions are marked PACK_EXPANSION_LOCAL_P in the body CALL, but not in DECLTYPE_CALL. */ vec<tree, va_gc> *direct_argvec = 0; tree decltype_call = 0, call = 0; tree fn_result = TREE_TYPE (TREE_TYPE (callop)); if (generic_lambda_p) { /* Prepare the dependent member call for the static member function '_FUN' and, potentially, prepare another call to be used in a decltype return expression for a deduced return call op to allow for simple implementation of the conversion operator. */ tree instance = build_nop (type, null_pointer_node); tree objfn = build_min (COMPONENT_REF, NULL_TREE, instance, DECL_NAME (callop), NULL_TREE); int nargs = list_length (DECL_ARGUMENTS (callop)) - 1; call = prepare_op_call (objfn, nargs); if (type_uses_auto (fn_result)) decltype_call = prepare_op_call (objfn, nargs); } else { direct_argvec = make_tree_vector (); direct_argvec->quick_push (build1 (NOP_EXPR, TREE_TYPE (DECL_ARGUMENTS (callop)), null_pointer_node)); } /* Copy CALLOP's argument list (as per 'copy_list') as FN_ARGS in order to declare the static member function "_FUN" below. For each arg append to DIRECT_ARGVEC (for the non-template case) or populate the pre-allocated call args (for the template case). If a parameter pack is found, expand it, flagging it as PACK_EXPANSION_LOCAL_P for the body call. */ tree fn_args = NULL_TREE; { int ix = 0; tree src = DECL_CHAIN (DECL_ARGUMENTS (callop)); tree tgt; while (src) { tree new_node = copy_node (src); if (!fn_args) fn_args = tgt = new_node; else { TREE_CHAIN (tgt) = new_node; tgt = new_node; } mark_exp_read (tgt); if (generic_lambda_p) { if (DECL_PACK_P (tgt)) { tree a = make_pack_expansion (tgt); if (decltype_call) CALL_EXPR_ARG (decltype_call, ix) = copy_node (a); PACK_EXPANSION_LOCAL_P (a) = true; CALL_EXPR_ARG (call, ix) = a; } else { tree a = convert_from_reference (tgt); CALL_EXPR_ARG (call, ix) = a; if (decltype_call) CALL_EXPR_ARG (decltype_call, ix) = copy_node (a); } ++ix; } else vec_safe_push (direct_argvec, tgt); src = TREE_CHAIN (src); } } if (generic_lambda_p) { if (decltype_call) { ++processing_template_decl; fn_result = finish_decltype_type (decltype_call, /*id_expression_or_member_access_p=*/false, tf_warning_or_error); --processing_template_decl; } } else call = build_call_a (callop, direct_argvec->length (), direct_argvec->address ()); CALL_FROM_THUNK_P (call) = 1; tree stattype = build_function_type (fn_result, FUNCTION_ARG_CHAIN (callop)); /* First build up the conversion op. */ tree rettype = build_pointer_type (stattype); tree name = mangle_conv_op_name_for_type (rettype); tree thistype = cp_build_qualified_type (type, TYPE_QUAL_CONST); tree fntype = build_method_type_directly (thistype, rettype, void_list_node); tree convfn = build_lang_decl (FUNCTION_DECL, name, fntype); tree fn = convfn; DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop); if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn && DECL_ALIGN (fn) < 2 * BITS_PER_UNIT) DECL_ALIGN (fn) = 2 * BITS_PER_UNIT; SET_OVERLOADED_OPERATOR_CODE (fn, TYPE_EXPR); grokclassfn (type, fn, NO_SPECIAL); set_linkage_according_to_type (type, fn); rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof); DECL_IN_AGGR_P (fn) = 1; DECL_ARTIFICIAL (fn) = 1; DECL_NOT_REALLY_EXTERN (fn) = 1; DECL_DECLARED_INLINE_P (fn) = 1; DECL_ARGUMENTS (fn) = build_this_parm (fntype, TYPE_QUAL_CONST); if (nested_def) DECL_INTERFACE_KNOWN (fn) = 1; if (generic_lambda_p) fn = add_inherited_template_parms (fn, DECL_TI_TEMPLATE (callop)); add_method (type, fn, NULL_TREE); /* Generic thunk code fails for varargs; we'll complain in mark_used if the conversion op is used. */ if (varargs_function_p (callop)) { DECL_DELETED_FN (fn) = 1; return; } /* Now build up the thunk to be returned. */ name = get_identifier ("_FUN"); tree statfn = build_lang_decl (FUNCTION_DECL, name, stattype); fn = statfn; DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop); if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn && DECL_ALIGN (fn) < 2 * BITS_PER_UNIT) DECL_ALIGN (fn) = 2 * BITS_PER_UNIT; grokclassfn (type, fn, NO_SPECIAL); set_linkage_according_to_type (type, fn); rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof); DECL_IN_AGGR_P (fn) = 1; DECL_ARTIFICIAL (fn) = 1; DECL_NOT_REALLY_EXTERN (fn) = 1; DECL_DECLARED_INLINE_P (fn) = 1; DECL_STATIC_FUNCTION_P (fn) = 1; DECL_ARGUMENTS (fn) = fn_args; for (tree arg = fn_args; arg; arg = DECL_CHAIN (arg)) { /* Avoid duplicate -Wshadow warnings. */ DECL_NAME (arg) = NULL_TREE; DECL_CONTEXT (arg) = fn; } if (nested_def) DECL_INTERFACE_KNOWN (fn) = 1; if (generic_lambda_p) fn = add_inherited_template_parms (fn, DECL_TI_TEMPLATE (callop)); add_method (type, fn, NULL_TREE); if (nested) push_function_context (); else /* Still increment function_depth so that we don't GC in the middle of an expression. */ ++function_depth; /* Generate the body of the thunk. */ start_preparsed_function (statfn, NULL_TREE, SF_PRE_PARSED | SF_INCLASS_INLINE); if (DECL_ONE_ONLY (statfn)) { /* Put the thunk in the same comdat group as the call op. */ cgraph_node::get_create (statfn)->add_to_same_comdat_group (cgraph_node::get_create (callop)); } tree body = begin_function_body (); tree compound_stmt = begin_compound_stmt (0); if (!generic_lambda_p) { set_flags_from_callee (call); if (MAYBE_CLASS_TYPE_P (TREE_TYPE (call))) call = build_cplus_new (TREE_TYPE (call), call, tf_warning_or_error); } call = convert_from_reference (call); finish_return_stmt (call); finish_compound_stmt (compound_stmt); finish_function_body (body); fn = finish_function (/*inline*/2); if (!generic_lambda_p) expand_or_defer_fn (fn); /* Generate the body of the conversion op. */ start_preparsed_function (convfn, NULL_TREE, SF_PRE_PARSED | SF_INCLASS_INLINE); body = begin_function_body (); compound_stmt = begin_compound_stmt (0); /* decl_needed_p needs to see that it's used. */ TREE_USED (statfn) = 1; finish_return_stmt (decay_conversion (statfn, tf_warning_or_error)); finish_compound_stmt (compound_stmt); finish_function_body (body); fn = finish_function (/*inline*/2); if (!generic_lambda_p) expand_or_defer_fn (fn); if (nested) pop_function_context (); else --function_depth; }
void print_node (FILE *file, const char *prefix, tree node, int indent) { int hash; struct bucket *b; machine_mode mode; enum tree_code_class tclass; int len; int i; expanded_location xloc; enum tree_code code; if (node == 0) return; code = TREE_CODE (node); tclass = TREE_CODE_CLASS (code); /* Don't get too deep in nesting. If the user wants to see deeper, it is easy to use the address of a lowest-level node as an argument in another call to debug_tree. */ if (indent > 24) { print_node_brief (file, prefix, node, indent); return; } if (indent > 8 && (tclass == tcc_type || tclass == tcc_declaration)) { print_node_brief (file, prefix, node, indent); return; } /* It is unsafe to look at any other fields of an ERROR_MARK node. */ if (code == ERROR_MARK) { print_node_brief (file, prefix, node, indent); return; } /* Allow this function to be called if the table is not there. */ if (table) { hash = ((uintptr_t) node) % HASH_SIZE; /* If node is in the table, just mention its address. */ for (b = table[hash]; b; b = b->next) if (b->node == node) { print_node_brief (file, prefix, node, indent); return; } /* Add this node to the table. */ b = XNEW (struct bucket); b->node = node; b->next = table[hash]; table[hash] = b; } /* Indent to the specified column, since this is the long form. */ indent_to (file, indent); /* Print the slot this node is in, and its code, and address. */ fprintf (file, "%s <%s", prefix, get_tree_code_name (code)); dump_addr (file, " ", node); /* Print the name, if any. */ if (tclass == tcc_declaration) { if (DECL_NAME (node)) fprintf (file, " %s", IDENTIFIER_POINTER (DECL_NAME (node))); else if (code == LABEL_DECL && LABEL_DECL_UID (node) != -1) { if (dump_flags & TDF_NOUID) fprintf (file, " L.xxxx"); else fprintf (file, " L.%d", (int) LABEL_DECL_UID (node)); } else { if (dump_flags & TDF_NOUID) fprintf (file, " %c.xxxx", code == CONST_DECL ? 'C' : 'D'); else fprintf (file, " %c.%u", code == CONST_DECL ? 'C' : 'D', DECL_UID (node)); } } else if (tclass == tcc_type) { if (TYPE_NAME (node)) { if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE) fprintf (file, " %s", IDENTIFIER_POINTER (TYPE_NAME (node))); else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL && DECL_NAME (TYPE_NAME (node))) fprintf (file, " %s", IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node)))); } } if (code == IDENTIFIER_NODE) fprintf (file, " %s", IDENTIFIER_POINTER (node)); if (code == INTEGER_CST) { if (indent <= 4) print_node_brief (file, "type", TREE_TYPE (node), indent + 4); } else if (CODE_CONTAINS_STRUCT (code, TS_TYPED)) { print_node (file, "type", TREE_TYPE (node), indent + 4); if (TREE_TYPE (node)) indent_to (file, indent + 3); } if (!TYPE_P (node) && TREE_SIDE_EFFECTS (node)) fputs (" side-effects", file); if (TYPE_P (node) ? TYPE_READONLY (node) : TREE_READONLY (node)) fputs (" readonly", file); if (TYPE_P (node) && TYPE_ATOMIC (node)) fputs (" atomic", file); if (!TYPE_P (node) && TREE_CONSTANT (node)) fputs (" constant", file); else if (TYPE_P (node) && TYPE_SIZES_GIMPLIFIED (node)) fputs (" sizes-gimplified", file); if (TYPE_P (node) && !ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (node))) fprintf (file, " address-space-%d", TYPE_ADDR_SPACE (node)); if (TREE_ADDRESSABLE (node)) fputs (" addressable", file); if (TREE_THIS_VOLATILE (node)) fputs (" volatile", file); if (TREE_ASM_WRITTEN (node)) fputs (" asm_written", file); if (TREE_USED (node)) fputs (" used", file); if (TREE_NOTHROW (node)) fputs (" nothrow", file); if (TREE_PUBLIC (node)) fputs (" public", file); if (TREE_PRIVATE (node)) fputs (" private", file); if (TREE_PROTECTED (node)) fputs (" protected", file); if (TREE_STATIC (node)) fputs (code == CALL_EXPR ? " must-tail-call" : " static", file); if (TREE_DEPRECATED (node)) fputs (" deprecated", file); if (TREE_VISITED (node)) fputs (" visited", file); if (code != TREE_VEC && code != INTEGER_CST && code != SSA_NAME) { if (TREE_LANG_FLAG_0 (node)) fputs (" tree_0", file); if (TREE_LANG_FLAG_1 (node)) fputs (" tree_1", file); if (TREE_LANG_FLAG_2 (node)) fputs (" tree_2", file); if (TREE_LANG_FLAG_3 (node)) fputs (" tree_3", file); if (TREE_LANG_FLAG_4 (node)) fputs (" tree_4", file); if (TREE_LANG_FLAG_5 (node)) fputs (" tree_5", file); if (TREE_LANG_FLAG_6 (node)) fputs (" tree_6", file); } /* DECL_ nodes have additional attributes. */ switch (TREE_CODE_CLASS (code)) { case tcc_declaration: if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) { if (DECL_UNSIGNED (node)) fputs (" unsigned", file); if (DECL_IGNORED_P (node)) fputs (" ignored", file); if (DECL_ABSTRACT_P (node)) fputs (" abstract", file); if (DECL_EXTERNAL (node)) fputs (" external", file); if (DECL_NONLOCAL (node)) fputs (" nonlocal", file); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)) { if (DECL_WEAK (node)) fputs (" weak", file); if (DECL_IN_SYSTEM_HEADER (node)) fputs (" in_system_header", file); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL) && code != LABEL_DECL && code != FUNCTION_DECL && DECL_REGISTER (node)) fputs (" regdecl", file); if (code == TYPE_DECL && TYPE_DECL_SUPPRESS_DEBUG (node)) fputs (" suppress-debug", file); if (code == FUNCTION_DECL && DECL_FUNCTION_SPECIFIC_TARGET (node)) fputs (" function-specific-target", file); if (code == FUNCTION_DECL && DECL_FUNCTION_SPECIFIC_OPTIMIZATION (node)) fputs (" function-specific-opt", file); if (code == FUNCTION_DECL && DECL_DECLARED_INLINE_P (node)) fputs (" autoinline", file); if (code == FUNCTION_DECL && DECL_BUILT_IN (node)) fputs (" built-in", file); if (code == FUNCTION_DECL && DECL_STATIC_CHAIN (node)) fputs (" static-chain", file); if (TREE_CODE (node) == FUNCTION_DECL && decl_is_tm_clone (node)) fputs (" tm-clone", file); if (code == FIELD_DECL && DECL_PACKED (node)) fputs (" packed", file); if (code == FIELD_DECL && DECL_BIT_FIELD (node)) fputs (" bit-field", file); if (code == FIELD_DECL && DECL_NONADDRESSABLE_P (node)) fputs (" nonaddressable", file); if (code == LABEL_DECL && EH_LANDING_PAD_NR (node)) fprintf (file, " landing-pad:%d", EH_LANDING_PAD_NR (node)); if (code == VAR_DECL && DECL_IN_TEXT_SECTION (node)) fputs (" in-text-section", file); if (code == VAR_DECL && DECL_IN_CONSTANT_POOL (node)) fputs (" in-constant-pool", file); if (code == VAR_DECL && DECL_COMMON (node)) fputs (" common", file); if (code == VAR_DECL && DECL_THREAD_LOCAL_P (node)) { fputs (" ", file); fputs (tls_model_names[DECL_TLS_MODEL (node)], file); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) { if (DECL_VIRTUAL_P (node)) fputs (" virtual", file); if (DECL_PRESERVE_P (node)) fputs (" preserve", file); if (DECL_LANG_FLAG_0 (node)) fputs (" decl_0", file); if (DECL_LANG_FLAG_1 (node)) fputs (" decl_1", file); if (DECL_LANG_FLAG_2 (node)) fputs (" decl_2", file); if (DECL_LANG_FLAG_3 (node)) fputs (" decl_3", file); if (DECL_LANG_FLAG_4 (node)) fputs (" decl_4", file); if (DECL_LANG_FLAG_5 (node)) fputs (" decl_5", file); if (DECL_LANG_FLAG_6 (node)) fputs (" decl_6", file); if (DECL_LANG_FLAG_7 (node)) fputs (" decl_7", file); mode = DECL_MODE (node); fprintf (file, " %s", GET_MODE_NAME (mode)); } if ((code == VAR_DECL || code == PARM_DECL || code == RESULT_DECL) && DECL_BY_REFERENCE (node)) fputs (" passed-by-reference", file); if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS) && DECL_DEFER_OUTPUT (node)) fputs (" defer-output", file); xloc = expand_location (DECL_SOURCE_LOCATION (node)); fprintf (file, " file %s line %d col %d", xloc.file, xloc.line, xloc.column); if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) { print_node (file, "size", DECL_SIZE (node), indent + 4); print_node (file, "unit size", DECL_SIZE_UNIT (node), indent + 4); if (code != FUNCTION_DECL || DECL_BUILT_IN (node)) indent_to (file, indent + 3); if (DECL_USER_ALIGN (node)) fprintf (file, " user"); fprintf (file, " align %d", DECL_ALIGN (node)); if (code == FIELD_DECL) fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED, DECL_OFFSET_ALIGN (node)); if (code == FUNCTION_DECL && DECL_BUILT_IN (node)) { if (DECL_BUILT_IN_CLASS (node) == BUILT_IN_MD) fprintf (file, " built-in BUILT_IN_MD %d", DECL_FUNCTION_CODE (node)); else fprintf (file, " built-in %s:%s", built_in_class_names[(int) DECL_BUILT_IN_CLASS (node)], built_in_names[(int) DECL_FUNCTION_CODE (node)]); } } if (code == FIELD_DECL) { print_node (file, "offset", DECL_FIELD_OFFSET (node), indent + 4); print_node (file, "bit offset", DECL_FIELD_BIT_OFFSET (node), indent + 4); if (DECL_BIT_FIELD_TYPE (node)) print_node (file, "bit_field_type", DECL_BIT_FIELD_TYPE (node), indent + 4); } print_node_brief (file, "context", DECL_CONTEXT (node), indent + 4); if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) { print_node_brief (file, "attributes", DECL_ATTRIBUTES (node), indent + 4); if (code != PARM_DECL) print_node_brief (file, "initial", DECL_INITIAL (node), indent + 4); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL)) { print_node_brief (file, "abstract_origin", DECL_ABSTRACT_ORIGIN (node), indent + 4); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON)) { print_node (file, "result", DECL_RESULT_FLD (node), indent + 4); } lang_hooks.print_decl (file, node, indent); if (DECL_RTL_SET_P (node)) { indent_to (file, indent + 4); print_rtl (file, DECL_RTL (node)); } if (code == PARM_DECL) { print_node (file, "arg-type", DECL_ARG_TYPE (node), indent + 4); if (DECL_INCOMING_RTL (node) != 0) { indent_to (file, indent + 4); fprintf (file, "incoming-rtl "); print_rtl (file, DECL_INCOMING_RTL (node)); } } else if (code == FUNCTION_DECL && DECL_STRUCT_FUNCTION (node) != 0) { print_node (file, "arguments", DECL_ARGUMENTS (node), indent + 4); indent_to (file, indent + 4); dump_addr (file, "struct-function ", DECL_STRUCT_FUNCTION (node)); } if ((code == VAR_DECL || code == PARM_DECL) && DECL_HAS_VALUE_EXPR_P (node)) print_node (file, "value-expr", DECL_VALUE_EXPR (node), indent + 4); /* Print the decl chain only if decl is at second level. */ if (indent == 4) print_node (file, "chain", TREE_CHAIN (node), indent + 4); else print_node_brief (file, "chain", TREE_CHAIN (node), indent + 4); break; case tcc_type: if (TYPE_UNSIGNED (node)) fputs (" unsigned", file); if (TYPE_NO_FORCE_BLK (node)) fputs (" no-force-blk", file); if (TYPE_STRING_FLAG (node)) fputs (" string-flag", file); if (TYPE_NEEDS_CONSTRUCTING (node)) fputs (" needs-constructing", file); if ((code == RECORD_TYPE || code == UNION_TYPE || code == QUAL_UNION_TYPE || code == ARRAY_TYPE) && TYPE_REVERSE_STORAGE_ORDER (node)) fputs (" reverse-storage-order", file); /* The transparent-union flag is used for different things in different nodes. */ if ((code == UNION_TYPE || code == RECORD_TYPE) && TYPE_TRANSPARENT_AGGR (node)) fputs (" transparent-aggr", file); else if (code == ARRAY_TYPE && TYPE_NONALIASED_COMPONENT (node)) fputs (" nonaliased-component", file); if (TYPE_PACKED (node)) fputs (" packed", file); if (TYPE_RESTRICT (node)) fputs (" restrict", file); if (TYPE_LANG_FLAG_0 (node)) fputs (" type_0", file); if (TYPE_LANG_FLAG_1 (node)) fputs (" type_1", file); if (TYPE_LANG_FLAG_2 (node)) fputs (" type_2", file); if (TYPE_LANG_FLAG_3 (node)) fputs (" type_3", file); if (TYPE_LANG_FLAG_4 (node)) fputs (" type_4", file); if (TYPE_LANG_FLAG_5 (node)) fputs (" type_5", file); if (TYPE_LANG_FLAG_6 (node)) fputs (" type_6", file); if (TYPE_LANG_FLAG_7 (node)) fputs (" type_7", file); mode = TYPE_MODE (node); fprintf (file, " %s", GET_MODE_NAME (mode)); print_node (file, "size", TYPE_SIZE (node), indent + 4); print_node (file, "unit size", TYPE_SIZE_UNIT (node), indent + 4); indent_to (file, indent + 3); if (TYPE_USER_ALIGN (node)) fprintf (file, " user"); fprintf (file, " align %d symtab %d alias set " HOST_WIDE_INT_PRINT_DEC, TYPE_ALIGN (node), TYPE_SYMTAB_ADDRESS (node), (HOST_WIDE_INT) TYPE_ALIAS_SET (node)); if (TYPE_STRUCTURAL_EQUALITY_P (node)) fprintf (file, " structural equality"); else dump_addr (file, " canonical type ", TYPE_CANONICAL (node)); print_node (file, "attributes", TYPE_ATTRIBUTES (node), indent + 4); if (INTEGRAL_TYPE_P (node) || code == REAL_TYPE || code == FIXED_POINT_TYPE) { fprintf (file, " precision %d", TYPE_PRECISION (node)); print_node_brief (file, "min", TYPE_MIN_VALUE (node), indent + 4); print_node_brief (file, "max", TYPE_MAX_VALUE (node), indent + 4); } if (code == ENUMERAL_TYPE) print_node (file, "values", TYPE_VALUES (node), indent + 4); else if (code == ARRAY_TYPE) print_node (file, "domain", TYPE_DOMAIN (node), indent + 4); else if (code == VECTOR_TYPE) fprintf (file, " nunits %d", (int) TYPE_VECTOR_SUBPARTS (node)); else if (code == RECORD_TYPE || code == UNION_TYPE || code == QUAL_UNION_TYPE) print_node (file, "fields", TYPE_FIELDS (node), indent + 4); else if (code == FUNCTION_TYPE || code == METHOD_TYPE) { if (TYPE_METHOD_BASETYPE (node)) print_node_brief (file, "method basetype", TYPE_METHOD_BASETYPE (node), indent + 4); print_node (file, "arg-types", TYPE_ARG_TYPES (node), indent + 4); } else if (code == OFFSET_TYPE) print_node_brief (file, "basetype", TYPE_OFFSET_BASETYPE (node), indent + 4); if (TYPE_CONTEXT (node)) print_node_brief (file, "context", TYPE_CONTEXT (node), indent + 4); lang_hooks.print_type (file, node, indent); if (TYPE_POINTER_TO (node) || TREE_CHAIN (node)) indent_to (file, indent + 3); print_node_brief (file, "pointer_to_this", TYPE_POINTER_TO (node), indent + 4); print_node_brief (file, "reference_to_this", TYPE_REFERENCE_TO (node), indent + 4); print_node_brief (file, "chain", TREE_CHAIN (node), indent + 4); break; case tcc_expression: case tcc_comparison: case tcc_unary: case tcc_binary: case tcc_reference: case tcc_statement: case tcc_vl_exp: if (code == BIND_EXPR) { print_node (file, "vars", TREE_OPERAND (node, 0), indent + 4); print_node (file, "body", TREE_OPERAND (node, 1), indent + 4); print_node (file, "block", TREE_OPERAND (node, 2), indent + 4); break; } if (code == CALL_EXPR) { call_expr_arg_iterator iter; tree arg; print_node (file, "fn", CALL_EXPR_FN (node), indent + 4); print_node (file, "static_chain", CALL_EXPR_STATIC_CHAIN (node), indent + 4); i = 0; FOR_EACH_CALL_EXPR_ARG (arg, iter, node) { char temp[10]; sprintf (temp, "arg %d", i); print_node (file, temp, arg, indent + 4); i++; } }
static void tree_nrv (void) { tree result = DECL_RESULT (current_function_decl); tree result_type = TREE_TYPE (result); tree found = NULL; basic_block bb; block_stmt_iterator bsi; struct nrv_data data; /* If this function does not return an aggregate type in memory, then there is nothing to do. */ if (!aggregate_value_p (result, current_function_decl)) return; /* Look through each block for assignments to the RESULT_DECL. */ FOR_EACH_BB (bb) { for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) { tree stmt = bsi_stmt (bsi); tree ret_expr; if (TREE_CODE (stmt) == RETURN_EXPR) { /* In a function with an aggregate return value, the gimplifier has changed all non-empty RETURN_EXPRs to return the RESULT_DECL. */ ret_expr = TREE_OPERAND (stmt, 0); if (ret_expr) gcc_assert (ret_expr == result); } else if (TREE_CODE (stmt) == MODIFY_EXPR && TREE_OPERAND (stmt, 0) == result) { ret_expr = TREE_OPERAND (stmt, 1); /* Now verify that this return statement uses the same value as any previously encountered return statement. */ if (found != NULL) { /* If we found a return statement using a different variable than previous return statements, then we can not perform NRV optimizations. */ if (found != ret_expr) return; } else found = ret_expr; /* The returned value must be a local automatic variable of the same type and alignment as the function's result. */ if (TREE_CODE (found) != VAR_DECL || TREE_THIS_VOLATILE (found) || DECL_CONTEXT (found) != current_function_decl || TREE_STATIC (found) || TREE_ADDRESSABLE (found) || DECL_ALIGN (found) > DECL_ALIGN (result) || !lang_hooks.types_compatible_p (TREE_TYPE (found), result_type)) return; } } } if (!found) return; /* If dumping details, then note once and only the NRV replacement. */ if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "NRV Replaced: "); print_generic_expr (dump_file, found, dump_flags); fprintf (dump_file, " with: "); print_generic_expr (dump_file, result, dump_flags); fprintf (dump_file, "\n"); } /* At this point we know that all the return statements return the same local which has suitable attributes for NRV. Copy debugging information from FOUND to RESULT. */ DECL_NAME (result) = DECL_NAME (found); DECL_SOURCE_LOCATION (result) = DECL_SOURCE_LOCATION (found); DECL_ABSTRACT_ORIGIN (result) = DECL_ABSTRACT_ORIGIN (found); TREE_ADDRESSABLE (result) = TREE_ADDRESSABLE (found); /* Now walk through the function changing all references to VAR to be RESULT. */ data.var = found; data.result = result; FOR_EACH_BB (bb) { for (bsi = bsi_start (bb); !bsi_end_p (bsi); ) { tree *tp = bsi_stmt_ptr (bsi); /* If this is a copy from VAR to RESULT, remove it. */ if (TREE_CODE (*tp) == MODIFY_EXPR && TREE_OPERAND (*tp, 0) == result && TREE_OPERAND (*tp, 1) == found) bsi_remove (&bsi); else { walk_tree (tp, finalize_nrv_r, &data, 0); bsi_next (&bsi); } } } /* FOUND is no longer used. Ensure it gets removed. */ var_ann (found)->used = 0; }
static unsigned int tree_profiling (void) { struct cgraph_node *node; /* This is a small-ipa pass that gets called only once, from cgraphunit.c:ipa_passes(). */ gcc_assert (symtab->state == IPA_SSA); init_node_map (true); FOR_EACH_DEFINED_FUNCTION (node) { if (!gimple_has_body_p (node->decl)) continue; /* Don't profile functions produced for builtin stuff. */ if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION) continue; /* Do not instrument extern inline functions when testing coverage. While this is not perfectly consistent (early inlined extern inlines will get acocunted), testsuite expects that. */ if (DECL_EXTERNAL (node->decl) && flag_test_coverage) continue; push_cfun (DECL_STRUCT_FUNCTION (node->decl)); /* Local pure-const may imply need to fixup the cfg. */ if (execute_fixup_cfg () & TODO_cleanup_cfg) cleanup_tree_cfg (); branch_prob (); if (! flag_branch_probabilities && flag_profile_values) gimple_gen_ic_func_profiler (); if (flag_branch_probabilities && flag_profile_values && flag_value_profile_transformations) gimple_value_profile_transformations (); /* The above could hose dominator info. Currently there is none coming in, this is a safety valve. It should be easy to adjust it, if and when there is some. */ free_dominance_info (CDI_DOMINATORS); free_dominance_info (CDI_POST_DOMINATORS); pop_cfun (); } /* Drop pure/const flags from instrumented functions. */ FOR_EACH_DEFINED_FUNCTION (node) { if (!gimple_has_body_p (node->decl) || !(!node->clone_of || node->decl != node->clone_of->decl)) continue; /* Don't profile functions produced for builtin stuff. */ if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION) continue; node->set_const_flag (false, false); node->set_pure_flag (false, false); } /* Update call statements and rebuild the cgraph. */ FOR_EACH_DEFINED_FUNCTION (node) { basic_block bb; if (!gimple_has_body_p (node->decl) || !(!node->clone_of || node->decl != node->clone_of->decl)) continue; /* Don't profile functions produced for builtin stuff. */ if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION) continue; push_cfun (DECL_STRUCT_FUNCTION (node->decl)); FOR_EACH_BB_FN (bb, cfun) { gimple_stmt_iterator gsi; for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple stmt = gsi_stmt (gsi); if (is_gimple_call (stmt)) update_stmt (stmt); } } /* re-merge split blocks. */ cleanup_tree_cfg (); update_ssa (TODO_update_ssa); cgraph_edge::rebuild_edges (); pop_cfun (); }