b5b8b0ac64
gcc/ChangeLog:
* doc/invoke.texi (-fvar-tracking-assignments): New.
(-fvar-tracking-assignments-toggle): New.
(-fdump-final-insns=file): Mark filename as optional.
(--param min-nondebug-insn-uid): New.
(-gdwarf-@{version}): Mention version 4.
* opts.c (common_handle_option): Accept it.
* tree-vrp.c (find_assert_locations_1): Skip debug stmts.
* regrename.c (regrename_optimize): Drop last. Don't count debug
insns as uses. Don't reject change because of debug insn.
(do_replace): Reject DEBUG_INSN as chain starter. Take base_regno
from the chain starter, and check for inexact matches in
DEBUG_INSNS.
(scan_rtx_reg): Accept inexact matches in DEBUG_INSNs.
(build_def_use): Simplify and fix the marking of DEBUG_INSNs.
* sched-ebb.c (schedule_ebbs): Skip boundary debug insns.
* fwprop.c (forward_propagate_and_simplify): ...into debug insns.
* doc/gimple.texi (is_gimple_debug): New.
(gimple_debug_bind_p): New.
(is_gimple_call, gimple_assign_cast_p): End sentence with period.
* doc/install.texi (bootstrap-debug): More details.
(bootstrap-debug-big, bootstrap-debug-lean): Document.
(bootstrap-debug-lib): More details.
(bootstrap-debug-ckovw): Update.
(bootstrap-time): New.
* tree-into-ssa.c (mark_def_sites): Skip debug stmts.
(insert_phi_nodes_for): Insert debug stmts.
(rewrite_stmt): Take iterator. Insert debug stmts.
(rewrite_enter_block): Adjust.
(maybe_replace_use_in_debug_stmt): New.
(rewrite_update_stmt): Use it.
(mark_use_interesting): Return early for debug stmts.
* tree-ssa-loop-im.c (rewrite_bittest): Propagate DEFs into debug
stmts before replacing stmt.
(move_computations_stmt): Likewise.
* ira-conflicts.c (add_copies): Skip debug insns.
* regstat.c (regstat_init_n_sets_and_refs): Discount debug insns.
(regstat_bb_compute_ri): Skip debug insns.
* tree-ssa-threadupdate.c (redirection_block_p): Skip debug stmts.
* tree-ssa-loop-manip.c (find_uses_to_rename_stmt,
check_loop_closed_ssa_stmt): Skip debug stmts.
* tree-tailcall.c (find_tail_calls): Likewise.
* tree-ssa-loop-ch.c (should_duplicate_loop_header_p): Likewise.
* tree.h (MAY_HAVE_DEBUG_STMTS): New.
(build_var_debug_value_stat): Declare.
(build_var_debug_value): Define.
(target_for_debug_bind): Declare.
* reload.c (find_equiv_reg): Skip debug insns.
* rtlanal.c (reg_used_between_p): Skip debug insns.
(side_effects_p): Likewise.
(canonicalize_condition): Likewise.
* ddg.c (create_ddg_dep_from_intra_loop_link): Check that non-debug
insns never depend on debug insns.
(create_ddg_dep_no_link): Likewise.
(add_cross_iteration_register_deps): Use ANTI_DEP for debug insns.
Don't add inter-loop dependencies for debug insns.
(build_intra_loop_deps): Likewise.
(create_ddg): Count debug insns.
* ddg.h (struct ddg::num_debug): New.
(num_backargs): Pair up with previous int field.
* diagnostic.c (diagnostic_report_diagnostic): Skip notes on
-fcompare-debug-second.
* final.c (get_attr_length_1): Skip debug insns.
(rest_of_clean-state): Don't dump CFA_RESTORE_STATE.
* gcc.c (invoke_as): Call compare-debug-dump-opt.
(driver_self_specs): Map -fdump-final-insns to
-fdump-final-insns=..
(get_local_tick): New.
(compare_debug_dump_opt_spec_function): Test for . argument and
compute output name. Compute temp output spec without flag name.
Compute -frandom-seed.
(OPT): Undef after use.
* cfgloopanal.c (num_loop_insns): Skip debug insns.
(average_num_loop_insns): Likewise.
* params.h (MIN_NONDEBUG_INSN_UID): New.
* gimple.def (GIMPLE_DEBUG): New.
* ipa-reference.c (scan_stmt_for_static_refs): Skip debug stmts.
* auto-inc-dec.c (merge_in_block): Skip debug insns.
(merge_in_block): Fix whitespace.
* toplev.c (flag_var_tracking): Update comment.
(flag_var_tracking_assignments): New.
(flag_var_tracking_assignments_toggle): New.
(process_options): Don't open final insns dump file if we're not
going to write to it. Compute defaults for var_tracking.
* df-scan.c (df_insn_rescan_debug_internal): New.
(df_uses_record): Handle debug insns.
* haifa-sched.c (ready): Initialize n_debug.
(contributes_to_priority): Skip debug insns.
(dep_list_size): New.
(priority): Use it.
(rank_for_schedule): Likewise. Schedule debug insns as soon as
they're ready. Disregard previous debug insns to make decisions.
(queue_insn): Never queue debug insns.
(ready_add, ready_remove_first, ready_remove): Count debug insns.
(schedule_insn): Don't reject debug insns because of issue rate.
(get_ebb_head_tail, no_real_insns_p): Skip boundary debug insns.
(queue_to_ready): Skip and discount debug insns.
(choose_ready): Let debug insns through.
(schedule_block): Check boundary debug insns. Discount debug
insns, schedule them early. Adjust whitespace.
(set_priorities): Check for boundary debug insns.
(add_jump_dependencies): Use dep_list_size.
(prev_non_location_insn): New.
(check_cfg): Use it.
* tree-ssa-loop-ivopts.c (find-interesting_users): Skip debug
stmts.
(remove_unused_ivs): Reset debug stmts.
* modulo-sched.c (const_iteration_count): Skip debug insns.
(res_MII): Discount debug insns.
(loop_single_full_bb_p): Skip debug insns.
(sms_schedule): Likewise.
(sms_schedule_by_order): Likewise.
(ps_has_conflicts): Likewise.
* caller-save.c (refmarker_fn): New.
(save_call_clobbered_regs): Replace regs with saved mem in
debug insns.
(mark_referenced_regs): Take pointer, mark and arg. Adjust.
Call refmarker_fn mark for hardregnos.
(mark_reg_as_referenced): New.
(replace_reg_with_saved_mem): New.
* ipa-pure-const.c (check_stmt): Skip debug stmts.
* cse.c (cse_insn): Canonicalize debug insns. Skip them when
searching back.
(cse_extended_basic_block): Skip debug insns.
(count_reg_usage): Likewise.
(is_dead_reg): New, split out of...
(set_live_p): ... here.
(insn_live_p): Use it for debug insns.
* tree-stdarg.c (check_all_va_list_escapes): Skip debug stmts.
(execute_optimize_stdarg): Likewise.
* tree-ssa-dom.c (propagate_rhs_into_lhs): Likewise.
* tree-ssa-propagate.c (substitute_and_fold): Don't regard
changes in debug stmts as changes.
* sel-sched.c (moving_insn_creates_bookkeeping_block_p): New.
(moveup_expr): Don't move across debug insns. Don't move
debug insn if it would create a bookkeeping block.
(moveup_expr_cached): Don't use cache for debug insns that
are heads of blocks.
(compute_av_set_inside_bb): Skip debug insns.
(sel_rank_for_schedule): Schedule debug insns first. Remove
dead code.
(block_valid_for_bookkeeping_p); Support lax searches.
(create_block_for_bookkeeping): Adjust block numbers when
encountering debug-only blocks.
(find_place_for_bookkeeping): Deal with debug-only blocks.
(generate_bookkeeping_insn): Accept no place to insert.
(remove_temp_moveop_nops): New argument full_tidying.
(prepare_place_to_insert): Deal with debug insns.
(advance_state_on_fence): Debug insns don't start cycles.
(update_boundaries): Take fence as argument. Deal with
debug insns.
(schedule_expr_on_boundary): No full_tidying on debug insns.
(fill_insns): Deal with debug insns.
(track_scheduled_insns_and_blocks): Don't count debug insns.
(need_nop_to_preserve_insn_bb): New, split out of...
(remove_insn_from_stream): ... this.
(fur_orig_expr_not_found): Skip debug insns.
* rtl.def (VALUE): Move up.
(DEBUG_INSN): New.
* tree-ssa-sink.c (all_immediate_uses_same_place): Skip debug
stmts.
(nearest_common_dominator_of_uses): Take debug_stmts argument.
Set it if debug stmts are found.
(statement_sink_location): Skip debug stmts. Propagate
moving defs into debug stmts.
* ifcvt.c (first_active_insn): Skip debug insns.
(last_active_insns): Likewise.
(cond_exec_process_insns): Likewise.
(noce_process_if_block): Likewise.
(check_cond_move_block): Likewise.
(cond_move_convert_if_block): Likewise.
(block_jumps_and_fallthru_p): Likewise.
(dead_or_predicable): Likewise.
* dwarf2out.c (debug_str_hash_forced): New.
(find_AT_string): Add comment.
(gen_label_for_indirect_string): New.
(get_debug_string_label): New.
(AT_string_form): Use it.
(mem_loc_descriptor): Handle non-TLS symbols. Handle MINUS , DIV,
MOD, AND, IOR, XOR, NOT, ABS, NEG, and CONST_STRING. Accept but
discard COMPARE, IF_THEN_ELSE, ROTATE, ROTATERT, TRUNCATE and
several operations that cannot be represented with DWARF opcodes.
(loc_descriptor): Ignore SIGN_EXTEND and ZERO_EXTEND. Require
dwarf_version 4 for DW_OP_implicit_value and DW_OP_stack_value.
(dwarf2out_var_location): Take during-call mark into account.
(output_indirect_string): Update comment. Output if there are
label and references.
(prune_indirect_string): New.
(prune_unused_types): Call it if debug_str_hash_forced.
More in dwarf2out.c, from Jakub Jelinek <jakub@redhat.com>:
(dw_long_long_const): Remove.
(struct dw_val_struct): Change val_long_long type to rtx.
(print_die, attr_checksum, same_dw_val_p, loc_descriptor): Adjust for
val_long_long change to CONST_DOUBLE rtx from a long hi/lo pair.
(output_die): Likewise. Use HOST_BITS_PER_WIDE_INT size of each
component instead of HOST_BITS_PER_LONG.
(output_loc_operands): Likewise. For const8* assert
HOST_BITS_PER_WIDE_INT rather than HOST_BITS_PER_LONG is >= 64.
(output_loc_operands_raw): For const8* assert HOST_BITS_PER_WIDE_INT
rather than HOST_BITS_PER_LONG is >= 64.
(add_AT_long_long): Remove val_hi and val_lo arguments, add
val_const_double.
(size_of_die): Use HOST_BITS_PER_WIDE_INT size multiplier instead of
HOST_BITS_PER_LONG for dw_val_class_long_long.
(add_const_value_attribute): Adjust add_AT_long_long caller. Don't
handle TLS SYMBOL_REFs. If CONST wraps a constant, tail recurse.
(dwarf_stack_op_name): Handle DW_OP_implicit_value and
DW_OP_stack_value.
(size_of_loc_descr, output_loc_operands, output_loc_operands_raw):
Handle DW_OP_implicit_value.
(extract_int): Move prototype earlier.
(mem_loc_descriptor): For SUBREG punt if inner
mode size is wider than DWARF2_ADDR_SIZE. Handle SIGN_EXTEND
and ZERO_EXTEND by DW_OP_shl and DW_OP_shr{a,}. Handle
EQ, NE, GT, GE, LT, LE, GTU, GEU, LTU, LEU, SMIN, SMAX, UMIN,
UMAX, SIGN_EXTRACT, ZERO_EXTRACT.
(loc_descriptor): Compare mode size with DWARF2_ADDR_SIZE
instead of Pmode size.
(loc_descriptor): Add MODE argument. Handle CONST_INT, CONST_DOUBLE,
CONST_VECTOR, CONST, LABEL_REF and SYMBOL_REF if mode != VOIDmode,
attempt to handle other expressions. Don't handle TLS SYMBOL_REFs.
(concat_loc_descriptor, concatn_loc_descriptor,
loc_descriptor_from_tree_1): Adjust loc_descriptor callers.
(add_location_or_const_value_attribute): Likewise. For single
location loc_lists attempt to use add_const_value_attribute
for constant decls. Add DW_AT_const_value even if
NOTE_VAR_LOCATION is VAR_LOCATION with CONSTANT_P or CONST_STRING
in its expression.
* cfgbuild.c (inside_basic_block_p): Handle debug insns.
(control_flow_insn_p): Likewise.
* tree-parloops.c (eliminate_local_variables_stmt): Handle debug
stmt.
(separate_decls_in_region_debug_bind): New.
(separate_decls_in_region): Process debug bind stmts afterwards.
* recog.c (verify_changes): Handle debug insns.
(extract_insn): Likewise.
(peephole2_optimize): Skip debug insns.
* dse.c (scan_insn): Skip debug insns.
* sel-sched-ir.c (return_nop_to_pool): Take full_tidying argument.
Pass it on.
(setup_id_for_insn): Handle debug insns.
(maybe_tidy_empty_bb): Adjust whitespace.
(tidy_control_flow): Skip debug insns.
(sel_remove_insn): Adjust for debug insns.
(sel_estimate_number_of_insns): Skip debug insns.
(create_insn_rtx_from_pattern): Handle debug insns.
(create_copy_of_insn_rtx): Likewise.
* sel-sched-.h (sel_bb_end): Declare.
(sel_bb_empty_or_nop_p): New.
(get_all_loop_exits): Use it.
(_eligible_successor_edge_p): Likewise.
(return_nop_to_pool): Adjust.
* tree-eh.c (tre_empty_eh_handler_p): Skip debug stmts.
* ira-lives.c (process_bb_node_lives): Skip debug insns.
* gimple-pretty-print.c (dump_gimple_debug): New.
(dump_gimple_stmt): Use it.
(dump_bb_header): Skip gimple debug stmts.
* regmove.c (optimize_reg_copy_1): Discount debug insns.
(fixup_match_2): Likewise.
(regmove_backward_pass): Likewise. Simplify combined
replacement. Handle debug insns.
* function.c (instantiate_virtual_regs): Handle debug insns.
* function.h (struct emit_status): Add x_cur_debug_insn_uid.
* print-rtl.h: Include cselib.h.
(print_rtx): Print VALUEs. Split out and recurse for
VAR_LOCATIONs.
* df.h (df_inns_rescan_debug_internal): Declare.
* gcse.c (alloc_hash_table): Estimate n_insns.
(cprop_insn): Don't regard debug insns as changes.
(bypass_conditional_jumps): Skip debug insns.
(one_pre_gcse_pass): Adjust.
(one_code_hoisting_pass): Likewise.
(compute_ld_motion_mems): Skip debug insns.
(one_cprop_pass): Adjust.
* tree-if-conv.c (tree_if_convert_stmt): Reset debug stmts.
(if_convertible_stmt_p): Handle debug stmts.
* init-regs.c (initialize_uninitialized_regs): Skip debug insns.
* tree-vect-loop.c (vect_is_simple_reduction): Skip debug stmts.
* ira-build.c (create_bb_allocnos): Skip debug insns.
* tree-flow-inline.h (has_zero_uses): Discount debug stmts.
(has_single_use): Likewise.
(single_imm_use): Likewise.
(num_imm_uses): Likewise.
* tree-ssa-phiopt.c (empty_block_p): Skip debug stmts.
* tree-ssa-coalesce.c (build_ssa_conflict_graph): Skip debug stmts.
(create_outofssa_var_map): Likewise.
* lower-subreg.c (adjust_decomposed_uses): New.
(resolve_debug): New.
(decompose_multiword_subregs): Use it.
* tree-dfa.c (find_referenced_vars): Skip debug stmts.
* emit-rtl.c: Include params.h.
(cur_debug_insn_uid): Define.
(set_new_first_and_last_insn): Set cur_debug_insn_uid too.
(copy_rtx_if_shared_1): Handle debug insns.
(reset_used_flags): Likewise.
(set_used_flags): LIkewise.
(get_max_insn_count): New.
(next_nondebug_insn): New.
(prev_nondebug_insn): New.
(make_debug_insn_raw): New.
(emit_insn_before_noloc): Handle debug insns.
(emit_jump_insn_before_noloc): Likewise.
(emit_call_insn_before_noloc): Likewise.
(emit_debug_insn_before_noloc): New.
(emit_insn_after_noloc): Handle debug insns.
(emit_jump_insn_after_noloc): Likewise.
(emit_call_insn_after_noloc): Likewise.
(emit_debug_insn_after_noloc): Likewise.
(emit_insn_after): Take loc from earlier non-debug insn.
(emit_jump_insn_after): Likewise.
(emit_call_insn_after): Likewise.
(emit_debug_insn_after_setloc): New.
(emit_debug_insn_after): New.
(emit_insn_before): Take loc from later non-debug insn.
(emit_jump_insn_before): Likewise.
(emit_call_insn_before): Likewise.
(emit_debug_insn_before_setloc): New.
(emit_debug_insn_before): New.
(emit_insn): Handle debug insns.
(emit_debug_insn): New.
(emit_jump_insn): Handle debug insns.
(emit_call_insn): Likewise.
(emit): Likewise.
(init_emit): Take min-nondebug-insn-uid into account.
Initialize cur_debug_insn_uid.
(emit_copy_of_insn_after): Handle debug insns.
* cfgexpand.c (gimple_assign_rhs_to_tree): Do not overwrite
location of single rhs in place.
(maybe_dump_rtl_for_gimple_stmt): Dump lineno.
(floor_sdiv_adjust): New.
(cell_sdiv_adjust): New.
(cell_udiv_adjust): New.
(round_sdiv_adjust): New.
(round_udiv_adjust): New.
(wrap_constant): Moved from cselib.
(unwrap_constant): New.
(expand_debug_expr): New.
(expand_debug_locations): New.
(expand_gimple_basic_block): Drop hiding redeclaration. Expand
debug bind stmts.
(gimple_expand_cfg): Expand debug locations.
* cselib.c: Include tree-pass.h.
(struct expand_value_data): New.
(cselib_record_sets_hook): New.
(PRESERVED_VALUE_P, LONG_TERM_PRESERVED_VALUE_P): New.
(cselib_clear_table): Move, and implemnet in terms of...
(cselib_reset_table_with_next_value): ... this.
(cselib_get_next_unknown_value): New.
(discard_useless_locs): Don't discard preserved values.
(cselib_preserve_value): New.
(cselib_preserved_value_p): New.
(cselib_preserve_definitely): New.
(cselib_clear_preserve): New.
(cselib_preserve_only_values): New.
(new_cselib_val): Take rtx argument. Dump it in details.
(cselib_lookup_mem): Adjust.
(expand_loc): Take regs_active in struct. Adjust. Silence
dumps unless details are requested.
(cselib_expand_value_rtx_cb): New.
(cselib_expand_value_rtx): Rename and reimplment in terms of...
(cselib_expand_value_rtx_1): ... this. Adjust. Silence dumps
without details. Copy more subregs. Try to resolve values
using a callback. Wrap constants.
(cselib_subst_to_values): Adjust.
(cselib_log_lookup): New.
(cselib_lookup): Call it.
(cselib_invalidate_regno): Don't count preserved values as
useless.
(cselib_invalidate_mem): Likewise.
(cselib_record_set): Likewise.
(struct set): Renamed to cselib_set, moved to cselib.h.
(cselib_record_sets): Adjust. Call hook.
(cselib_process_insn): Reset table when it would be cleared.
(dump_cselib_val): New.
(dump_cselib_table): New.
* tree-cfgcleanup.c (tree_forwarded_block_p): Skip debug stmts.
(remove_forwarder_block): Support moving debug stmts.
* cselib.h (cselib_record_sets_hook): Declare.
(cselib_expand_callback): New type.
(cselib_expand_value_rtx_cb): Declare.
(cselib_reset_table_with_next_value): Declare.
(cselib_get_next_unknown_value): Declare.
(cselib_preserve_value): Declare.
(cselib_preserved_value_p): Declare.
(cselib_preserve_only_values): Declare.
(dump_cselib_table): Declare.
* cfgcleanup.c (flow_find_cross_jump): Skip debug insns.
(try_crossjump_to_edge): Likewise.
(delete_unreachable_blocks): Remove dominant GIMPLE blocks after
dominated blocks when debug stmts are present.
* simplify-rtx.c (delegitimize_mem_from_attrs): New.
* tree-ssa-live.c (remove_unused_locals): Skip debug stmts.
(set_var_live_on_entry): Likewise.
* loop-invariant.c (find_invariants_bb): Skip debug insns.
* cfglayout.c (curr_location, last_location): Make static.
(set_curr_insn_source_location): Don't avoid bouncing.
(get_curr_insn_source_location): New.
(get_curr_insn_block): New.
(duplicate_insn_chain): Handle debug insns.
* tree-ssa-forwprop.c (forward_propagate_addr_expr): Propagate
into debug stmts.
* common.opt (fcompare-debug): Move to sort order.
(fdump-unnumbered-links): Likewise.
(fvar-tracking-assignments): New.
(fvar-tracking-assignments-toggle): New.
* tree-ssa-dce.c (mark_stmt_necessary): Don't mark blocks
because of debug stmts.
(mark_stmt_if_obviously_necessary): Mark debug stmts.
(eliminate_unnecessary_stmts): Walk dominated blocks before
dominators.
* tree-ssa-ter.c (find_replaceable_in_bb): Skip debug stmts.
* ira.c (memref_used_between_p): Skip debug insns.
(update_equiv_regs): Likewise.
* sched-deps.c (sd_lists_size): Accept empty list.
(sd_init_insn): Mark debug insns.
(sd_finish_insn): Unmark them.
(sd_add_dep): Reject non-debug deps on debug insns.
(fixup_sched_groups): Give debug insns group treatment.
Skip debug insns.
(sched_analyze_reg): Don't mark debug insns for sched before call.
(sched_analyze_2): Handle debug insns.
(sched_analyze_insn): Compute next non-debug insn. Handle debug
insns.
(deps_analyze_insn): Handle debug insns.
(deps_start_bb): Skip debug insns.
(init_deps): Initialize last_debug_insn.
* tree-ssa.c (target_for_debug_bind): New.
(find_released_ssa_name): New.
(propagate_var_def_into_debug_stmts): New.
(propagate_defs_into_debug_stmts): New.
(verify_ssa): Skip debug bind stmts without values.
(warn_uninialized_vars): Skip debug stmts.
* target-def.h (TARGET_DELEGITIMIZE_ADDRESS): Set default.
* rtl.c (rtx_equal_p_cb): Handle VALUEs.
(rtx_equal_p): Likewise.
* ira-costs.c (scan_one_insn): Skip debug insns.
(process_bb_node_for_hard_reg_moves): Likewise.
* rtl.h (DEBUG_INSN_P): New.
(NONDEBUG_INSN_P): New.
(MAY_HAVE_DEBUG_INSNS): New.
(INSN_P): Accept debug insns.
(RTX_FRAME_RELATED_P): Likewise.
(INSN_DELETED_P): Likewise
(PAT_VAR_LOCATION_DECL): New.
(PAT_VAR_LOCATION_LOC): New.
(PAT_VAR_OCATION_STATUS): New.
(NOTE_VAR_LOCATION_DECL): Reimplement.
(NOTE_VAR_LOCATION_LOC): Likewise.
(NOTE_VAR_LOCATION_STATUS): Likewise.
(INSN_VAR_LOCATION): New.
(INSN_VAR_LOCATION_DECL): New.
(INSN_VAR_LOCATION_LOC): New.
(INSN_VAR_LOCATION_STATUS): New.
(gen_rtx_UNKNOWN_VAR_LOC): New.
(VAR_LOC_UNKNOWN_P): New.
(NOTE_DURING_CALL_P): New.
(SCHED_GROUP_P): Accept debug insns.
(emit_debug_insn_before): Declare.
(emit_debug_insn_before_noloc): Declare.
(emit_debug_insn_beore_setloc): Declare.
(emit_debug_insn_after): Declare.
(emit_debug_insn_after_noloc): Declare.
(emit_debug_insn_after_setloc): Declare.
(emit_debug_insn): Declare.
(make_debug_insn_raw): Declare.
(prev_nondebug_insn): Declare.
(next_nondebug_insn): Declare.
(delegitimize_mem_from_attrs): Declare.
(get_max_insn_count): Declare.
(wrap_constant): Declare.
(unwrap_constant): Declare.
(get_curr_insn_source_location): Declare.
(get_curr_insn_block): Declare.
* tree-inline.c (insert_debug_decl_map): New.
(processing_debug_stmt): New.
(remap_decl): Don't create new mappings in debug stmts.
(remap_gimple_op_r): Don't add references in debug stmts.
(copy_tree_body_r): Likewise.
(remap_gimple_stmt): Handle debug bind stmts.
(copy_bb): Skip debug stmts.
(copy_edges_for_bb): Likewise.
(copy_debug_stmt): New.
(copy_debug_stmts): New.
(copy_body): Copy debug stmts at the end.
(insert_init_debug_bind): New.
(insert_init_stmt): Take id. Skip and emit debug stmts.
(setup_one_parameter): Remap variable earlier, register debug
mapping.
(estimate_num_insns): Skip debug stmts.
(expand_call_inline): Preserve debug_map.
(optimize_inline_calls): Check for no debug_stmts left-overs.
(unsave_expr_now): Preserve debug_map.
(copy_gimple_seq_and_replace_locals): Likewise.
(tree_function_versioning): Check for no debug_stmts left-overs.
Init and destroy debug_map as needed. Split edges unconditionally.
(build_duplicate_type): Init and destroy debug_map as needed.
* tree-inline.h: Include gimple.h instead of pointer-set.h.
(struct copy_body_data): Add debug_stmts and debug_map.
* sched-int.h (struct ready_list): Add n_debug.
(struct deps): Add last_debug_insn.
(DEBUG_INSN_SCHED_P): New.
(BOUNDARY_DEBUG_INSN_P): New.
(SCHEDULE_DEBUG_INSN_P): New.
(sd_iterator_cond): Accept empty list.
* combine.c (create_log_links): Skip debug insns.
(combine_instructions): Likewise.
(cleanup_auto_inc_dec): New. From Jakub Jelinek: Make sure the
return value is always unshared.
(struct rtx_subst_pair): New.
(auto_adjust_pair): New.
(propagate_for_debug_subst): New.
(propagate_for_debug): New.
(try_combine): Skip debug insns. Propagate removed defs into
debug insns.
(next_nonnote_nondebug_insn): New.
(distribute_notes): Use it. Skip debug insns.
(distribute_links): Skip debug insns.
* tree-outof-ssa.c (set_location_for_edge): Likewise.
* resource.c (mark_target_live_regs): Likewise.
* var-tracking.c: Include cselib.h and target.h.
(enum micro_operation_type): Add MO_VAL_USE, MO_VAL_LOC, and
MO_VAL_SET.
(micro_operation_type_name): New.
(enum emit_note_where): Add EMIT_NOTE_AFTER_CALL_INSN.
(struct micro_operation_def): Update comments.
(decl_or_value): New type. Use instead of decls.
(struct emit_note_data_def): Add vars.
(struct attrs_def): Use decl_or_value.
(struct variable_tracking_info_def): Add permp, flooded.
(struct location_chain_def): Update comment.
(struct variable_part_def): Use decl_or_value.
(struct variable_def): Make var_part a variable length array.
(valvar_pool): New.
(scratch_regs): New.
(cselib_hook_called): New.
(dv_is_decl_p): New.
(dv_is_value_p): New.
(dv_as_decl): New.
(dv_as_value): New.
(dv_as_opaque): New.
(dv_onepart_p): New.
(dv_pool): New.
(IS_DECL_CODE): New.
(check_value_is_not_decl): New.
(dv_from_decl): New.
(dv_from_value): New.
(dv_htab_hash): New.
(variable_htab_hash): Use it.
(variable_htab_eq): Support values.
(variable_htab_free): Free from the right pool.
(attrs_list_member, attrs_list_insert): Use decl_or_value.
(attrs_list_union): Adjust.
(attrs_list_mpdv_union): New.
(tie_break_pointers): New.
(canon_value_cmp): New.
(unshare_variable): Return possibly-modified slot.
(vars_copy_1): Adjust.
(var_reg_decl_set): Adjust. Split out of...
(var_reg_set): ... this.
(get_init_value): Adjust.
(var_reg_delete_and_set): Adjust.
(var_reg_delete): Adjust.
(var_regno_delete): Adjust.
(var_mem_decl_set): Split out of...
(var_mem_set): ... this.
(var_mem_delete_and_set): Adjust.
(var_mem_delete): Adjust.
(val_store): New.
(val_reset): New.
(val_resolve): New.
(variable_union): Adjust. Speed up merge of 1-part vars.
(variable_canonicalize): Use unshared slot.
(VALUED_RECURSED_INTO): New.
(find_loc_in_1pdv): New.
(struct dfset_merge): New.
(insert_into_intersection): New.
(intersect_loc_chains): New.
(loc_cmp): New.
(canonicalize_loc_order_check): New.
(canonicalize_values_mark): New.
(canonicalize_values_star): New.
(variable_merge_over_cur): New.
(variable_merge_over_src): New.
(dataflow_set_merge): New.
(dataflow_set_equiv_regs): New.
(remove_duplicate_values): New.
(struct dfset_post_merge): New.
(variable_post_merge_new_vals): New.
(variable_post_merge_perm_vals): New.
(dataflow_post_merge_adjust): New.
(find_mem_expr_in_1pdv): New.
(dataflow_set_preserve_mem_locs): New.
(dataflow_set_remove_mem_locs): New.
(dataflow_set_clear_at_call): New.
(onepart_variable_different_p): New.
(variable_different_p): Use it.
(dataflow_set_different_1): Adjust. Make detailed dump
more verbose.
(track_expr_p): Add need_rtl parameter. Don't generate rtl
if not needed.
(track_loc_p): Pass it true.
(struct count_use_info): New.
(find_use_val): New.
(replace_expr_with_values): New.
(log_op_type): New.
(use_type): New, partially split out of...
(count_uses): ... this. Count new micro-ops.
(count_uses_1): Adjust.
(count_stores): Adjust.
(count_with_sets): New.
(VAL_NEEDS_RESOLUTION): New.
(VAL_HOLDS_TRACK_EXPR): New.
(VAL_EXPR_IS_COPIED): New.
(VAL_EXPR_IS_CLOBBERED): New.
(add_uses): Adjust. Generate new micro-ops.
(add_uses_1): Adjust.
(add_stores): Generate new micro-ops.
(add_with_sets): New.
(find_src_status): Adjust.
(find_src_set_src): Adjust.
(compute_bb_dataflow): Use dataflow_set_clear_at_call.
Handle new micro-ops. Canonicalize value equivalances.
(vt_find_locations): Compute total size of hash tables for
dumping. Perform merge for var-tracking-assignments. Don't
disregard single-block loops.
(dump_attrs_list): Handle decl_or_value.
(dump_variable): Take variable. Deal with decl_or_value.
(dump_variable_slot): New.
(dump_vars): Use it.
(dump_dataflow_sets): Adjust.
(set_slot_part): New, extended to support one-part variables
after splitting out of...
(set_variable_part): ... this.
(clobber_slot_part): New, split out of...
(clobber_variable_part): ... this.
(delete_slot_part): New, split out of...
(delete_variable_part): .... this.
(check_wrap_constant): New.
(vt_expand_loc_callback): New.
(vt_expand_loc): New.
(emit_note_insn_var_location): Adjust. Handle values. Handle
EMIT_NOTE_AFTER_CALL_INSN.
(emit_notes_for_differences_1): Adjust. Handle values.
(emit_notes_for_differences_2): Likewise.
(emit_notes_for_differences): Adjust.
(emit_notes_in_bb): Take pointer to set. Emit AFTER_CALL_INSN
notes. Adjust. Handle new micro-ops.
(vt_add_function_parameters): Adjust. Create and bind values.
(vt_initialize): Adjust. Initialize scratch_regs and
valvar_pool, flooded and perm.. Initialize and use cselib. Log
operations. Move some code to count_with_sets and add_with_sets.
(delete_debug_insns): New.
(vt_debug_insns_local): New.
(vt_finalize): Release permp, valvar_pool, scratch_regs. Finish
cselib.
(var_tracking_main): If var-tracking-assignments is enabled
but var-tracking isn't, delete debug insns and leave. Likewise
if we exceed limits or fail the stack adjustments tests, and
after all var-tracking processing.
More in var-tracking, from Jakub Jelinek <jakub@redhat.com>:
(dataflow_set): Add traversed_vars.
(value_chain, const_value_chain): New typedefs.
(value_chain_pool, value_chains): New variables.
(value_chain_htab_hash, value_chain_htab_eq, add_value_chain,
add_value_chains, add_cselib_value_chains, remove_value_chain,
remove_value_chains, remove_cselib_value_chains): New functions.
(shared_hash_find_slot_unshare_1, shared_hash_find_slot_1,
shared_hash_find_slot_noinsert_1, shared_hash_find_1): New
static inlines.
(shared_hash_find_slot_unshare, shared_hash_find_slot,
shared_hash_find_slot_noinsert, shared_hash_find): Update.
(dst_can_be_shared): New variable.
(unshare_variable): Unshare set->vars if shared, use shared_hash_*.
Clear dst_can_be_shared. If set->traversed_vars is non-NULL and
different from set->vars, look up slot again instead of using the
passed in slot.
(dataflow_set_init): Initialize traversed_vars.
(variable_union): Use shared_hash_*. Use initially NO_INSERT
lookup if set->vars is shared. Don't keep slot cleared before
calling unshare_variable. Unshare set->vars if needed. Adjust
unshare_variable callers. Clear dst_can_be_shared if needed.
Even ->refcount == 1 vars must be unshared if set->vars is shared
and var needs to be modified.
(dataflow_set_union): Set traversed_vars during canonicalization.
(VALUE_CHANGED, DECL_CHANGED): Define.
(set_dv_changed, dv_changed_p): New static inlines.
(track_expr_p): Clear DECL_CHANGED.
(dump_dataflow_sets): Set it.
(variable_was_changed): Call set_dv_changed.
(emit_note_insn_var_location): Likewise.
(changed_variables_stack): New variable.
(check_changed_vars_1, check_changed_vars_2): New functions.
(emit_notes_for_changes): Do nothing if changed_variables is
empty. Traverse changed_variables with check_changed_vars_1,
call check_changed_vars_2 on each changed_variables_stack entry.
(emit_notes_in_bb): Add SET argument. Just clear it at the
beginning, use it instead of local &set, don't destroy it at the
end.
(vt_emit_notes): Call dataflow_set_clear early on all
VTI(bb)->out sets, never use them, instead use emit_notes_in_bb
computed set, dataflow_set_clear also VTI(bb)->in when we are
done with the basic block. Initialize changed_variables_stack,
free it afterwards. If ENABLE_CHECKING verify that after noting
differences to an empty set value_chains hash table is empty.
(vt_initialize): Initialize value_chains and value_chain_pool.
(vt_finalize): Delete value_chains htab, free value_chain_pool.
(variable_tracking_main): Call dump_dataflow_sets before calling
vt_emit_notes, not after it.
* tree-flow.h (propagate_defs_into_debug_stmts): Declare.
(propagate_var_def_into_debug_stmts): Declare.
* df-problems.c (df_lr_bb_local_compute): Skip debug insns.
(df_set_note): Reject debug insns.
(df_whole_mw_reg_dead_p): Take added_notes_p argument. Don't
add notes to debug insns.
(df_note_bb_compute): Adjust. Likewise.
(df_simulate_uses): Skip debug insns.
(df_simulate_initialize_backwards): Likewise.
* reg-stack.c (subst_stack_regs_in_debug_insn): New.
(subst_stack_regs_pat): Reject debug insns.
(convert_regs_1): Handle debug insns.
* Makefile.in (TREE_INLINE_H): Take pointer-set.h from GIMPLE_H.
(print-rtl.o): Depend on cselib.h.
(cselib.o): Depend on TREE_PASS_H.
(var-tracking.o): Depend on cselib.h and TARGET_H.
* sched-rgn.c (rgn_estimate_number_of_insns): Discount
debug insns.
(init_ready_list): Skip boundary debug insns.
(add_branch_dependences): Skip debug insns.
(free_block_dependencies): Check for blocks with only debug
insns.
(compute_priorities): Likewise.
* gimple.c (gss_for_code): Handle GIMPLE_DEBUG.
(gimple_build_with_ops_stat): Take subcode as unsigned. Adjust
all callers.
(gimple_build_debug_bind_stat): New.
(empty_body_p): Skip debug stmts.
(gimple_has_side_effects): Likewise.
(gimple_rhs_has_side_effects): Likewise.
* gimple.h (enum gimple_debug_subcode, GIMPLE_DEBUG_BIND): New.
(gimple_build_debug_bind_stat): Declare.
(gimple_build_debug_bind): Define.
(is_gimple_debug): New.
(gimple_debug_bind_p): New.
(gimple_debug_bind_get_var): New.
(gimple_debug_bind_get_value): New.
(gimple_debug_bind_get_value_ptr): New.
(gimple_debug_bind_set_var): New.
(gimple_debug_bind_set_value): New.
(GIMPLE_DEBUG_BIND_NOVALUE): New internal temporary macro.
(gimple_debug_bind_reset_value): New.
(gimple_debug_bind_has_value_p): New.
(gsi_next_nondebug): New.
(gsi_prev_nondebug): New.
(gsi_start_nondebug_bb): New.
(gsi_last_nondebug_bb): New.
* sched-vis.c (print_pattern): Handle VAR_LOCATION.
(print_insn): Handle DEBUG_INSN.
* tree-cfg.c (remove_bb): Walk stmts backwards. Let loc
of first insn prevail.
(first_stmt): Skip debug stmts.
(first_non_label_stmt): Likewise.
(last_stmt): Likewise.
(has_zero_uses_1): New.
(single_imm_use_1): New.
(verify_gimple_debug): New.
(verify_types_in_gimple_stmt): Handle debug stmts.
(verify_stmt): Likewise.
(debug_loop_num): Skip debug stmts.
(remove_edge_and_dominated_blocks): Remove dominators last.
* tree-ssa-reasssoc.c (rewrite_expr_tree): Propagate into
debug stmts.
(linearize_expr): Likewise.
* config/i386/i386.c (ix86_delegitimize_address): Call
default implementation.
* config/ia64/ia64.c (ia64_safe_itanium_class): Handle debug
insns.
(group_barrier_needed): Skip debug insns.
(emit_insn_group_barriers): Likewise.
(emit_all_insn_group_barriers): Likewise.
(ia64_variable_issue): Handle debug insns.
(ia64_dfa_new_cycle): Likewise.
(final_emit_insn_group_barriers): Skip debug insns.
(ia64_dwarf2out_def_steady_cfa): Take frame argument. Don't
def cfa without frame.
(process_set): Likewise.
(process_for_unwind_directive): Pass frame on.
* config/rs6000/rs6000.c (TARGET_DELEGITIMIZE_ADDRESS): Define.
(rs6000_delegitimize_address): New.
(rs6000_debug_adjust_cost): Handle debug insns.
(is_microcoded_insn): Likewise.
(is_cracked_insn): Likewise.
(is_nonpipeline_insn): Likewise.
(insn_must_be_first_in_group): Likewise.
(insn_must_be_last_in_group): Likewise.
(force_new_group): Likewise.
* cfgrtl.c (rtl_split_block): Emit INSN_DELETED note if block
contains only debug insns.
(rtl_merge_blocks): Skip debug insns.
(purge_dead_edges): Likewise.
(rtl_block_ends_with_call_p): Skip debug insns.
* dce.c (deletable_insn_p): Handle VAR_LOCATION.
(mark_reg_dependencies): Skip debug insns.
* params.def (PARAM_MIN_NONDEBUG_INSN_UID): New.
* tree-ssanames.c (release_ssa_name): Propagate def into
debug stmts.
* tree-ssa-threadedge.c
(record_temporary_equivalences_from_stmts): Skip debug stmts.
* regcprop.c (replace_oldest_value_addr): Skip debug insns.
(replace_oldest_value_mem): Use ALL_REGS for debug insns.
(copyprop_hardreg_forward_1): Handle debug insns.
* reload1.c (reload): Skip debug insns. Replace unassigned
pseudos in debug insns with their equivalences.
(eliminate_regs_in_insn): Skip debug insns.
(emit_input_reload_insns): Skip debug insns at first, adjust
them later.
* tree-ssa-operands.c (add_virtual_operand): Reject debug stmts.
(get_indirect_ref_operands): Pass opf_no_vops on.
(get_expr_operands): Likewise. Skip debug stmts.
(parse_ssa_operands): Scan debug insns with opf_no_vops.
gcc/testsuite/ChangeLog:
* gcc.dg/guality/guality.c: New.
* gcc.dg/guality/guality.h: New.
* gcc.dg/guality/guality.exp: New.
* gcc.dg/guality/example.c: New.
* lib/gcc-dg.exp (cleanup-dump): Remove .gk files.
(cleanup-saved-temps): Likewise, .gkd files too.
gcc/cp/ChangeLog:
* cp-tree.h (TFF_NO_OMIT_DEFAULT_TEMPLATE_ARGUMENTS): New.
* cp-lang.c (cxx_dwarf_name): Pass it.
* error.c (count_non_default_template_args): Take flags as
argument. Adjust all callers. Skip counting of default
arguments if the new flag is given.
ChangeLog:
* Makefile.tpl (BUILD_CONFIG): Default to bootstrap-debug.
* Makefile.in: Rebuilt.
contrib/ChangeLog:
* compare-debug: Look for .gkd files and compare them.
config/ChangeLog:
* bootstrap-debug.mk: Add comments.
* bootstrap-debug-big.mk: New.
* bootstrap-debug-lean.mk: New.
* bootstrap-debug-ckovw.mk: Add comments.
* bootstrap-debug-lib.mk: Drop CFLAGS for stages. Use -g0
for TFLAGS in stage1. Drop -fvar-tracking-assignments-toggle.
From-SVN: r151312
2881 lines
76 KiB
C
2881 lines
76 KiB
C
/* Call-backs for C++ error reporting.
|
|
This code is non-reentrant.
|
|
Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2002,
|
|
2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
|
This file is part of GCC.
|
|
|
|
GCC is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
GCC is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GCC; see the file COPYING3. If not see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
#include "config.h"
|
|
#include "system.h"
|
|
#include "coretypes.h"
|
|
#include "tm.h"
|
|
#include "tree.h"
|
|
#include "cp-tree.h"
|
|
#include "real.h"
|
|
#include "toplev.h"
|
|
#include "flags.h"
|
|
#include "diagnostic.h"
|
|
#include "langhooks-def.h"
|
|
#include "intl.h"
|
|
#include "cxx-pretty-print.h"
|
|
#include "pointer-set.h"
|
|
|
|
#define pp_separate_with_comma(PP) pp_cxx_separate_with (PP, ',')
|
|
|
|
/* The global buffer where we dump everything. It is there only for
|
|
transitional purpose. It is expected, in the near future, to be
|
|
completely removed. */
|
|
static cxx_pretty_printer scratch_pretty_printer;
|
|
#define cxx_pp (&scratch_pretty_printer)
|
|
|
|
/* Translate if being used for diagnostics, but not for dump files or
|
|
__PRETTY_FUNCTION. */
|
|
#define M_(msgid) (pp_translate_identifiers (cxx_pp) ? _(msgid) : (msgid))
|
|
|
|
# define NEXT_CODE(T) (TREE_CODE (TREE_TYPE (T)))
|
|
|
|
static const char *args_to_string (tree, int);
|
|
static const char *assop_to_string (enum tree_code);
|
|
static const char *code_to_string (enum tree_code);
|
|
static const char *cv_to_string (tree, int);
|
|
static const char *decl_to_string (tree, int);
|
|
static const char *expr_to_string (tree);
|
|
static const char *fndecl_to_string (tree, int);
|
|
static const char *op_to_string (enum tree_code);
|
|
static const char *parm_to_string (int);
|
|
static const char *type_to_string (tree, int);
|
|
|
|
static void dump_type (tree, int);
|
|
static void dump_typename (tree, int);
|
|
static void dump_simple_decl (tree, tree, int);
|
|
static void dump_decl (tree, int);
|
|
static void dump_template_decl (tree, int);
|
|
static void dump_function_decl (tree, int);
|
|
static void dump_expr (tree, int);
|
|
static void dump_unary_op (const char *, tree, int);
|
|
static void dump_binary_op (const char *, tree, int);
|
|
static void dump_aggr_type (tree, int);
|
|
static void dump_type_prefix (tree, int);
|
|
static void dump_type_suffix (tree, int);
|
|
static void dump_function_name (tree, int);
|
|
static void dump_call_expr_args (tree, int, bool);
|
|
static void dump_aggr_init_expr_args (tree, int, bool);
|
|
static void dump_expr_list (tree, int);
|
|
static void dump_global_iord (tree);
|
|
static void dump_parameters (tree, int);
|
|
static void dump_exception_spec (tree, int);
|
|
static void dump_template_argument (tree, int);
|
|
static void dump_template_argument_list (tree, tree, int);
|
|
static void dump_template_parameter (tree, int);
|
|
static void dump_template_bindings (tree, tree, VEC(tree,gc) *);
|
|
static void dump_scope (tree, int);
|
|
static void dump_template_parms (tree, int, int);
|
|
|
|
static int count_non_default_template_args (tree, tree, int);
|
|
|
|
static const char *function_category (tree);
|
|
static void maybe_print_instantiation_context (diagnostic_context *);
|
|
static void print_instantiation_full_context (diagnostic_context *);
|
|
static void print_instantiation_partial_context (diagnostic_context *,
|
|
struct tinst_level *,
|
|
location_t);
|
|
static void cp_diagnostic_starter (diagnostic_context *, diagnostic_info *);
|
|
static void cp_diagnostic_finalizer (diagnostic_context *, diagnostic_info *);
|
|
static void cp_print_error_function (diagnostic_context *, diagnostic_info *);
|
|
|
|
static bool cp_printer (pretty_printer *, text_info *, const char *,
|
|
int, bool, bool, bool);
|
|
static location_t location_of (tree);
|
|
|
|
void
|
|
init_error (void)
|
|
{
|
|
diagnostic_starter (global_dc) = cp_diagnostic_starter;
|
|
diagnostic_finalizer (global_dc) = cp_diagnostic_finalizer;
|
|
diagnostic_format_decoder (global_dc) = cp_printer;
|
|
|
|
pp_construct (pp_base (cxx_pp), NULL, 0);
|
|
pp_cxx_pretty_printer_init (cxx_pp);
|
|
}
|
|
|
|
/* Dump a scope, if deemed necessary. */
|
|
|
|
static void
|
|
dump_scope (tree scope, int flags)
|
|
{
|
|
int f = ~TFF_RETURN_TYPE & (flags & (TFF_SCOPE | TFF_CHASE_TYPEDEF));
|
|
|
|
if (scope == NULL_TREE)
|
|
return;
|
|
|
|
if (TREE_CODE (scope) == NAMESPACE_DECL)
|
|
{
|
|
if (scope != global_namespace)
|
|
{
|
|
dump_decl (scope, f);
|
|
pp_cxx_colon_colon (cxx_pp);
|
|
}
|
|
}
|
|
else if (AGGREGATE_TYPE_P (scope))
|
|
{
|
|
dump_type (scope, f);
|
|
pp_cxx_colon_colon (cxx_pp);
|
|
}
|
|
else if ((flags & TFF_SCOPE) && TREE_CODE (scope) == FUNCTION_DECL)
|
|
{
|
|
dump_function_decl (scope, f);
|
|
pp_cxx_colon_colon (cxx_pp);
|
|
}
|
|
}
|
|
|
|
/* Dump the template ARGument under control of FLAGS. */
|
|
|
|
static void
|
|
dump_template_argument (tree arg, int flags)
|
|
{
|
|
if (ARGUMENT_PACK_P (arg))
|
|
dump_template_argument_list (ARGUMENT_PACK_ARGS (arg), NULL_TREE, flags);
|
|
else if (TYPE_P (arg) || TREE_CODE (arg) == TEMPLATE_DECL)
|
|
dump_type (arg, flags & ~TFF_CLASS_KEY_OR_ENUM);
|
|
else
|
|
{
|
|
if (TREE_CODE (arg) == TREE_LIST)
|
|
arg = TREE_VALUE (arg);
|
|
|
|
dump_expr (arg, (flags | TFF_EXPR_IN_PARENS) & ~TFF_CLASS_KEY_OR_ENUM);
|
|
}
|
|
}
|
|
|
|
/* Count the number of template arguments ARGS whose value does not
|
|
match the (optional) default template parameter in PARAMS */
|
|
|
|
static int
|
|
count_non_default_template_args (tree args, tree params, int flags)
|
|
{
|
|
tree inner_args = INNERMOST_TEMPLATE_ARGS (args);
|
|
int n = TREE_VEC_LENGTH (inner_args);
|
|
int last;
|
|
|
|
if (params == NULL_TREE
|
|
/* We use this flag when generating debug information. We don't
|
|
want to expand templates at this point, for this may generate
|
|
new decls, which gets decl counts out of sync, which may in
|
|
turn cause codegen differences between compilations with and
|
|
without -g. */
|
|
|| (flags & TFF_NO_OMIT_DEFAULT_TEMPLATE_ARGUMENTS) != 0
|
|
|| !flag_pretty_templates)
|
|
return n;
|
|
|
|
for (last = n - 1; last >= 0; --last)
|
|
{
|
|
tree param = TREE_VEC_ELT (params, last);
|
|
tree def = TREE_PURPOSE (param);
|
|
|
|
if (!def)
|
|
break;
|
|
if (uses_template_parms (def))
|
|
{
|
|
++processing_template_decl;
|
|
/* This speculative substitution must not cause any classes to be
|
|
instantiated that otherwise wouldn't be. */
|
|
def = tsubst_copy_and_build (def, args, tf_no_class_instantiations,
|
|
NULL_TREE, false, true);
|
|
--processing_template_decl;
|
|
}
|
|
if (!cp_tree_equal (TREE_VEC_ELT (inner_args, last), def))
|
|
break;
|
|
}
|
|
|
|
return last + 1;
|
|
}
|
|
|
|
/* Dump a template-argument-list ARGS (always a TREE_VEC) under control
|
|
of FLAGS. */
|
|
|
|
static void
|
|
dump_template_argument_list (tree args, tree parms, int flags)
|
|
{
|
|
int n = count_non_default_template_args (args, parms, flags);
|
|
int need_comma = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < n; ++i)
|
|
{
|
|
tree arg = TREE_VEC_ELT (args, i);
|
|
|
|
/* Only print a comma if we know there is an argument coming. In
|
|
the case of an empty template argument pack, no actual
|
|
argument will be printed. */
|
|
if (need_comma
|
|
&& (!ARGUMENT_PACK_P (arg)
|
|
|| TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg)) > 0))
|
|
pp_separate_with_comma (cxx_pp);
|
|
|
|
dump_template_argument (arg, flags);
|
|
need_comma = 1;
|
|
}
|
|
}
|
|
|
|
/* Dump a template parameter PARM (a TREE_LIST) under control of FLAGS. */
|
|
|
|
static void
|
|
dump_template_parameter (tree parm, int flags)
|
|
{
|
|
tree p;
|
|
tree a;
|
|
|
|
if (parm == error_mark_node)
|
|
return;
|
|
|
|
p = TREE_VALUE (parm);
|
|
a = TREE_PURPOSE (parm);
|
|
|
|
if (TREE_CODE (p) == TYPE_DECL)
|
|
{
|
|
if (flags & TFF_DECL_SPECIFIERS)
|
|
{
|
|
pp_cxx_ws_string (cxx_pp, "class");
|
|
if (TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (p)))
|
|
pp_cxx_ws_string (cxx_pp, "...");
|
|
if (DECL_NAME (p))
|
|
pp_cxx_tree_identifier (cxx_pp, DECL_NAME (p));
|
|
}
|
|
else if (DECL_NAME (p))
|
|
pp_cxx_tree_identifier (cxx_pp, DECL_NAME (p));
|
|
else
|
|
pp_cxx_canonical_template_parameter (cxx_pp, TREE_TYPE (p));
|
|
}
|
|
else
|
|
dump_decl (p, flags | TFF_DECL_SPECIFIERS);
|
|
|
|
if ((flags & TFF_FUNCTION_DEFAULT_ARGUMENTS) && a != NULL_TREE)
|
|
{
|
|
pp_cxx_whitespace (cxx_pp);
|
|
pp_equal (cxx_pp);
|
|
pp_cxx_whitespace (cxx_pp);
|
|
if (TREE_CODE (p) == TYPE_DECL || TREE_CODE (p) == TEMPLATE_DECL)
|
|
dump_type (a, flags & ~TFF_CHASE_TYPEDEF);
|
|
else
|
|
dump_expr (a, flags | TFF_EXPR_IN_PARENS);
|
|
}
|
|
}
|
|
|
|
/* Dump, under control of FLAGS, a template-parameter-list binding.
|
|
PARMS is a TREE_LIST of TREE_VEC of TREE_LIST and ARGS is a
|
|
TREE_VEC. */
|
|
|
|
static void
|
|
dump_template_bindings (tree parms, tree args, VEC(tree,gc)* typenames)
|
|
{
|
|
int need_comma = 0;
|
|
int i;
|
|
tree t;
|
|
|
|
while (parms)
|
|
{
|
|
tree p = TREE_VALUE (parms);
|
|
int lvl = TMPL_PARMS_DEPTH (parms);
|
|
int arg_idx = 0;
|
|
int i;
|
|
tree lvl_args = NULL_TREE;
|
|
|
|
/* Don't crash if we had an invalid argument list. */
|
|
if (TMPL_ARGS_DEPTH (args) >= lvl)
|
|
lvl_args = TMPL_ARGS_LEVEL (args, lvl);
|
|
|
|
for (i = 0; i < TREE_VEC_LENGTH (p); ++i)
|
|
{
|
|
tree arg = NULL_TREE;
|
|
|
|
/* Don't crash if we had an invalid argument list. */
|
|
if (lvl_args && NUM_TMPL_ARGS (lvl_args) > arg_idx)
|
|
arg = TREE_VEC_ELT (lvl_args, arg_idx);
|
|
|
|
if (need_comma)
|
|
pp_separate_with_comma (cxx_pp);
|
|
dump_template_parameter (TREE_VEC_ELT (p, i), TFF_PLAIN_IDENTIFIER);
|
|
pp_cxx_whitespace (cxx_pp);
|
|
pp_equal (cxx_pp);
|
|
pp_cxx_whitespace (cxx_pp);
|
|
if (arg)
|
|
dump_template_argument (arg, TFF_PLAIN_IDENTIFIER);
|
|
else
|
|
pp_string (cxx_pp, M_("<missing>"));
|
|
|
|
++arg_idx;
|
|
need_comma = 1;
|
|
}
|
|
|
|
parms = TREE_CHAIN (parms);
|
|
}
|
|
|
|
for (i = 0; VEC_iterate (tree, typenames, i, t); ++i)
|
|
{
|
|
if (need_comma)
|
|
pp_separate_with_comma (cxx_pp);
|
|
dump_type (t, TFF_PLAIN_IDENTIFIER);
|
|
pp_cxx_whitespace (cxx_pp);
|
|
pp_equal (cxx_pp);
|
|
pp_cxx_whitespace (cxx_pp);
|
|
t = tsubst (t, args, tf_none, NULL_TREE);
|
|
/* Strip typedefs. We can't just use TFF_CHASE_TYPEDEF because
|
|
pp_simple_type_specifier doesn't know about it. */
|
|
t = strip_typedefs (t);
|
|
dump_type (t, TFF_PLAIN_IDENTIFIER);
|
|
}
|
|
}
|
|
|
|
/* Dump a human-readable equivalent of TYPE. FLAGS controls the
|
|
format. */
|
|
|
|
static void
|
|
dump_type (tree t, int flags)
|
|
{
|
|
if (t == NULL_TREE)
|
|
return;
|
|
|
|
if (TYPE_PTRMEMFUNC_P (t))
|
|
goto offset_type;
|
|
|
|
switch (TREE_CODE (t))
|
|
{
|
|
case UNKNOWN_TYPE:
|
|
if (t == init_list_type_node)
|
|
pp_string (cxx_pp, M_("<brace-enclosed initializer list>"));
|
|
else
|
|
pp_string (cxx_pp, M_("<unresolved overloaded function type>"));
|
|
break;
|
|
|
|
case TREE_LIST:
|
|
/* A list of function parms. */
|
|
dump_parameters (t, flags);
|
|
break;
|
|
|
|
case IDENTIFIER_NODE:
|
|
pp_cxx_tree_identifier (cxx_pp, t);
|
|
break;
|
|
|
|
case TREE_BINFO:
|
|
dump_type (BINFO_TYPE (t), flags);
|
|
break;
|
|
|
|
case RECORD_TYPE:
|
|
case UNION_TYPE:
|
|
case ENUMERAL_TYPE:
|
|
dump_aggr_type (t, flags);
|
|
break;
|
|
|
|
case TYPE_DECL:
|
|
if (flags & TFF_CHASE_TYPEDEF)
|
|
{
|
|
dump_type (DECL_ORIGINAL_TYPE (t)
|
|
? DECL_ORIGINAL_TYPE (t) : TREE_TYPE (t), flags);
|
|
break;
|
|
}
|
|
/* Else fall through. */
|
|
|
|
case TEMPLATE_DECL:
|
|
case NAMESPACE_DECL:
|
|
dump_decl (t, flags & ~TFF_DECL_SPECIFIERS);
|
|
break;
|
|
|
|
case INTEGER_TYPE:
|
|
case REAL_TYPE:
|
|
case VOID_TYPE:
|
|
case BOOLEAN_TYPE:
|
|
case COMPLEX_TYPE:
|
|
case VECTOR_TYPE:
|
|
case FIXED_POINT_TYPE:
|
|
pp_type_specifier_seq (cxx_pp, t);
|
|
break;
|
|
|
|
case TEMPLATE_TEMPLATE_PARM:
|
|
/* For parameters inside template signature. */
|
|
if (TYPE_IDENTIFIER (t))
|
|
pp_cxx_tree_identifier (cxx_pp, TYPE_IDENTIFIER (t));
|
|
else
|
|
pp_cxx_canonical_template_parameter (cxx_pp, t);
|
|
break;
|
|
|
|
case BOUND_TEMPLATE_TEMPLATE_PARM:
|
|
{
|
|
tree args = TYPE_TI_ARGS (t);
|
|
pp_cxx_cv_qualifier_seq (cxx_pp, t);
|
|
pp_cxx_tree_identifier (cxx_pp, TYPE_IDENTIFIER (t));
|
|
pp_cxx_begin_template_argument_list (cxx_pp);
|
|
dump_template_argument_list (args, NULL_TREE, flags);
|
|
pp_cxx_end_template_argument_list (cxx_pp);
|
|
}
|
|
break;
|
|
|
|
case TEMPLATE_TYPE_PARM:
|
|
pp_cxx_cv_qualifier_seq (cxx_pp, t);
|
|
if (TYPE_IDENTIFIER (t))
|
|
pp_cxx_tree_identifier (cxx_pp, TYPE_IDENTIFIER (t));
|
|
else
|
|
pp_cxx_canonical_template_parameter
|
|
(cxx_pp, TEMPLATE_TYPE_PARM_INDEX (t));
|
|
break;
|
|
|
|
/* This is not always necessary for pointers and such, but doing this
|
|
reduces code size. */
|
|
case ARRAY_TYPE:
|
|
case POINTER_TYPE:
|
|
case REFERENCE_TYPE:
|
|
case OFFSET_TYPE:
|
|
offset_type:
|
|
case FUNCTION_TYPE:
|
|
case METHOD_TYPE:
|
|
{
|
|
dump_type_prefix (t, flags);
|
|
dump_type_suffix (t, flags);
|
|
break;
|
|
}
|
|
case TYPENAME_TYPE:
|
|
if (! (flags & TFF_CHASE_TYPEDEF)
|
|
&& DECL_ORIGINAL_TYPE (TYPE_NAME (t)))
|
|
{
|
|
dump_decl (TYPE_NAME (t), TFF_PLAIN_IDENTIFIER);
|
|
break;
|
|
}
|
|
pp_cxx_cv_qualifier_seq (cxx_pp, t);
|
|
pp_cxx_ws_string (cxx_pp,
|
|
TYPENAME_IS_ENUM_P (t) ? "enum"
|
|
: TYPENAME_IS_CLASS_P (t) ? "class"
|
|
: "typename");
|
|
dump_typename (t, flags);
|
|
break;
|
|
|
|
case UNBOUND_CLASS_TEMPLATE:
|
|
dump_type (TYPE_CONTEXT (t), flags);
|
|
pp_cxx_colon_colon (cxx_pp);
|
|
pp_cxx_ws_string (cxx_pp, "template");
|
|
dump_type (DECL_NAME (TYPE_NAME (t)), flags);
|
|
break;
|
|
|
|
case TYPEOF_TYPE:
|
|
pp_cxx_ws_string (cxx_pp, "__typeof__");
|
|
pp_cxx_whitespace (cxx_pp);
|
|
pp_cxx_left_paren (cxx_pp);
|
|
dump_expr (TYPEOF_TYPE_EXPR (t), flags & ~TFF_EXPR_IN_PARENS);
|
|
pp_cxx_right_paren (cxx_pp);
|
|
break;
|
|
|
|
case TYPE_PACK_EXPANSION:
|
|
dump_type (PACK_EXPANSION_PATTERN (t), flags);
|
|
pp_cxx_ws_string (cxx_pp, "...");
|
|
break;
|
|
|
|
case TYPE_ARGUMENT_PACK:
|
|
dump_template_argument (t, flags);
|
|
break;
|
|
|
|
case DECLTYPE_TYPE:
|
|
pp_cxx_ws_string (cxx_pp, "decltype");
|
|
pp_cxx_whitespace (cxx_pp);
|
|
pp_cxx_left_paren (cxx_pp);
|
|
dump_expr (DECLTYPE_TYPE_EXPR (t), flags & ~TFF_EXPR_IN_PARENS);
|
|
pp_cxx_right_paren (cxx_pp);
|
|
break;
|
|
|
|
default:
|
|
pp_unsupported_tree (cxx_pp, t);
|
|
/* Fall through to error. */
|
|
|
|
case ERROR_MARK:
|
|
pp_string (cxx_pp, M_("<type error>"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Dump a TYPENAME_TYPE. We need to notice when the context is itself
|
|
a TYPENAME_TYPE. */
|
|
|
|
static void
|
|
dump_typename (tree t, int flags)
|
|
{
|
|
tree ctx = TYPE_CONTEXT (t);
|
|
|
|
if (TREE_CODE (ctx) == TYPENAME_TYPE)
|
|
dump_typename (ctx, flags);
|
|
else
|
|
dump_type (ctx, flags & ~TFF_CLASS_KEY_OR_ENUM);
|
|
pp_cxx_colon_colon (cxx_pp);
|
|
dump_decl (TYPENAME_TYPE_FULLNAME (t), flags);
|
|
}
|
|
|
|
/* Return the name of the supplied aggregate, or enumeral type. */
|
|
|
|
const char *
|
|
class_key_or_enum_as_string (tree t)
|
|
{
|
|
if (TREE_CODE (t) == ENUMERAL_TYPE)
|
|
{
|
|
if (SCOPED_ENUM_P (t))
|
|
return "enum class";
|
|
else
|
|
return "enum";
|
|
}
|
|
else if (TREE_CODE (t) == UNION_TYPE)
|
|
return "union";
|
|
else if (TYPE_LANG_SPECIFIC (t) && CLASSTYPE_DECLARED_CLASS (t))
|
|
return "class";
|
|
else
|
|
return "struct";
|
|
}
|
|
|
|
/* Print out a class declaration T under the control of FLAGS,
|
|
in the form `class foo'. */
|
|
|
|
static void
|
|
dump_aggr_type (tree t, int flags)
|
|
{
|
|
tree name;
|
|
const char *variety = class_key_or_enum_as_string (t);
|
|
int typdef = 0;
|
|
int tmplate = 0;
|
|
|
|
pp_cxx_cv_qualifier_seq (cxx_pp, t);
|
|
|
|
if (flags & TFF_CLASS_KEY_OR_ENUM)
|
|
pp_cxx_ws_string (cxx_pp, variety);
|
|
|
|
name = TYPE_NAME (t);
|
|
|
|
if (name)
|
|
{
|
|
typdef = !DECL_ARTIFICIAL (name);
|
|
|
|
if (typdef
|
|
&& ((flags & TFF_CHASE_TYPEDEF)
|
|
|| (!flag_pretty_templates && DECL_LANG_SPECIFIC (name)
|
|
&& DECL_TEMPLATE_INFO (name))))
|
|
{
|
|
t = TYPE_MAIN_VARIANT (t);
|
|
name = TYPE_NAME (t);
|
|
typdef = 0;
|
|
}
|
|
|
|
tmplate = !typdef && TREE_CODE (t) != ENUMERAL_TYPE
|
|
&& TYPE_LANG_SPECIFIC (t) && CLASSTYPE_TEMPLATE_INFO (t)
|
|
&& (TREE_CODE (CLASSTYPE_TI_TEMPLATE (t)) != TEMPLATE_DECL
|
|
|| PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t)));
|
|
|
|
if (! (flags & TFF_UNQUALIFIED_NAME))
|
|
dump_scope (CP_DECL_CONTEXT (name), flags | TFF_SCOPE);
|
|
flags &= ~TFF_UNQUALIFIED_NAME;
|
|
if (tmplate)
|
|
{
|
|
/* Because the template names are mangled, we have to locate
|
|
the most general template, and use that name. */
|
|
tree tpl = CLASSTYPE_TI_TEMPLATE (t);
|
|
|
|
while (DECL_TEMPLATE_INFO (tpl))
|
|
tpl = DECL_TI_TEMPLATE (tpl);
|
|
name = tpl;
|
|
}
|
|
name = DECL_NAME (name);
|
|
}
|
|
|
|
if (name == 0 || ANON_AGGRNAME_P (name))
|
|
{
|
|
if (flags & TFF_CLASS_KEY_OR_ENUM)
|
|
pp_string (cxx_pp, M_("<anonymous>"));
|
|
else
|
|
pp_printf (pp_base (cxx_pp), M_("<anonymous %s>"), variety);
|
|
}
|
|
else
|
|
pp_cxx_tree_identifier (cxx_pp, name);
|
|
if (tmplate)
|
|
dump_template_parms (TYPE_TEMPLATE_INFO (t),
|
|
!CLASSTYPE_USE_TEMPLATE (t),
|
|
flags & ~TFF_TEMPLATE_HEADER);
|
|
}
|
|
|
|
/* Dump into the obstack the initial part of the output for a given type.
|
|
This is necessary when dealing with things like functions returning
|
|
functions. Examples:
|
|
|
|
return type of `int (* fee ())()': pointer -> function -> int. Both
|
|
pointer (and reference and offset) and function (and member) types must
|
|
deal with prefix and suffix.
|
|
|
|
Arrays must also do this for DECL nodes, like int a[], and for things like
|
|
int *[]&. */
|
|
|
|
static void
|
|
dump_type_prefix (tree t, int flags)
|
|
{
|
|
if (TYPE_PTRMEMFUNC_P (t))
|
|
{
|
|
t = TYPE_PTRMEMFUNC_FN_TYPE (t);
|
|
goto offset_type;
|
|
}
|
|
|
|
switch (TREE_CODE (t))
|
|
{
|
|
case POINTER_TYPE:
|
|
case REFERENCE_TYPE:
|
|
{
|
|
tree sub = TREE_TYPE (t);
|
|
|
|
dump_type_prefix (sub, flags);
|
|
if (TREE_CODE (sub) == ARRAY_TYPE
|
|
|| TREE_CODE (sub) == FUNCTION_TYPE)
|
|
{
|
|
pp_cxx_whitespace (cxx_pp);
|
|
pp_cxx_left_paren (cxx_pp);
|
|
}
|
|
if (TREE_CODE (t) == POINTER_TYPE)
|
|
pp_character(cxx_pp, '*');
|
|
else if (TREE_CODE (t) == REFERENCE_TYPE)
|
|
{
|
|
if (TYPE_REF_IS_RVALUE (t))
|
|
pp_string (cxx_pp, "&&");
|
|
else
|
|
pp_character (cxx_pp, '&');
|
|
}
|
|
pp_base (cxx_pp)->padding = pp_before;
|
|
pp_cxx_cv_qualifier_seq (cxx_pp, t);
|
|
}
|
|
break;
|
|
|
|
case OFFSET_TYPE:
|
|
offset_type:
|
|
dump_type_prefix (TREE_TYPE (t), flags);
|
|
if (TREE_CODE (t) == OFFSET_TYPE) /* pmfs deal with this in d_t_p */
|
|
{
|
|
pp_maybe_space (cxx_pp);
|
|
if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
|
|
pp_cxx_left_paren (cxx_pp);
|
|
dump_type (TYPE_OFFSET_BASETYPE (t), flags);
|
|
pp_cxx_colon_colon (cxx_pp);
|
|
}
|
|
pp_cxx_star (cxx_pp);
|
|
pp_cxx_cv_qualifier_seq (cxx_pp, t);
|
|
pp_base (cxx_pp)->padding = pp_before;
|
|
break;
|
|
|
|
/* This can be reached without a pointer when dealing with
|
|
templates, e.g. std::is_function. */
|
|
case FUNCTION_TYPE:
|
|
dump_type_prefix (TREE_TYPE (t), flags);
|
|
break;
|
|
|
|
case METHOD_TYPE:
|
|
dump_type_prefix (TREE_TYPE (t), flags);
|
|
pp_maybe_space (cxx_pp);
|
|
pp_cxx_left_paren (cxx_pp);
|
|
dump_aggr_type (TYPE_METHOD_BASETYPE (t), flags);
|
|
pp_cxx_colon_colon (cxx_pp);
|
|
break;
|
|
|
|
case ARRAY_TYPE:
|
|
dump_type_prefix (TREE_TYPE (t), flags);
|
|
break;
|
|
|
|
case ENUMERAL_TYPE:
|
|
case IDENTIFIER_NODE:
|
|
case INTEGER_TYPE:
|
|
case BOOLEAN_TYPE:
|
|
case REAL_TYPE:
|
|
case RECORD_TYPE:
|
|
case TEMPLATE_TYPE_PARM:
|
|
case TEMPLATE_TEMPLATE_PARM:
|
|
case BOUND_TEMPLATE_TEMPLATE_PARM:
|
|
case TREE_LIST:
|
|
case TYPE_DECL:
|
|
case TREE_VEC:
|
|
case UNION_TYPE:
|
|
case UNKNOWN_TYPE:
|
|
case VOID_TYPE:
|
|
case TYPENAME_TYPE:
|
|
case COMPLEX_TYPE:
|
|
case VECTOR_TYPE:
|
|
case TYPEOF_TYPE:
|
|
case DECLTYPE_TYPE:
|
|
case TYPE_PACK_EXPANSION:
|
|
case FIXED_POINT_TYPE:
|
|
dump_type (t, flags);
|
|
pp_base (cxx_pp)->padding = pp_before;
|
|
break;
|
|
|
|
default:
|
|
pp_unsupported_tree (cxx_pp, t);
|
|
/* fall through. */
|
|
case ERROR_MARK:
|
|
pp_string (cxx_pp, M_("<typeprefixerror>"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Dump the suffix of type T, under control of FLAGS. This is the part
|
|
which appears after the identifier (or function parms). */
|
|
|
|
static void
|
|
dump_type_suffix (tree t, int flags)
|
|
{
|
|
if (TYPE_PTRMEMFUNC_P (t))
|
|
t = TYPE_PTRMEMFUNC_FN_TYPE (t);
|
|
|
|
switch (TREE_CODE (t))
|
|
{
|
|
case POINTER_TYPE:
|
|
case REFERENCE_TYPE:
|
|
case OFFSET_TYPE:
|
|
if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE
|
|
|| TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE)
|
|
pp_cxx_right_paren (cxx_pp);
|
|
dump_type_suffix (TREE_TYPE (t), flags);
|
|
break;
|
|
|
|
case FUNCTION_TYPE:
|
|
case METHOD_TYPE:
|
|
{
|
|
tree arg;
|
|
if (TREE_CODE (t) == METHOD_TYPE)
|
|
/* Can only be reached through a pointer. */
|
|
pp_cxx_right_paren (cxx_pp);
|
|
arg = TYPE_ARG_TYPES (t);
|
|
if (TREE_CODE (t) == METHOD_TYPE)
|
|
arg = TREE_CHAIN (arg);
|
|
|
|
/* Function pointers don't have default args. Not in standard C++,
|
|
anyway; they may in g++, but we'll just pretend otherwise. */
|
|
dump_parameters (arg, flags & ~TFF_FUNCTION_DEFAULT_ARGUMENTS);
|
|
|
|
if (TREE_CODE (t) == METHOD_TYPE)
|
|
pp_cxx_cv_qualifier_seq
|
|
(cxx_pp, TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t))));
|
|
else
|
|
pp_cxx_cv_qualifier_seq (cxx_pp, t);
|
|
dump_exception_spec (TYPE_RAISES_EXCEPTIONS (t), flags);
|
|
dump_type_suffix (TREE_TYPE (t), flags);
|
|
break;
|
|
}
|
|
|
|
case ARRAY_TYPE:
|
|
pp_maybe_space (cxx_pp);
|
|
pp_cxx_left_bracket (cxx_pp);
|
|
if (TYPE_DOMAIN (t))
|
|
{
|
|
tree dtype = TYPE_DOMAIN (t);
|
|
tree max = TYPE_MAX_VALUE (dtype);
|
|
if (host_integerp (max, 0))
|
|
pp_wide_integer (cxx_pp, tree_low_cst (max, 0) + 1);
|
|
else if (TREE_CODE (max) == MINUS_EXPR)
|
|
dump_expr (TREE_OPERAND (max, 0),
|
|
flags & ~TFF_EXPR_IN_PARENS);
|
|
else
|
|
dump_expr (fold_build2_loc (input_location,
|
|
PLUS_EXPR, dtype, max,
|
|
build_int_cst (dtype, 1)),
|
|
flags & ~TFF_EXPR_IN_PARENS);
|
|
}
|
|
pp_cxx_right_bracket (cxx_pp);
|
|
dump_type_suffix (TREE_TYPE (t), flags);
|
|
break;
|
|
|
|
case ENUMERAL_TYPE:
|
|
case IDENTIFIER_NODE:
|
|
case INTEGER_TYPE:
|
|
case BOOLEAN_TYPE:
|
|
case REAL_TYPE:
|
|
case RECORD_TYPE:
|
|
case TEMPLATE_TYPE_PARM:
|
|
case TEMPLATE_TEMPLATE_PARM:
|
|
case BOUND_TEMPLATE_TEMPLATE_PARM:
|
|
case TREE_LIST:
|
|
case TYPE_DECL:
|
|
case TREE_VEC:
|
|
case UNION_TYPE:
|
|
case UNKNOWN_TYPE:
|
|
case VOID_TYPE:
|
|
case TYPENAME_TYPE:
|
|
case COMPLEX_TYPE:
|
|
case VECTOR_TYPE:
|
|
case TYPEOF_TYPE:
|
|
case DECLTYPE_TYPE:
|
|
case TYPE_PACK_EXPANSION:
|
|
case FIXED_POINT_TYPE:
|
|
break;
|
|
|
|
default:
|
|
pp_unsupported_tree (cxx_pp, t);
|
|
case ERROR_MARK:
|
|
/* Don't mark it here, we should have already done in
|
|
dump_type_prefix. */
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
dump_global_iord (tree t)
|
|
{
|
|
const char *p = NULL;
|
|
|
|
if (DECL_GLOBAL_CTOR_P (t))
|
|
p = M_("(static initializers for %s)");
|
|
else if (DECL_GLOBAL_DTOR_P (t))
|
|
p = M_("(static destructors for %s)");
|
|
else
|
|
gcc_unreachable ();
|
|
|
|
pp_printf (pp_base (cxx_pp), p, input_filename);
|
|
}
|
|
|
|
static void
|
|
dump_simple_decl (tree t, tree type, int flags)
|
|
{
|
|
if (flags & TFF_DECL_SPECIFIERS)
|
|
{
|
|
dump_type_prefix (type, flags & ~TFF_UNQUALIFIED_NAME);
|
|
pp_maybe_space (cxx_pp);
|
|
}
|
|
if (! (flags & TFF_UNQUALIFIED_NAME)
|
|
&& (!DECL_INITIAL (t)
|
|
|| TREE_CODE (DECL_INITIAL (t)) != TEMPLATE_PARM_INDEX))
|
|
dump_scope (CP_DECL_CONTEXT (t), flags);
|
|
flags &= ~TFF_UNQUALIFIED_NAME;
|
|
if ((flags & TFF_DECL_SPECIFIERS)
|
|
&& DECL_TEMPLATE_PARM_P (t)
|
|
&& TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (t)))
|
|
pp_string (cxx_pp, "...");
|
|
if (DECL_NAME (t))
|
|
dump_decl (DECL_NAME (t), flags);
|
|
else
|
|
pp_string (cxx_pp, M_("<anonymous>"));
|
|
if (flags & TFF_DECL_SPECIFIERS)
|
|
dump_type_suffix (type, flags);
|
|
}
|
|
|
|
/* Dump a human readable string for the decl T under control of FLAGS. */
|
|
|
|
static void
|
|
dump_decl (tree t, int flags)
|
|
{
|
|
if (t == NULL_TREE)
|
|
return;
|
|
|
|
switch (TREE_CODE (t))
|
|
{
|
|
case TYPE_DECL:
|
|
/* Don't say 'typedef class A' */
|
|
if (DECL_ARTIFICIAL (t) && !DECL_SELF_REFERENCE_P (t))
|
|
{
|
|
if ((flags & TFF_DECL_SPECIFIERS)
|
|
&& TREE_CODE (TREE_TYPE (t)) == TEMPLATE_TYPE_PARM)
|
|
{
|
|
/* Say `class T' not just `T'. */
|
|
pp_cxx_ws_string (cxx_pp, "class");
|
|
|
|
/* Emit the `...' for a parameter pack. */
|
|
if (TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (t)))
|
|
pp_cxx_ws_string (cxx_pp, "...");
|
|
}
|
|
|
|
dump_type (TREE_TYPE (t), flags);
|
|
break;
|
|
}
|
|
if (flags & TFF_DECL_SPECIFIERS)
|
|
pp_cxx_ws_string (cxx_pp, "typedef");
|
|
dump_simple_decl (t, DECL_ORIGINAL_TYPE (t)
|
|
? DECL_ORIGINAL_TYPE (t) : TREE_TYPE (t),
|
|
flags);
|
|
break;
|
|
|
|
case VAR_DECL:
|
|
if (DECL_NAME (t) && VTABLE_NAME_P (DECL_NAME (t)))
|
|
{
|
|
pp_string (cxx_pp, M_("vtable for "));
|
|
gcc_assert (TYPE_P (DECL_CONTEXT (t)));
|
|
dump_type (DECL_CONTEXT (t), flags);
|
|
break;
|
|
}
|
|
/* Else fall through. */
|
|
case FIELD_DECL:
|
|
case PARM_DECL:
|
|
dump_simple_decl (t, TREE_TYPE (t), flags);
|
|
break;
|
|
|
|
case RESULT_DECL:
|
|
pp_string (cxx_pp, M_("<return value> "));
|
|
dump_simple_decl (t, TREE_TYPE (t), flags);
|
|
break;
|
|
|
|
case NAMESPACE_DECL:
|
|
if (flags & TFF_DECL_SPECIFIERS)
|
|
pp_cxx_declaration (cxx_pp, t);
|
|
else
|
|
{
|
|
if (! (flags & TFF_UNQUALIFIED_NAME))
|
|
dump_scope (CP_DECL_CONTEXT (t), flags);
|
|
flags &= ~TFF_UNQUALIFIED_NAME;
|
|
if (DECL_NAME (t) == NULL_TREE)
|
|
pp_string (cxx_pp, M_("<unnamed>"));
|
|
else
|
|
pp_cxx_tree_identifier (cxx_pp, DECL_NAME (t));
|
|
}
|
|
break;
|
|
|
|
case SCOPE_REF:
|
|
pp_expression (cxx_pp, t);
|
|
break;
|
|
|
|
case ARRAY_REF:
|
|
dump_decl (TREE_OPERAND (t, 0), flags);
|
|
pp_cxx_left_bracket (cxx_pp);
|
|
dump_decl (TREE_OPERAND (t, 1), flags);
|
|
pp_cxx_right_bracket (cxx_pp);
|
|
break;
|
|
|
|
/* So that we can do dump_decl on an aggr type. */
|
|
case RECORD_TYPE:
|
|
case UNION_TYPE:
|
|
case ENUMERAL_TYPE:
|
|
dump_type (t, flags);
|
|
break;
|
|
|
|
case BIT_NOT_EXPR:
|
|
/* This is a pseudo destructor call which has not been folded into
|
|
a PSEUDO_DTOR_EXPR yet. */
|
|
pp_cxx_complement (cxx_pp);
|
|
dump_type (TREE_OPERAND (t, 0), flags);
|
|
break;
|
|
|
|
case TYPE_EXPR:
|
|
gcc_unreachable ();
|
|
break;
|
|
|
|
/* These special cases are duplicated here so that other functions
|
|
can feed identifiers to error and get them demangled properly. */
|
|
case IDENTIFIER_NODE:
|
|
if (IDENTIFIER_TYPENAME_P (t))
|
|
{
|
|
pp_cxx_ws_string (cxx_pp, "operator");
|
|
/* Not exactly IDENTIFIER_TYPE_VALUE. */
|
|
dump_type (TREE_TYPE (t), flags);
|
|
break;
|
|
}
|
|
else
|
|
pp_cxx_tree_identifier (cxx_pp, t);
|
|
break;
|
|
|
|
case OVERLOAD:
|
|
if (OVL_CHAIN (t))
|
|
{
|
|
t = OVL_CURRENT (t);
|
|
if (DECL_CLASS_SCOPE_P (t))
|
|
{
|
|
dump_type (DECL_CONTEXT (t), flags);
|
|
pp_cxx_colon_colon (cxx_pp);
|
|
}
|
|
else if (DECL_CONTEXT (t))
|
|
{
|
|
dump_decl (DECL_CONTEXT (t), flags);
|
|
pp_cxx_colon_colon (cxx_pp);
|
|
}
|
|
dump_decl (DECL_NAME (t), flags);
|
|
break;
|
|
}
|
|
|
|
/* If there's only one function, just treat it like an ordinary
|
|
FUNCTION_DECL. */
|
|
t = OVL_CURRENT (t);
|
|
/* Fall through. */
|
|
|
|
case FUNCTION_DECL:
|
|
if (! DECL_LANG_SPECIFIC (t))
|
|
pp_string (cxx_pp, M_("<built-in>"));
|
|
else if (DECL_GLOBAL_CTOR_P (t) || DECL_GLOBAL_DTOR_P (t))
|
|
dump_global_iord (t);
|
|
else
|
|
dump_function_decl (t, flags);
|
|
break;
|
|
|
|
case TEMPLATE_DECL:
|
|
dump_template_decl (t, flags);
|
|
break;
|
|
|
|
case TEMPLATE_ID_EXPR:
|
|
{
|
|
tree name = TREE_OPERAND (t, 0);
|
|
|
|
if (is_overloaded_fn (name))
|
|
name = DECL_NAME (get_first_fn (name));
|
|
dump_decl (name, flags);
|
|
pp_cxx_begin_template_argument_list (cxx_pp);
|
|
if (TREE_OPERAND (t, 1))
|
|
dump_template_argument_list (TREE_OPERAND (t, 1), NULL_TREE, flags);
|
|
pp_cxx_end_template_argument_list (cxx_pp);
|
|
}
|
|
break;
|
|
|
|
case LABEL_DECL:
|
|
pp_cxx_tree_identifier (cxx_pp, DECL_NAME (t));
|
|
break;
|
|
|
|
case CONST_DECL:
|
|
if ((TREE_TYPE (t) != NULL_TREE && NEXT_CODE (t) == ENUMERAL_TYPE)
|
|
|| (DECL_INITIAL (t) &&
|
|
TREE_CODE (DECL_INITIAL (t)) == TEMPLATE_PARM_INDEX))
|
|
dump_simple_decl (t, TREE_TYPE (t), flags);
|
|
else if (DECL_NAME (t))
|
|
dump_decl (DECL_NAME (t), flags);
|
|
else if (DECL_INITIAL (t))
|
|
dump_expr (DECL_INITIAL (t), flags | TFF_EXPR_IN_PARENS);
|
|
else
|
|
pp_string (cxx_pp, M_("<enumerator>"));
|
|
break;
|
|
|
|
case USING_DECL:
|
|
pp_cxx_ws_string (cxx_pp, "using");
|
|
dump_type (USING_DECL_SCOPE (t), flags);
|
|
pp_cxx_colon_colon (cxx_pp);
|
|
dump_decl (DECL_NAME (t), flags);
|
|
break;
|
|
|
|
case STATIC_ASSERT:
|
|
pp_cxx_declaration (cxx_pp, t);
|
|
break;
|
|
|
|
case BASELINK:
|
|
dump_decl (BASELINK_FUNCTIONS (t), flags);
|
|
break;
|
|
|
|
case NON_DEPENDENT_EXPR:
|
|
dump_expr (t, flags);
|
|
break;
|
|
|
|
case TEMPLATE_TYPE_PARM:
|
|
if (flags & TFF_DECL_SPECIFIERS)
|
|
pp_cxx_declaration (cxx_pp, t);
|
|
else
|
|
pp_type_id (cxx_pp, t);
|
|
break;
|
|
|
|
case UNBOUND_CLASS_TEMPLATE:
|
|
case TYPE_PACK_EXPANSION:
|
|
case TREE_BINFO:
|
|
dump_type (t, flags);
|
|
break;
|
|
|
|
default:
|
|
pp_unsupported_tree (cxx_pp, t);
|
|
/* Fall through to error. */
|
|
|
|
case ERROR_MARK:
|
|
pp_string (cxx_pp, M_("<declaration error>"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Dump a template declaration T under control of FLAGS. This means the
|
|
'template <...> leaders plus the 'class X' or 'void fn(...)' part. */
|
|
|
|
static void
|
|
dump_template_decl (tree t, int flags)
|
|
{
|
|
tree orig_parms = DECL_TEMPLATE_PARMS (t);
|
|
tree parms;
|
|
int i;
|
|
|
|
if (flags & TFF_TEMPLATE_HEADER)
|
|
{
|
|
for (parms = orig_parms = nreverse (orig_parms);
|
|
parms;
|
|
parms = TREE_CHAIN (parms))
|
|
{
|
|
tree inner_parms = INNERMOST_TEMPLATE_PARMS (parms);
|
|
int len = TREE_VEC_LENGTH (inner_parms);
|
|
|
|
pp_cxx_ws_string (cxx_pp, "template");
|
|
pp_cxx_begin_template_argument_list (cxx_pp);
|
|
|
|
/* If we've shown the template prefix, we'd better show the
|
|
parameters' and decl's type too. */
|
|
flags |= TFF_DECL_SPECIFIERS;
|
|
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
if (i)
|
|
pp_separate_with_comma (cxx_pp);
|
|
dump_template_parameter (TREE_VEC_ELT (inner_parms, i), flags);
|
|
}
|
|
pp_cxx_end_template_argument_list (cxx_pp);
|
|
pp_cxx_whitespace (cxx_pp);
|
|
}
|
|
nreverse(orig_parms);
|
|
|
|
if (DECL_TEMPLATE_TEMPLATE_PARM_P (t))
|
|
{
|
|
/* Say `template<arg> class TT' not just `template<arg> TT'. */
|
|
pp_cxx_ws_string (cxx_pp, "class");
|
|
|
|
/* If this is a parameter pack, print the ellipsis. */
|
|
if (TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (t)))
|
|
pp_cxx_ws_string (cxx_pp, "...");
|
|
}
|
|
}
|
|
|
|
if (DECL_TEMPLATE_RESULT (t)
|
|
&& TREE_CODE (DECL_TEMPLATE_RESULT (t)) == TYPE_DECL)
|
|
dump_type (TREE_TYPE (t),
|
|
((flags & ~TFF_CLASS_KEY_OR_ENUM) | TFF_TEMPLATE_NAME
|
|
| (flags & TFF_DECL_SPECIFIERS ? TFF_CLASS_KEY_OR_ENUM : 0)));
|
|
else if (DECL_TEMPLATE_RESULT (t)
|
|
&& TREE_CODE (DECL_TEMPLATE_RESULT (t)) == VAR_DECL)
|
|
dump_decl (DECL_TEMPLATE_RESULT (t), flags | TFF_TEMPLATE_NAME);
|
|
else
|
|
{
|
|
gcc_assert (TREE_TYPE (t));
|
|
switch (NEXT_CODE (t))
|
|
{
|
|
case METHOD_TYPE:
|
|
case FUNCTION_TYPE:
|
|
dump_function_decl (t, flags | TFF_TEMPLATE_NAME);
|
|
break;
|
|
default:
|
|
/* This case can occur with some invalid code. */
|
|
dump_type (TREE_TYPE (t),
|
|
(flags & ~TFF_CLASS_KEY_OR_ENUM) | TFF_TEMPLATE_NAME
|
|
| (flags & TFF_DECL_SPECIFIERS
|
|
? TFF_CLASS_KEY_OR_ENUM : 0));
|
|
}
|
|
}
|
|
}
|
|
|
|
/* find_typenames looks through the type of the function template T
|
|
and returns a VEC containing any typedefs or TYPENAME_TYPEs it finds. */
|
|
|
|
struct find_typenames_t
|
|
{
|
|
struct pointer_set_t *p_set;
|
|
VEC (tree,gc) *typenames;
|
|
};
|
|
|
|
static tree
|
|
find_typenames_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, void *data)
|
|
{
|
|
struct find_typenames_t *d = (struct find_typenames_t *)data;
|
|
tree mv = NULL_TREE;
|
|
|
|
if (TYPE_P (*tp) && is_typedef_decl (TYPE_NAME (*tp)))
|
|
/* Add the type of the typedef without any additional cv-quals. */
|
|
mv = TREE_TYPE (TYPE_NAME (*tp));
|
|
else if (TREE_CODE (*tp) == TYPENAME_TYPE)
|
|
/* Add the typename without any cv-qualifiers. */
|
|
mv = TYPE_MAIN_VARIANT (*tp);
|
|
|
|
if (mv && (mv == *tp || !pointer_set_insert (d->p_set, mv)))
|
|
VEC_safe_push (tree, gc, d->typenames, mv);
|
|
|
|
/* Search into class template arguments, which cp_walk_subtrees
|
|
doesn't do. */
|
|
if (CLASS_TYPE_P (*tp) && CLASSTYPE_TEMPLATE_INFO (*tp))
|
|
cp_walk_tree (&CLASSTYPE_TI_ARGS (*tp), find_typenames_r,
|
|
data, d->p_set);
|
|
|
|
return NULL_TREE;
|
|
}
|
|
|
|
static VEC(tree,gc) *
|
|
find_typenames (tree t)
|
|
{
|
|
struct find_typenames_t ft;
|
|
ft.p_set = pointer_set_create ();
|
|
ft.typenames = NULL;
|
|
cp_walk_tree (&TREE_TYPE (DECL_TEMPLATE_RESULT (t)),
|
|
find_typenames_r, &ft, ft.p_set);
|
|
pointer_set_destroy (ft.p_set);
|
|
return ft.typenames;
|
|
}
|
|
|
|
/* Pretty print a function decl. There are several ways we want to print a
|
|
function declaration. The TFF_ bits in FLAGS tells us how to behave.
|
|
As error can only apply the '#' flag once to give 0 and 1 for V, there
|
|
is %D which doesn't print the throw specs, and %F which does. */
|
|
|
|
static void
|
|
dump_function_decl (tree t, int flags)
|
|
{
|
|
tree fntype;
|
|
tree parmtypes;
|
|
tree cname = NULL_TREE;
|
|
tree template_args = NULL_TREE;
|
|
tree template_parms = NULL_TREE;
|
|
int show_return = flags & TFF_RETURN_TYPE || flags & TFF_DECL_SPECIFIERS;
|
|
int do_outer_scope = ! (flags & TFF_UNQUALIFIED_NAME);
|
|
tree exceptions;
|
|
VEC(tree,gc) *typenames = NULL;
|
|
|
|
flags &= ~TFF_UNQUALIFIED_NAME;
|
|
if (TREE_CODE (t) == TEMPLATE_DECL)
|
|
t = DECL_TEMPLATE_RESULT (t);
|
|
|
|
/* Save the exceptions, in case t is a specialization and we are
|
|
emitting an error about incompatible specifications. */
|
|
exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (t));
|
|
|
|
/* Pretty print template instantiations only. */
|
|
if (DECL_USE_TEMPLATE (t) && DECL_TEMPLATE_INFO (t)
|
|
&& flag_pretty_templates)
|
|
{
|
|
tree tmpl;
|
|
|
|
template_args = DECL_TI_ARGS (t);
|
|
tmpl = most_general_template (t);
|
|
if (tmpl && TREE_CODE (tmpl) == TEMPLATE_DECL)
|
|
{
|
|
template_parms = DECL_TEMPLATE_PARMS (tmpl);
|
|
t = tmpl;
|
|
typenames = find_typenames (t);
|
|
}
|
|
}
|
|
|
|
fntype = TREE_TYPE (t);
|
|
parmtypes = FUNCTION_FIRST_USER_PARMTYPE (t);
|
|
|
|
if (DECL_CLASS_SCOPE_P (t))
|
|
cname = DECL_CONTEXT (t);
|
|
/* This is for partially instantiated template methods. */
|
|
else if (TREE_CODE (fntype) == METHOD_TYPE)
|
|
cname = TREE_TYPE (TREE_VALUE (parmtypes));
|
|
|
|
if (!(flags & TFF_DECL_SPECIFIERS))
|
|
/* OK */;
|
|
else if (DECL_STATIC_FUNCTION_P (t))
|
|
pp_cxx_ws_string (cxx_pp, "static");
|
|
else if (DECL_VIRTUAL_P (t))
|
|
pp_cxx_ws_string (cxx_pp, "virtual");
|
|
|
|
/* Print the return type? */
|
|
if (show_return)
|
|
show_return = !DECL_CONV_FN_P (t) && !DECL_CONSTRUCTOR_P (t)
|
|
&& !DECL_DESTRUCTOR_P (t);
|
|
if (show_return)
|
|
dump_type_prefix (TREE_TYPE (fntype), flags);
|
|
|
|
/* Print the function name. */
|
|
if (!do_outer_scope)
|
|
/* Nothing. */;
|
|
else if (cname)
|
|
{
|
|
dump_type (cname, flags);
|
|
pp_cxx_colon_colon (cxx_pp);
|
|
}
|
|
else
|
|
dump_scope (CP_DECL_CONTEXT (t), flags);
|
|
|
|
dump_function_name (t, flags);
|
|
|
|
if (!(flags & TFF_NO_FUNCTION_ARGUMENTS))
|
|
{
|
|
dump_parameters (parmtypes, flags);
|
|
|
|
if (TREE_CODE (fntype) == METHOD_TYPE)
|
|
{
|
|
pp_base (cxx_pp)->padding = pp_before;
|
|
pp_cxx_cv_qualifier_seq
|
|
(cxx_pp, TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (fntype))));
|
|
}
|
|
|
|
if (flags & TFF_EXCEPTION_SPECIFICATION)
|
|
{
|
|
pp_base (cxx_pp)->padding = pp_before;
|
|
dump_exception_spec (exceptions, flags);
|
|
}
|
|
|
|
if (show_return)
|
|
dump_type_suffix (TREE_TYPE (fntype), flags);
|
|
}
|
|
|
|
/* If T is a template instantiation, dump the parameter binding. */
|
|
if (template_parms != NULL_TREE && template_args != NULL_TREE)
|
|
{
|
|
pp_cxx_whitespace (cxx_pp);
|
|
pp_cxx_left_bracket (cxx_pp);
|
|
pp_cxx_ws_string (cxx_pp, M_("with"));
|
|
pp_cxx_whitespace (cxx_pp);
|
|
dump_template_bindings (template_parms, template_args, typenames);
|
|
pp_cxx_right_bracket (cxx_pp);
|
|
}
|
|
}
|
|
|
|
/* Print a parameter list. If this is for a member function, the
|
|
member object ptr (and any other hidden args) should have
|
|
already been removed. */
|
|
|
|
static void
|
|
dump_parameters (tree parmtypes, int flags)
|
|
{
|
|
int first = 1;
|
|
pp_cxx_left_paren (cxx_pp);
|
|
|
|
for (first = 1; parmtypes != void_list_node;
|
|
parmtypes = TREE_CHAIN (parmtypes))
|
|
{
|
|
if (!first)
|
|
pp_separate_with_comma (cxx_pp);
|
|
first = 0;
|
|
if (!parmtypes)
|
|
{
|
|
pp_cxx_ws_string (cxx_pp, "...");
|
|
break;
|
|
}
|
|
|
|
dump_type (TREE_VALUE (parmtypes), flags);
|
|
|
|
if ((flags & TFF_FUNCTION_DEFAULT_ARGUMENTS) && TREE_PURPOSE (parmtypes))
|
|
{
|
|
pp_cxx_whitespace (cxx_pp);
|
|
pp_equal (cxx_pp);
|
|
pp_cxx_whitespace (cxx_pp);
|
|
dump_expr (TREE_PURPOSE (parmtypes), flags | TFF_EXPR_IN_PARENS);
|
|
}
|
|
}
|
|
|
|
pp_cxx_right_paren (cxx_pp);
|
|
}
|
|
|
|
/* Print an exception specification. T is the exception specification. */
|
|
|
|
static void
|
|
dump_exception_spec (tree t, int flags)
|
|
{
|
|
if (t)
|
|
{
|
|
pp_cxx_ws_string (cxx_pp, "throw");
|
|
pp_cxx_whitespace (cxx_pp);
|
|
pp_cxx_left_paren (cxx_pp);
|
|
if (TREE_VALUE (t) != NULL_TREE)
|
|
while (1)
|
|
{
|
|
dump_type (TREE_VALUE (t), flags);
|
|
t = TREE_CHAIN (t);
|
|
if (!t)
|
|
break;
|
|
pp_separate_with_comma (cxx_pp);
|
|
}
|
|
pp_cxx_right_paren (cxx_pp);
|
|
}
|
|
}
|
|
|
|
/* Handle the function name for a FUNCTION_DECL node, grokking operators
|
|
and destructors properly. */
|
|
|
|
static void
|
|
dump_function_name (tree t, int flags)
|
|
{
|
|
tree name = DECL_NAME (t);
|
|
|
|
/* We can get here with a decl that was synthesized by language-
|
|
independent machinery (e.g. coverage.c) in which case it won't
|
|
have a lang_specific structure attached and DECL_CONSTRUCTOR_P
|
|
will crash. In this case it is safe just to print out the
|
|
literal name. */
|
|
if (!DECL_LANG_SPECIFIC (t))
|
|
{
|
|
pp_cxx_tree_identifier (cxx_pp, name);
|
|
return;
|
|
}
|
|
|
|
if (TREE_CODE (t) == TEMPLATE_DECL)
|
|
t = DECL_TEMPLATE_RESULT (t);
|
|
|
|
/* Don't let the user see __comp_ctor et al. */
|
|
if (DECL_CONSTRUCTOR_P (t)
|
|
|| DECL_DESTRUCTOR_P (t))
|
|
name = constructor_name (DECL_CONTEXT (t));
|
|
|
|
if (DECL_DESTRUCTOR_P (t))
|
|
{
|
|
pp_cxx_complement (cxx_pp);
|
|
dump_decl (name, TFF_PLAIN_IDENTIFIER);
|
|
}
|
|
else if (DECL_CONV_FN_P (t))
|
|
{
|
|
/* This cannot use the hack that the operator's return
|
|
type is stashed off of its name because it may be
|
|
used for error reporting. In the case of conflicting
|
|
declarations, both will have the same name, yet
|
|
the types will be different, hence the TREE_TYPE field
|
|
of the first name will be clobbered by the second. */
|
|
pp_cxx_ws_string (cxx_pp, "operator");
|
|
dump_type (TREE_TYPE (TREE_TYPE (t)), flags);
|
|
}
|
|
else if (name && IDENTIFIER_OPNAME_P (name))
|
|
pp_cxx_tree_identifier (cxx_pp, name);
|
|
else
|
|
dump_decl (name, flags);
|
|
|
|
if (DECL_TEMPLATE_INFO (t)
|
|
&& !DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (t)
|
|
&& (TREE_CODE (DECL_TI_TEMPLATE (t)) != TEMPLATE_DECL
|
|
|| PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (t))))
|
|
dump_template_parms (DECL_TEMPLATE_INFO (t), !DECL_USE_TEMPLATE (t), flags);
|
|
}
|
|
|
|
/* Dump the template parameters from the template info INFO under control of
|
|
FLAGS. PRIMARY indicates whether this is a primary template decl, or
|
|
specialization (partial or complete). For partial specializations we show
|
|
the specialized parameter values. For a primary template we show no
|
|
decoration. */
|
|
|
|
static void
|
|
dump_template_parms (tree info, int primary, int flags)
|
|
{
|
|
tree args = info ? TI_ARGS (info) : NULL_TREE;
|
|
|
|
if (primary && flags & TFF_TEMPLATE_NAME)
|
|
return;
|
|
flags &= ~(TFF_CLASS_KEY_OR_ENUM | TFF_TEMPLATE_NAME);
|
|
pp_cxx_begin_template_argument_list (cxx_pp);
|
|
|
|
/* Be careful only to print things when we have them, so as not
|
|
to crash producing error messages. */
|
|
if (args && !primary)
|
|
{
|
|
int len, ix;
|
|
/* We don't know the parms for a friend template specialization. */
|
|
tree params = (TREE_CODE (TI_TEMPLATE (info)) == TEMPLATE_DECL
|
|
? DECL_INNERMOST_TEMPLATE_PARMS (TI_TEMPLATE (info))
|
|
: NULL_TREE);
|
|
|
|
len = count_non_default_template_args (args, params, flags);
|
|
|
|
args = INNERMOST_TEMPLATE_ARGS (args);
|
|
for (ix = 0; ix != len; ix++)
|
|
{
|
|
tree arg = TREE_VEC_ELT (args, ix);
|
|
|
|
/* Only print a comma if we know there is an argument coming. In
|
|
the case of an empty template argument pack, no actual
|
|
argument will be printed. */
|
|
if (ix
|
|
&& (!ARGUMENT_PACK_P (arg)
|
|
|| TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg)) > 0))
|
|
pp_separate_with_comma (cxx_pp);
|
|
|
|
if (!arg)
|
|
pp_string (cxx_pp, M_("<template parameter error>"));
|
|
else
|
|
dump_template_argument (arg, flags);
|
|
}
|
|
}
|
|
else if (primary)
|
|
{
|
|
tree tpl = TI_TEMPLATE (info);
|
|
tree parms = DECL_TEMPLATE_PARMS (tpl);
|
|
int len, ix;
|
|
|
|
parms = TREE_CODE (parms) == TREE_LIST ? TREE_VALUE (parms) : NULL_TREE;
|
|
len = parms ? TREE_VEC_LENGTH (parms) : 0;
|
|
|
|
for (ix = 0; ix != len; ix++)
|
|
{
|
|
tree parm;
|
|
|
|
if (TREE_VEC_ELT (parms, ix) == error_mark_node)
|
|
{
|
|
pp_string (cxx_pp, M_("<template parameter error>"));
|
|
continue;
|
|
}
|
|
|
|
parm = TREE_VALUE (TREE_VEC_ELT (parms, ix));
|
|
|
|
if (ix)
|
|
pp_separate_with_comma (cxx_pp);
|
|
|
|
dump_decl (parm, flags & ~TFF_DECL_SPECIFIERS);
|
|
}
|
|
}
|
|
pp_cxx_end_template_argument_list (cxx_pp);
|
|
}
|
|
|
|
/* Print out the arguments of CALL_EXPR T as a parenthesized list using
|
|
flags FLAGS. Skip over the first argument if SKIPFIRST is true. */
|
|
|
|
static void
|
|
dump_call_expr_args (tree t, int flags, bool skipfirst)
|
|
{
|
|
tree arg;
|
|
call_expr_arg_iterator iter;
|
|
|
|
pp_cxx_left_paren (cxx_pp);
|
|
FOR_EACH_CALL_EXPR_ARG (arg, iter, t)
|
|
{
|
|
if (skipfirst)
|
|
skipfirst = false;
|
|
else
|
|
{
|
|
dump_expr (arg, flags | TFF_EXPR_IN_PARENS);
|
|
if (more_call_expr_args_p (&iter))
|
|
pp_separate_with_comma (cxx_pp);
|
|
}
|
|
}
|
|
pp_cxx_right_paren (cxx_pp);
|
|
}
|
|
|
|
/* Print out the arguments of AGGR_INIT_EXPR T as a parenthesized list
|
|
using flags FLAGS. Skip over the first argument if SKIPFIRST is
|
|
true. */
|
|
|
|
static void
|
|
dump_aggr_init_expr_args (tree t, int flags, bool skipfirst)
|
|
{
|
|
tree arg;
|
|
aggr_init_expr_arg_iterator iter;
|
|
|
|
pp_cxx_left_paren (cxx_pp);
|
|
FOR_EACH_AGGR_INIT_EXPR_ARG (arg, iter, t)
|
|
{
|
|
if (skipfirst)
|
|
skipfirst = false;
|
|
else
|
|
{
|
|
dump_expr (arg, flags | TFF_EXPR_IN_PARENS);
|
|
if (more_aggr_init_expr_args_p (&iter))
|
|
pp_separate_with_comma (cxx_pp);
|
|
}
|
|
}
|
|
pp_cxx_right_paren (cxx_pp);
|
|
}
|
|
|
|
/* Print out a list of initializers (subr of dump_expr). */
|
|
|
|
static void
|
|
dump_expr_list (tree l, int flags)
|
|
{
|
|
while (l)
|
|
{
|
|
dump_expr (TREE_VALUE (l), flags | TFF_EXPR_IN_PARENS);
|
|
l = TREE_CHAIN (l);
|
|
if (l)
|
|
pp_separate_with_comma (cxx_pp);
|
|
}
|
|
}
|
|
|
|
/* Print out a vector of initializers (subr of dump_expr). */
|
|
|
|
static void
|
|
dump_expr_init_vec (VEC(constructor_elt,gc) *v, int flags)
|
|
{
|
|
unsigned HOST_WIDE_INT idx;
|
|
tree value;
|
|
|
|
FOR_EACH_CONSTRUCTOR_VALUE (v, idx, value)
|
|
{
|
|
dump_expr (value, flags | TFF_EXPR_IN_PARENS);
|
|
if (idx != VEC_length (constructor_elt, v) - 1)
|
|
pp_separate_with_comma (cxx_pp);
|
|
}
|
|
}
|
|
|
|
|
|
/* We've gotten an indirect REFERENCE (an OBJ_TYPE_REF) to a virtual
|
|
function. Resolve it to a close relative -- in the sense of static
|
|
type -- variant being overridden. That is close to what was written in
|
|
the source code. Subroutine of dump_expr. */
|
|
|
|
static tree
|
|
resolve_virtual_fun_from_obj_type_ref (tree ref)
|
|
{
|
|
tree obj_type = TREE_TYPE (OBJ_TYPE_REF_OBJECT (ref));
|
|
HOST_WIDE_INT index = tree_low_cst (OBJ_TYPE_REF_TOKEN (ref), 1);
|
|
tree fun = BINFO_VIRTUALS (TYPE_BINFO (TREE_TYPE (obj_type)));
|
|
while (index)
|
|
{
|
|
fun = TREE_CHAIN (fun);
|
|
index -= (TARGET_VTABLE_USES_DESCRIPTORS
|
|
? TARGET_VTABLE_USES_DESCRIPTORS : 1);
|
|
}
|
|
|
|
return BV_FN (fun);
|
|
}
|
|
|
|
/* Print out an expression E under control of FLAGS. */
|
|
|
|
static void
|
|
dump_expr (tree t, int flags)
|
|
{
|
|
if (t == 0)
|
|
return;
|
|
|
|
if (STATEMENT_CLASS_P (t))
|
|
{
|
|
pp_cxx_ws_string (cxx_pp, M_("<statement>"));
|
|
return;
|
|
}
|
|
|
|
switch (TREE_CODE (t))
|
|
{
|
|
case VAR_DECL:
|
|
case PARM_DECL:
|
|
case FIELD_DECL:
|
|
case CONST_DECL:
|
|
case FUNCTION_DECL:
|
|
case TEMPLATE_DECL:
|
|
case NAMESPACE_DECL:
|
|
case LABEL_DECL:
|
|
case OVERLOAD:
|
|
case IDENTIFIER_NODE:
|
|
dump_decl (t, (flags & ~TFF_DECL_SPECIFIERS) | TFF_NO_FUNCTION_ARGUMENTS);
|
|
break;
|
|
|
|
case INTEGER_CST:
|
|
case REAL_CST:
|
|
case STRING_CST:
|
|
case COMPLEX_CST:
|
|
pp_constant (cxx_pp, t);
|
|
break;
|
|
|
|
case THROW_EXPR:
|
|
/* While waiting for caret diagnostics, avoid printing
|
|
__cxa_allocate_exception, __cxa_throw, and the like. */
|
|
pp_cxx_ws_string (cxx_pp, M_("<throw-expression>"));
|
|
break;
|
|
|
|
case PTRMEM_CST:
|
|
pp_ampersand (cxx_pp);
|
|
dump_type (PTRMEM_CST_CLASS (t), flags);
|
|
pp_cxx_colon_colon (cxx_pp);
|
|
pp_cxx_tree_identifier (cxx_pp, DECL_NAME (PTRMEM_CST_MEMBER (t)));
|
|
break;
|
|
|
|
case COMPOUND_EXPR:
|
|
pp_cxx_left_paren (cxx_pp);
|
|
dump_expr (TREE_OPERAND (t, 0), flags | TFF_EXPR_IN_PARENS);
|
|
pp_separate_with_comma (cxx_pp);
|
|
dump_expr (TREE_OPERAND (t, 1), flags | TFF_EXPR_IN_PARENS);
|
|
pp_cxx_right_paren (cxx_pp);
|
|
break;
|
|
|
|
case COND_EXPR:
|
|
pp_cxx_left_paren (cxx_pp);
|
|
dump_expr (TREE_OPERAND (t, 0), flags | TFF_EXPR_IN_PARENS);
|
|
pp_string (cxx_pp, " ? ");
|
|
dump_expr (TREE_OPERAND (t, 1), flags | TFF_EXPR_IN_PARENS);
|
|
pp_string (cxx_pp, " : ");
|
|
dump_expr (TREE_OPERAND (t, 2), flags | TFF_EXPR_IN_PARENS);
|
|
pp_cxx_right_paren (cxx_pp);
|
|
break;
|
|
|
|
case SAVE_EXPR:
|
|
if (TREE_HAS_CONSTRUCTOR (t))
|
|
{
|
|
pp_cxx_ws_string (cxx_pp, "new");
|
|
pp_cxx_whitespace (cxx_pp);
|
|
dump_type (TREE_TYPE (TREE_TYPE (t)), flags);
|
|
}
|
|
else
|
|
dump_expr (TREE_OPERAND (t, 0), flags | TFF_EXPR_IN_PARENS);
|
|
break;
|
|
|
|
case AGGR_INIT_EXPR:
|
|
{
|
|
tree fn = NULL_TREE;
|
|
|
|
if (TREE_CODE (AGGR_INIT_EXPR_FN (t)) == ADDR_EXPR)
|
|
fn = TREE_OPERAND (AGGR_INIT_EXPR_FN (t), 0);
|
|
|
|
if (fn && TREE_CODE (fn) == FUNCTION_DECL)
|
|
{
|
|
if (DECL_CONSTRUCTOR_P (fn))
|
|
dump_type (DECL_CONTEXT (fn), flags);
|
|
else
|
|
dump_decl (fn, 0);
|
|
}
|
|
else
|
|
dump_expr (AGGR_INIT_EXPR_FN (t), 0);
|
|
}
|
|
dump_aggr_init_expr_args (t, flags, true);
|
|
break;
|
|
|
|
case CALL_EXPR:
|
|
{
|
|
tree fn = CALL_EXPR_FN (t);
|
|
bool skipfirst = false;
|
|
|
|
if (TREE_CODE (fn) == ADDR_EXPR)
|
|
fn = TREE_OPERAND (fn, 0);
|
|
|
|
/* Nobody is interested in seeing the guts of vcalls. */
|
|
if (TREE_CODE (fn) == OBJ_TYPE_REF)
|
|
fn = resolve_virtual_fun_from_obj_type_ref (fn);
|
|
|
|
if (TREE_TYPE (fn) != NULL_TREE && NEXT_CODE (fn) == METHOD_TYPE)
|
|
{
|
|
tree ob = CALL_EXPR_ARG (t, 0);
|
|
if (TREE_CODE (ob) == ADDR_EXPR)
|
|
{
|
|
dump_expr (TREE_OPERAND (ob, 0), flags | TFF_EXPR_IN_PARENS);
|
|
pp_cxx_dot (cxx_pp);
|
|
}
|
|
else if (TREE_CODE (ob) != PARM_DECL
|
|
|| strcmp (IDENTIFIER_POINTER (DECL_NAME (ob)), "this"))
|
|
{
|
|
dump_expr (ob, flags | TFF_EXPR_IN_PARENS);
|
|
pp_cxx_arrow (cxx_pp);
|
|
}
|
|
skipfirst = true;
|
|
}
|
|
dump_expr (fn, flags | TFF_EXPR_IN_PARENS);
|
|
dump_call_expr_args (t, flags, skipfirst);
|
|
}
|
|
break;
|
|
|
|
case TARGET_EXPR:
|
|
/* Note that this only works for G++ target exprs. If somebody
|
|
builds a general TARGET_EXPR, there's no way to represent that
|
|
it initializes anything other that the parameter slot for the
|
|
default argument. Note we may have cleared out the first
|
|
operand in expand_expr, so don't go killing ourselves. */
|
|
if (TREE_OPERAND (t, 1))
|
|
dump_expr (TREE_OPERAND (t, 1), flags | TFF_EXPR_IN_PARENS);
|
|
break;
|
|
|
|
case POINTER_PLUS_EXPR:
|
|
dump_binary_op ("+", t, flags);
|
|
break;
|
|
|
|
case INIT_EXPR:
|
|
case MODIFY_EXPR:
|
|
case PLUS_EXPR:
|
|
case MINUS_EXPR:
|
|
case MULT_EXPR:
|
|
case TRUNC_DIV_EXPR:
|
|
case TRUNC_MOD_EXPR:
|
|
case MIN_EXPR:
|
|
case MAX_EXPR:
|
|
case LSHIFT_EXPR:
|
|
case RSHIFT_EXPR:
|
|
case BIT_IOR_EXPR:
|
|
case BIT_XOR_EXPR:
|
|
case BIT_AND_EXPR:
|
|
case TRUTH_ANDIF_EXPR:
|
|
case TRUTH_ORIF_EXPR:
|
|
case LT_EXPR:
|
|
case LE_EXPR:
|
|
case GT_EXPR:
|
|
case GE_EXPR:
|
|
case EQ_EXPR:
|
|
case NE_EXPR:
|
|
case EXACT_DIV_EXPR:
|
|
dump_binary_op (operator_name_info[(int) TREE_CODE (t)].name, t, flags);
|
|
break;
|
|
|
|
case CEIL_DIV_EXPR:
|
|
case FLOOR_DIV_EXPR:
|
|
case ROUND_DIV_EXPR:
|
|
case RDIV_EXPR:
|
|
dump_binary_op ("/", t, flags);
|
|
break;
|
|
|
|
case CEIL_MOD_EXPR:
|
|
case FLOOR_MOD_EXPR:
|
|
case ROUND_MOD_EXPR:
|
|
dump_binary_op ("%", t, flags);
|
|
break;
|
|
|
|
case COMPONENT_REF:
|
|
{
|
|
tree ob = TREE_OPERAND (t, 0);
|
|
if (TREE_CODE (ob) == INDIRECT_REF)
|
|
{
|
|
ob = TREE_OPERAND (ob, 0);
|
|
if (TREE_CODE (ob) != PARM_DECL
|
|
|| (DECL_NAME (ob)
|
|
&& strcmp (IDENTIFIER_POINTER (DECL_NAME (ob)), "this")))
|
|
{
|
|
dump_expr (ob, flags | TFF_EXPR_IN_PARENS);
|
|
pp_cxx_arrow (cxx_pp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dump_expr (ob, flags | TFF_EXPR_IN_PARENS);
|
|
pp_cxx_dot (cxx_pp);
|
|
}
|
|
dump_expr (TREE_OPERAND (t, 1), flags & ~TFF_EXPR_IN_PARENS);
|
|
}
|
|
break;
|
|
|
|
case ARRAY_REF:
|
|
dump_expr (TREE_OPERAND (t, 0), flags | TFF_EXPR_IN_PARENS);
|
|
pp_cxx_left_bracket (cxx_pp);
|
|
dump_expr (TREE_OPERAND (t, 1), flags | TFF_EXPR_IN_PARENS);
|
|
pp_cxx_right_bracket (cxx_pp);
|
|
break;
|
|
|
|
case UNARY_PLUS_EXPR:
|
|
dump_unary_op ("+", t, flags);
|
|
break;
|
|
|
|
case ADDR_EXPR:
|
|
if (TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL
|
|
|| TREE_CODE (TREE_OPERAND (t, 0)) == STRING_CST
|
|
/* An ADDR_EXPR can have reference type. In that case, we
|
|
shouldn't print the `&' doing so indicates to the user
|
|
that the expression has pointer type. */
|
|
|| (TREE_TYPE (t)
|
|
&& TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE))
|
|
dump_expr (TREE_OPERAND (t, 0), flags | TFF_EXPR_IN_PARENS);
|
|
else if (TREE_CODE (TREE_OPERAND (t, 0)) == LABEL_DECL)
|
|
dump_unary_op ("&&", t, flags);
|
|
else
|
|
dump_unary_op ("&", t, flags);
|
|
break;
|
|
|
|
case INDIRECT_REF:
|
|
if (TREE_HAS_CONSTRUCTOR (t))
|
|
{
|
|
t = TREE_OPERAND (t, 0);
|
|
gcc_assert (TREE_CODE (t) == CALL_EXPR);
|
|
dump_expr (CALL_EXPR_FN (t), flags | TFF_EXPR_IN_PARENS);
|
|
dump_call_expr_args (t, flags, true);
|
|
}
|
|
else
|
|
{
|
|
if (TREE_OPERAND (t,0) != NULL_TREE
|
|
&& TREE_TYPE (TREE_OPERAND (t, 0))
|
|
&& NEXT_CODE (TREE_OPERAND (t, 0)) == REFERENCE_TYPE)
|
|
dump_expr (TREE_OPERAND (t, 0), flags);
|
|
else
|
|
dump_unary_op ("*", t, flags);
|
|
}
|
|
break;
|
|
|
|
case NEGATE_EXPR:
|
|
case BIT_NOT_EXPR:
|
|
case TRUTH_NOT_EXPR:
|
|
case PREDECREMENT_EXPR:
|
|
case PREINCREMENT_EXPR:
|
|
dump_unary_op (operator_name_info [(int)TREE_CODE (t)].name, t, flags);
|
|
break;
|
|
|
|
case POSTDECREMENT_EXPR:
|
|
case POSTINCREMENT_EXPR:
|
|
pp_cxx_left_paren (cxx_pp);
|
|
dump_expr (TREE_OPERAND (t, 0), flags | TFF_EXPR_IN_PARENS);
|
|
pp_cxx_ws_string (cxx_pp, operator_name_info[(int)TREE_CODE (t)].name);
|
|
pp_cxx_right_paren (cxx_pp);
|
|
break;
|
|
|
|
case NON_LVALUE_EXPR:
|
|
/* FIXME: This is a KLUDGE workaround for a parsing problem. There
|
|
should be another level of INDIRECT_REF so that I don't have to do
|
|
this. */
|
|
if (TREE_TYPE (t) != NULL_TREE && NEXT_CODE (t) == POINTER_TYPE)
|
|
{
|
|
tree next = TREE_TYPE (TREE_TYPE (t));
|
|
|
|
while (TREE_CODE (next) == POINTER_TYPE)
|
|
next = TREE_TYPE (next);
|
|
|
|
if (TREE_CODE (next) == FUNCTION_TYPE)
|
|
{
|
|
if (flags & TFF_EXPR_IN_PARENS)
|
|
pp_cxx_left_paren (cxx_pp);
|
|
pp_cxx_star (cxx_pp);
|
|
dump_expr (TREE_OPERAND (t, 0), flags & ~TFF_EXPR_IN_PARENS);
|
|
if (flags & TFF_EXPR_IN_PARENS)
|
|
pp_cxx_right_paren (cxx_pp);
|
|
break;
|
|
}
|
|
/* Else fall through. */
|
|
}
|
|
dump_expr (TREE_OPERAND (t, 0), flags | TFF_EXPR_IN_PARENS);
|
|
break;
|
|
|
|
CASE_CONVERT:
|
|
case VIEW_CONVERT_EXPR:
|
|
{
|
|
tree op = TREE_OPERAND (t, 0);
|
|
|
|
if (!same_type_p (TREE_TYPE (op), TREE_TYPE (t)))
|
|
{
|
|
/* It is a cast, but we cannot tell whether it is a
|
|
reinterpret or static cast. Use the C style notation. */
|
|
if (flags & TFF_EXPR_IN_PARENS)
|
|
pp_cxx_left_paren (cxx_pp);
|
|
pp_cxx_left_paren (cxx_pp);
|
|
dump_type (TREE_TYPE (t), flags);
|
|
pp_cxx_right_paren (cxx_pp);
|
|
dump_expr (op, flags | TFF_EXPR_IN_PARENS);
|
|
if (flags & TFF_EXPR_IN_PARENS)
|
|
pp_cxx_right_paren (cxx_pp);
|
|
}
|
|
else
|
|
dump_expr (op, flags);
|
|
break;
|
|
}
|
|
|
|
case CONSTRUCTOR:
|
|
if (TREE_TYPE (t) && TYPE_PTRMEMFUNC_P (TREE_TYPE (t)))
|
|
{
|
|
tree idx = build_ptrmemfunc_access_expr (t, pfn_identifier);
|
|
|
|
if (integer_zerop (idx))
|
|
{
|
|
/* A NULL pointer-to-member constant. */
|
|
pp_cxx_left_paren (cxx_pp);
|
|
pp_cxx_left_paren (cxx_pp);
|
|
dump_type (TREE_TYPE (t), flags);
|
|
pp_cxx_right_paren (cxx_pp);
|
|
pp_character (cxx_pp, '0');
|
|
pp_cxx_right_paren (cxx_pp);
|
|
break;
|
|
}
|
|
else if (host_integerp (idx, 0))
|
|
{
|
|
tree virtuals;
|
|
unsigned HOST_WIDE_INT n;
|
|
|
|
t = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (t)));
|
|
t = TYPE_METHOD_BASETYPE (t);
|
|
virtuals = BINFO_VIRTUALS (TYPE_BINFO (TYPE_MAIN_VARIANT (t)));
|
|
|
|
n = tree_low_cst (idx, 0);
|
|
|
|
/* Map vtable index back one, to allow for the null pointer to
|
|
member. */
|
|
--n;
|
|
|
|
while (n > 0 && virtuals)
|
|
{
|
|
--n;
|
|
virtuals = TREE_CHAIN (virtuals);
|
|
}
|
|
if (virtuals)
|
|
{
|
|
dump_expr (BV_FN (virtuals),
|
|
flags | TFF_EXPR_IN_PARENS);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (TREE_TYPE (t) && EMPTY_CONSTRUCTOR_P (t))
|
|
{
|
|
dump_type (TREE_TYPE (t), 0);
|
|
pp_cxx_left_paren (cxx_pp);
|
|
pp_cxx_right_paren (cxx_pp);
|
|
}
|
|
else
|
|
{
|
|
pp_cxx_left_brace (cxx_pp);
|
|
dump_expr_init_vec (CONSTRUCTOR_ELTS (t), flags);
|
|
pp_cxx_right_brace (cxx_pp);
|
|
}
|
|
|
|
break;
|
|
|
|
case OFFSET_REF:
|
|
{
|
|
tree ob = TREE_OPERAND (t, 0);
|
|
if (is_dummy_object (ob))
|
|
{
|
|
t = TREE_OPERAND (t, 1);
|
|
if (TREE_CODE (t) == FUNCTION_DECL)
|
|
/* A::f */
|
|
dump_expr (t, flags | TFF_EXPR_IN_PARENS);
|
|
else if (BASELINK_P (t))
|
|
dump_expr (OVL_CURRENT (BASELINK_FUNCTIONS (t)),
|
|
flags | TFF_EXPR_IN_PARENS);
|
|
else
|
|
dump_decl (t, flags);
|
|
}
|
|
else
|
|
{
|
|
if (TREE_CODE (ob) == INDIRECT_REF)
|
|
{
|
|
dump_expr (TREE_OPERAND (ob, 0), flags | TFF_EXPR_IN_PARENS);
|
|
pp_cxx_arrow (cxx_pp);
|
|
pp_cxx_star (cxx_pp);
|
|
}
|
|
else
|
|
{
|
|
dump_expr (ob, flags | TFF_EXPR_IN_PARENS);
|
|
pp_cxx_dot (cxx_pp);
|
|
pp_cxx_star (cxx_pp);
|
|
}
|
|
dump_expr (TREE_OPERAND (t, 1), flags | TFF_EXPR_IN_PARENS);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case TEMPLATE_PARM_INDEX:
|
|
dump_decl (TEMPLATE_PARM_DECL (t), flags & ~TFF_DECL_SPECIFIERS);
|
|
break;
|
|
|
|
case CAST_EXPR:
|
|
if (TREE_OPERAND (t, 0) == NULL_TREE
|
|
|| TREE_CHAIN (TREE_OPERAND (t, 0)))
|
|
{
|
|
dump_type (TREE_TYPE (t), flags);
|
|
pp_cxx_left_paren (cxx_pp);
|
|
dump_expr_list (TREE_OPERAND (t, 0), flags);
|
|
pp_cxx_right_paren (cxx_pp);
|
|
}
|
|
else
|
|
{
|
|
pp_cxx_left_paren (cxx_pp);
|
|
dump_type (TREE_TYPE (t), flags);
|
|
pp_cxx_right_paren (cxx_pp);
|
|
pp_cxx_left_paren (cxx_pp);
|
|
dump_expr_list (TREE_OPERAND (t, 0), flags);
|
|
pp_cxx_right_paren (cxx_pp);
|
|
}
|
|
break;
|
|
|
|
case STATIC_CAST_EXPR:
|
|
pp_cxx_ws_string (cxx_pp, "static_cast");
|
|
goto cast;
|
|
case REINTERPRET_CAST_EXPR:
|
|
pp_cxx_ws_string (cxx_pp, "reinterpret_cast");
|
|
goto cast;
|
|
case CONST_CAST_EXPR:
|
|
pp_cxx_ws_string (cxx_pp, "const_cast");
|
|
goto cast;
|
|
case DYNAMIC_CAST_EXPR:
|
|
pp_cxx_ws_string (cxx_pp, "dynamic_cast");
|
|
cast:
|
|
pp_cxx_begin_template_argument_list (cxx_pp);
|
|
dump_type (TREE_TYPE (t), flags);
|
|
pp_cxx_end_template_argument_list (cxx_pp);
|
|
pp_cxx_left_paren (cxx_pp);
|
|
dump_expr (TREE_OPERAND (t, 0), flags);
|
|
pp_cxx_right_paren (cxx_pp);
|
|
break;
|
|
|
|
case ARROW_EXPR:
|
|
dump_expr (TREE_OPERAND (t, 0), flags);
|
|
pp_cxx_arrow (cxx_pp);
|
|
break;
|
|
|
|
case SIZEOF_EXPR:
|
|
case ALIGNOF_EXPR:
|
|
if (TREE_CODE (t) == SIZEOF_EXPR)
|
|
pp_cxx_ws_string (cxx_pp, "sizeof");
|
|
else
|
|
{
|
|
gcc_assert (TREE_CODE (t) == ALIGNOF_EXPR);
|
|
pp_cxx_ws_string (cxx_pp, "__alignof__");
|
|
}
|
|
pp_cxx_whitespace (cxx_pp);
|
|
pp_cxx_left_paren (cxx_pp);
|
|
if (TYPE_P (TREE_OPERAND (t, 0)))
|
|
dump_type (TREE_OPERAND (t, 0), flags);
|
|
else
|
|
dump_expr (TREE_OPERAND (t, 0), flags);
|
|
pp_cxx_right_paren (cxx_pp);
|
|
break;
|
|
|
|
case REALPART_EXPR:
|
|
case IMAGPART_EXPR:
|
|
pp_cxx_ws_string (cxx_pp, operator_name_info[TREE_CODE (t)].name);
|
|
pp_cxx_whitespace (cxx_pp);
|
|
dump_expr (TREE_OPERAND (t, 0), flags);
|
|
break;
|
|
|
|
case DEFAULT_ARG:
|
|
pp_string (cxx_pp, M_("<unparsed>"));
|
|
break;
|
|
|
|
case TRY_CATCH_EXPR:
|
|
case WITH_CLEANUP_EXPR:
|
|
case CLEANUP_POINT_EXPR:
|
|
dump_expr (TREE_OPERAND (t, 0), flags);
|
|
break;
|
|
|
|
case PSEUDO_DTOR_EXPR:
|
|
dump_expr (TREE_OPERAND (t, 2), flags);
|
|
pp_cxx_dot (cxx_pp);
|
|
dump_type (TREE_OPERAND (t, 0), flags);
|
|
pp_cxx_colon_colon (cxx_pp);
|
|
pp_cxx_complement (cxx_pp);
|
|
dump_type (TREE_OPERAND (t, 1), flags);
|
|
break;
|
|
|
|
case TEMPLATE_ID_EXPR:
|
|
dump_decl (t, flags);
|
|
break;
|
|
|
|
case BIND_EXPR:
|
|
case STMT_EXPR:
|
|
case EXPR_STMT:
|
|
case STATEMENT_LIST:
|
|
/* We don't yet have a way of dumping statements in a
|
|
human-readable format. */
|
|
pp_string (cxx_pp, "({...})");
|
|
break;
|
|
|
|
case LOOP_EXPR:
|
|
pp_string (cxx_pp, "while (1) { ");
|
|
dump_expr (TREE_OPERAND (t, 0), flags & ~TFF_EXPR_IN_PARENS);
|
|
pp_cxx_right_brace (cxx_pp);
|
|
break;
|
|
|
|
case EXIT_EXPR:
|
|
pp_string (cxx_pp, "if (");
|
|
dump_expr (TREE_OPERAND (t, 0), flags & ~TFF_EXPR_IN_PARENS);
|
|
pp_string (cxx_pp, ") break; ");
|
|
break;
|
|
|
|
case BASELINK:
|
|
dump_expr (get_first_fn (t), flags & ~TFF_EXPR_IN_PARENS);
|
|
break;
|
|
|
|
case EMPTY_CLASS_EXPR:
|
|
dump_type (TREE_TYPE (t), flags);
|
|
pp_cxx_left_paren (cxx_pp);
|
|
pp_cxx_right_paren (cxx_pp);
|
|
break;
|
|
|
|
case NON_DEPENDENT_EXPR:
|
|
dump_expr (TREE_OPERAND (t, 0), flags);
|
|
break;
|
|
|
|
case ARGUMENT_PACK_SELECT:
|
|
dump_template_argument (ARGUMENT_PACK_SELECT_FROM_PACK (t), flags);
|
|
break;
|
|
|
|
case RECORD_TYPE:
|
|
case UNION_TYPE:
|
|
case ENUMERAL_TYPE:
|
|
case REAL_TYPE:
|
|
case VOID_TYPE:
|
|
case BOOLEAN_TYPE:
|
|
case INTEGER_TYPE:
|
|
case COMPLEX_TYPE:
|
|
case VECTOR_TYPE:
|
|
pp_type_specifier_seq (cxx_pp, t);
|
|
break;
|
|
|
|
case TYPENAME_TYPE:
|
|
/* We get here when we want to print a dependent type as an
|
|
id-expression, without any disambiguator decoration. */
|
|
pp_id_expression (cxx_pp, t);
|
|
break;
|
|
|
|
case TEMPLATE_TYPE_PARM:
|
|
case BOUND_TEMPLATE_TEMPLATE_PARM:
|
|
dump_type (t, flags);
|
|
break;
|
|
|
|
case TRAIT_EXPR:
|
|
pp_cxx_trait_expression (cxx_pp, t);
|
|
break;
|
|
|
|
case VA_ARG_EXPR:
|
|
pp_cxx_va_arg_expression (cxx_pp, t);
|
|
break;
|
|
|
|
case OFFSETOF_EXPR:
|
|
pp_cxx_offsetof_expression (cxx_pp, t);
|
|
break;
|
|
|
|
case SCOPE_REF:
|
|
case EXPR_PACK_EXPANSION:
|
|
case TYPEID_EXPR:
|
|
case MEMBER_REF:
|
|
case DOTSTAR_EXPR:
|
|
case NEW_EXPR:
|
|
case VEC_NEW_EXPR:
|
|
case DELETE_EXPR:
|
|
case VEC_DELETE_EXPR:
|
|
case MODOP_EXPR:
|
|
case ABS_EXPR:
|
|
case CONJ_EXPR:
|
|
case VECTOR_CST:
|
|
case FIXED_CST:
|
|
case UNORDERED_EXPR:
|
|
case ORDERED_EXPR:
|
|
case UNLT_EXPR:
|
|
case UNLE_EXPR:
|
|
case UNGT_EXPR:
|
|
case UNGE_EXPR:
|
|
case UNEQ_EXPR:
|
|
case LTGT_EXPR:
|
|
case COMPLEX_EXPR:
|
|
case BIT_FIELD_REF:
|
|
case FIX_TRUNC_EXPR:
|
|
case FLOAT_EXPR:
|
|
pp_expression (cxx_pp, t);
|
|
break;
|
|
|
|
case TRUTH_AND_EXPR:
|
|
case TRUTH_OR_EXPR:
|
|
case TRUTH_XOR_EXPR:
|
|
if (flags & TFF_EXPR_IN_PARENS)
|
|
pp_cxx_left_paren (cxx_pp);
|
|
pp_expression (cxx_pp, t);
|
|
if (flags & TFF_EXPR_IN_PARENS)
|
|
pp_cxx_right_paren (cxx_pp);
|
|
break;
|
|
|
|
case OBJ_TYPE_REF:
|
|
dump_expr (resolve_virtual_fun_from_obj_type_ref (t), flags);
|
|
break;
|
|
|
|
/* This list is incomplete, but should suffice for now.
|
|
It is very important that `sorry' does not call
|
|
`report_error_function'. That could cause an infinite loop. */
|
|
default:
|
|
pp_unsupported_tree (cxx_pp, t);
|
|
/* fall through to ERROR_MARK... */
|
|
case ERROR_MARK:
|
|
pp_string (cxx_pp, M_("<expression error>"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
dump_binary_op (const char *opstring, tree t, int flags)
|
|
{
|
|
pp_cxx_left_paren (cxx_pp);
|
|
dump_expr (TREE_OPERAND (t, 0), flags | TFF_EXPR_IN_PARENS);
|
|
pp_cxx_whitespace (cxx_pp);
|
|
if (opstring)
|
|
pp_cxx_ws_string (cxx_pp, opstring);
|
|
else
|
|
pp_string (cxx_pp, M_("<unknown operator>"));
|
|
pp_cxx_whitespace (cxx_pp);
|
|
dump_expr (TREE_OPERAND (t, 1), flags | TFF_EXPR_IN_PARENS);
|
|
pp_cxx_right_paren (cxx_pp);
|
|
}
|
|
|
|
static void
|
|
dump_unary_op (const char *opstring, tree t, int flags)
|
|
{
|
|
if (flags & TFF_EXPR_IN_PARENS)
|
|
pp_cxx_left_paren (cxx_pp);
|
|
pp_cxx_ws_string (cxx_pp, opstring);
|
|
dump_expr (TREE_OPERAND (t, 0), flags & ~TFF_EXPR_IN_PARENS);
|
|
if (flags & TFF_EXPR_IN_PARENS)
|
|
pp_cxx_right_paren (cxx_pp);
|
|
}
|
|
|
|
static void
|
|
reinit_cxx_pp (void)
|
|
{
|
|
pp_clear_output_area (cxx_pp);
|
|
pp_base (cxx_pp)->padding = pp_none;
|
|
pp_indentation (cxx_pp) = 0;
|
|
pp_needs_newline (cxx_pp) = false;
|
|
cxx_pp->enclosing_scope = current_function_decl;
|
|
}
|
|
|
|
|
|
/* Exported interface to stringifying types, exprs and decls under TFF_*
|
|
control. */
|
|
|
|
const char *
|
|
type_as_string (tree typ, int flags)
|
|
{
|
|
reinit_cxx_pp ();
|
|
pp_translate_identifiers (cxx_pp) = false;
|
|
dump_type (typ, flags);
|
|
return pp_formatted_text (cxx_pp);
|
|
}
|
|
|
|
const char *
|
|
type_as_string_translate (tree typ, int flags)
|
|
{
|
|
reinit_cxx_pp ();
|
|
dump_type (typ, flags);
|
|
return pp_formatted_text (cxx_pp);
|
|
}
|
|
|
|
const char *
|
|
expr_as_string (tree decl, int flags)
|
|
{
|
|
reinit_cxx_pp ();
|
|
pp_translate_identifiers (cxx_pp) = false;
|
|
dump_expr (decl, flags);
|
|
return pp_formatted_text (cxx_pp);
|
|
}
|
|
|
|
const char *
|
|
decl_as_string (tree decl, int flags)
|
|
{
|
|
reinit_cxx_pp ();
|
|
pp_translate_identifiers (cxx_pp) = false;
|
|
dump_decl (decl, flags);
|
|
return pp_formatted_text (cxx_pp);
|
|
}
|
|
|
|
const char *
|
|
decl_as_string_translate (tree decl, int flags)
|
|
{
|
|
reinit_cxx_pp ();
|
|
dump_decl (decl, flags);
|
|
return pp_formatted_text (cxx_pp);
|
|
}
|
|
|
|
/* Generate the three forms of printable names for cxx_printable_name. */
|
|
|
|
const char *
|
|
lang_decl_name (tree decl, int v, bool translate)
|
|
{
|
|
if (v >= 2)
|
|
return (translate
|
|
? decl_as_string_translate (decl, TFF_DECL_SPECIFIERS)
|
|
: decl_as_string (decl, TFF_DECL_SPECIFIERS));
|
|
|
|
reinit_cxx_pp ();
|
|
pp_translate_identifiers (cxx_pp) = translate;
|
|
if (v == 1
|
|
&& (DECL_CLASS_SCOPE_P (decl)
|
|
|| (DECL_NAMESPACE_SCOPE_P (decl)
|
|
&& CP_DECL_CONTEXT (decl) != global_namespace)))
|
|
{
|
|
dump_type (CP_DECL_CONTEXT (decl), TFF_PLAIN_IDENTIFIER);
|
|
pp_cxx_colon_colon (cxx_pp);
|
|
}
|
|
|
|
if (TREE_CODE (decl) == FUNCTION_DECL)
|
|
dump_function_name (decl, TFF_PLAIN_IDENTIFIER);
|
|
else
|
|
dump_decl (DECL_NAME (decl), TFF_PLAIN_IDENTIFIER);
|
|
|
|
return pp_formatted_text (cxx_pp);
|
|
}
|
|
|
|
/* Return the location of a tree passed to %+ formats. */
|
|
|
|
static location_t
|
|
location_of (tree t)
|
|
{
|
|
if (TREE_CODE (t) == PARM_DECL && DECL_CONTEXT (t))
|
|
t = DECL_CONTEXT (t);
|
|
else if (TYPE_P (t))
|
|
t = TYPE_MAIN_DECL (t);
|
|
else if (TREE_CODE (t) == OVERLOAD)
|
|
t = OVL_FUNCTION (t);
|
|
|
|
return DECL_SOURCE_LOCATION (t);
|
|
}
|
|
|
|
/* Now the interfaces from error et al to dump_type et al. Each takes an
|
|
on/off VERBOSE flag and supply the appropriate TFF_ flags to a dump_
|
|
function. */
|
|
|
|
static const char *
|
|
decl_to_string (tree decl, int verbose)
|
|
{
|
|
int flags = 0;
|
|
|
|
if (TREE_CODE (decl) == TYPE_DECL || TREE_CODE (decl) == RECORD_TYPE
|
|
|| TREE_CODE (decl) == UNION_TYPE || TREE_CODE (decl) == ENUMERAL_TYPE)
|
|
flags = TFF_CLASS_KEY_OR_ENUM;
|
|
if (verbose)
|
|
flags |= TFF_DECL_SPECIFIERS;
|
|
else if (TREE_CODE (decl) == FUNCTION_DECL)
|
|
flags |= TFF_DECL_SPECIFIERS | TFF_RETURN_TYPE;
|
|
flags |= TFF_TEMPLATE_HEADER;
|
|
|
|
reinit_cxx_pp ();
|
|
dump_decl (decl, flags);
|
|
return pp_formatted_text (cxx_pp);
|
|
}
|
|
|
|
static const char *
|
|
expr_to_string (tree decl)
|
|
{
|
|
reinit_cxx_pp ();
|
|
dump_expr (decl, 0);
|
|
return pp_formatted_text (cxx_pp);
|
|
}
|
|
|
|
static const char *
|
|
fndecl_to_string (tree fndecl, int verbose)
|
|
{
|
|
int flags;
|
|
|
|
flags = TFF_EXCEPTION_SPECIFICATION | TFF_DECL_SPECIFIERS
|
|
| TFF_TEMPLATE_HEADER;
|
|
if (verbose)
|
|
flags |= TFF_FUNCTION_DEFAULT_ARGUMENTS;
|
|
reinit_cxx_pp ();
|
|
dump_decl (fndecl, flags);
|
|
return pp_formatted_text (cxx_pp);
|
|
}
|
|
|
|
|
|
static const char *
|
|
code_to_string (enum tree_code c)
|
|
{
|
|
return tree_code_name [c];
|
|
}
|
|
|
|
const char *
|
|
language_to_string (enum languages c)
|
|
{
|
|
switch (c)
|
|
{
|
|
case lang_c:
|
|
return "C";
|
|
|
|
case lang_cplusplus:
|
|
return "C++";
|
|
|
|
case lang_java:
|
|
return "Java";
|
|
|
|
default:
|
|
gcc_unreachable ();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/* Return the proper printed version of a parameter to a C++ function. */
|
|
|
|
static const char *
|
|
parm_to_string (int p)
|
|
{
|
|
reinit_cxx_pp ();
|
|
if (p < 0)
|
|
pp_string (cxx_pp, "'this'");
|
|
else
|
|
pp_decimal_int (cxx_pp, p + 1);
|
|
return pp_formatted_text (cxx_pp);
|
|
}
|
|
|
|
static const char *
|
|
op_to_string (enum tree_code p)
|
|
{
|
|
tree id = operator_name_info[(int) p].identifier;
|
|
return id ? IDENTIFIER_POINTER (id) : M_("<unknown>");
|
|
}
|
|
|
|
static const char *
|
|
type_to_string (tree typ, int verbose)
|
|
{
|
|
int flags = 0;
|
|
if (verbose)
|
|
flags |= TFF_CLASS_KEY_OR_ENUM;
|
|
flags |= TFF_TEMPLATE_HEADER;
|
|
|
|
reinit_cxx_pp ();
|
|
dump_type (typ, flags);
|
|
return pp_formatted_text (cxx_pp);
|
|
}
|
|
|
|
static const char *
|
|
assop_to_string (enum tree_code p)
|
|
{
|
|
tree id = assignment_operator_name_info[(int) p].identifier;
|
|
return id ? IDENTIFIER_POINTER (id) : M_("{unknown}");
|
|
}
|
|
|
|
static const char *
|
|
args_to_string (tree p, int verbose)
|
|
{
|
|
int flags = 0;
|
|
if (verbose)
|
|
flags |= TFF_CLASS_KEY_OR_ENUM;
|
|
|
|
if (p == NULL_TREE)
|
|
return "";
|
|
|
|
if (TYPE_P (TREE_VALUE (p)))
|
|
return type_as_string_translate (p, flags);
|
|
|
|
reinit_cxx_pp ();
|
|
for (; p; p = TREE_CHAIN (p))
|
|
{
|
|
if (TREE_VALUE (p) == null_node)
|
|
pp_cxx_ws_string (cxx_pp, "NULL");
|
|
else
|
|
dump_type (error_type (TREE_VALUE (p)), flags);
|
|
if (TREE_CHAIN (p))
|
|
pp_separate_with_comma (cxx_pp);
|
|
}
|
|
return pp_formatted_text (cxx_pp);
|
|
}
|
|
|
|
static const char *
|
|
cv_to_string (tree p, int v)
|
|
{
|
|
reinit_cxx_pp ();
|
|
pp_base (cxx_pp)->padding = v ? pp_before : pp_none;
|
|
pp_cxx_cv_qualifier_seq (cxx_pp, p);
|
|
return pp_formatted_text (cxx_pp);
|
|
}
|
|
|
|
/* Langhook for print_error_function. */
|
|
void
|
|
cxx_print_error_function (diagnostic_context *context, const char *file,
|
|
diagnostic_info *diagnostic)
|
|
{
|
|
lhd_print_error_function (context, file, diagnostic);
|
|
pp_base_set_prefix (context->printer, file);
|
|
maybe_print_instantiation_context (context);
|
|
}
|
|
|
|
static void
|
|
cp_diagnostic_starter (diagnostic_context *context,
|
|
diagnostic_info *diagnostic)
|
|
{
|
|
diagnostic_report_current_module (context);
|
|
cp_print_error_function (context, diagnostic);
|
|
maybe_print_instantiation_context (context);
|
|
pp_base_set_prefix (context->printer, diagnostic_build_prefix (diagnostic));
|
|
}
|
|
|
|
static void
|
|
cp_diagnostic_finalizer (diagnostic_context *context,
|
|
diagnostic_info *diagnostic ATTRIBUTE_UNUSED)
|
|
{
|
|
pp_base_destroy_prefix (context->printer);
|
|
}
|
|
|
|
/* Print current function onto BUFFER, in the process of reporting
|
|
a diagnostic message. Called from cp_diagnostic_starter. */
|
|
static void
|
|
cp_print_error_function (diagnostic_context *context,
|
|
diagnostic_info *diagnostic)
|
|
{
|
|
if (diagnostic_last_function_changed (context, diagnostic))
|
|
{
|
|
const char *old_prefix = context->printer->prefix;
|
|
const char *file = LOCATION_FILE (diagnostic->location);
|
|
tree abstract_origin = diagnostic->abstract_origin;
|
|
char *new_prefix = (file && abstract_origin == NULL)
|
|
? file_name_as_prefix (file) : NULL;
|
|
|
|
pp_base_set_prefix (context->printer, new_prefix);
|
|
|
|
if (current_function_decl == NULL)
|
|
pp_base_string (context->printer, _("At global scope:"));
|
|
else
|
|
{
|
|
tree fndecl, ao;
|
|
|
|
if (abstract_origin)
|
|
{
|
|
ao = BLOCK_ABSTRACT_ORIGIN (abstract_origin);
|
|
while (TREE_CODE (ao) == BLOCK
|
|
&& BLOCK_ABSTRACT_ORIGIN (ao)
|
|
&& BLOCK_ABSTRACT_ORIGIN (ao) != ao)
|
|
ao = BLOCK_ABSTRACT_ORIGIN (ao);
|
|
gcc_assert (TREE_CODE (ao) == FUNCTION_DECL);
|
|
fndecl = ao;
|
|
}
|
|
else
|
|
fndecl = current_function_decl;
|
|
|
|
pp_printf (context->printer, function_category (fndecl),
|
|
cxx_printable_name_translate (fndecl, 2));
|
|
|
|
while (abstract_origin)
|
|
{
|
|
location_t *locus;
|
|
tree block = abstract_origin;
|
|
|
|
locus = &BLOCK_SOURCE_LOCATION (block);
|
|
fndecl = NULL;
|
|
block = BLOCK_SUPERCONTEXT (block);
|
|
while (block && TREE_CODE (block) == BLOCK
|
|
&& BLOCK_ABSTRACT_ORIGIN (block))
|
|
{
|
|
ao = BLOCK_ABSTRACT_ORIGIN (block);
|
|
|
|
while (TREE_CODE (ao) == BLOCK
|
|
&& BLOCK_ABSTRACT_ORIGIN (ao)
|
|
&& BLOCK_ABSTRACT_ORIGIN (ao) != ao)
|
|
ao = BLOCK_ABSTRACT_ORIGIN (ao);
|
|
|
|
if (TREE_CODE (ao) == FUNCTION_DECL)
|
|
{
|
|
fndecl = ao;
|
|
break;
|
|
}
|
|
else if (TREE_CODE (ao) != BLOCK)
|
|
break;
|
|
|
|
block = BLOCK_SUPERCONTEXT (block);
|
|
}
|
|
if (fndecl)
|
|
abstract_origin = block;
|
|
else
|
|
{
|
|
while (block && TREE_CODE (block) == BLOCK)
|
|
block = BLOCK_SUPERCONTEXT (block);
|
|
|
|
if (block && TREE_CODE (block) == FUNCTION_DECL)
|
|
fndecl = block;
|
|
abstract_origin = NULL;
|
|
}
|
|
if (fndecl)
|
|
{
|
|
expanded_location s = expand_location (*locus);
|
|
pp_base_character (context->printer, ',');
|
|
pp_base_newline (context->printer);
|
|
if (s.file != NULL)
|
|
{
|
|
if (flag_show_column && s.column != 0)
|
|
pp_printf (context->printer,
|
|
_(" inlined from %qs at %s:%d:%d"),
|
|
cxx_printable_name_translate (fndecl, 2),
|
|
s.file, s.line, s.column);
|
|
else
|
|
pp_printf (context->printer,
|
|
_(" inlined from %qs at %s:%d"),
|
|
cxx_printable_name_translate (fndecl, 2),
|
|
s.file, s.line);
|
|
|
|
}
|
|
else
|
|
pp_printf (context->printer, _(" inlined from %qs"),
|
|
cxx_printable_name_translate (fndecl, 2));
|
|
}
|
|
}
|
|
pp_base_character (context->printer, ':');
|
|
}
|
|
pp_base_newline (context->printer);
|
|
|
|
diagnostic_set_last_function (context, diagnostic);
|
|
pp_base_destroy_prefix (context->printer);
|
|
context->printer->prefix = old_prefix;
|
|
}
|
|
}
|
|
|
|
/* Returns a description of FUNCTION using standard terminology. The
|
|
result is a format string of the form "In CATEGORY %qs". */
|
|
static const char *
|
|
function_category (tree fn)
|
|
{
|
|
/* We can get called from the middle-end for diagnostics of function
|
|
clones. Make sure we have language specific information before
|
|
dereferencing it. */
|
|
if (DECL_LANG_SPECIFIC (STRIP_TEMPLATE (fn))
|
|
&& DECL_FUNCTION_MEMBER_P (fn))
|
|
{
|
|
if (DECL_STATIC_FUNCTION_P (fn))
|
|
return _("In static member function %qs");
|
|
else if (DECL_COPY_CONSTRUCTOR_P (fn))
|
|
return _("In copy constructor %qs");
|
|
else if (DECL_CONSTRUCTOR_P (fn))
|
|
return _("In constructor %qs");
|
|
else if (DECL_DESTRUCTOR_P (fn))
|
|
return _("In destructor %qs");
|
|
else
|
|
return _("In member function %qs");
|
|
}
|
|
else
|
|
return _("In function %qs");
|
|
}
|
|
|
|
/* Report the full context of a current template instantiation,
|
|
onto BUFFER. */
|
|
static void
|
|
print_instantiation_full_context (diagnostic_context *context)
|
|
{
|
|
struct tinst_level *p = current_instantiation ();
|
|
location_t location = input_location;
|
|
|
|
if (p)
|
|
{
|
|
if (current_function_decl != p->decl
|
|
&& current_function_decl != NULL_TREE)
|
|
/* We can get here during the processing of some synthesized
|
|
method. Then, P->DECL will be the function that's causing
|
|
the synthesis. */
|
|
;
|
|
else
|
|
{
|
|
if (current_function_decl == p->decl)
|
|
/* Avoid redundancy with the "In function" line. */;
|
|
else
|
|
pp_verbatim (context->printer,
|
|
_("%s: In instantiation of %qs:\n"),
|
|
LOCATION_FILE (location),
|
|
decl_as_string_translate (p->decl,
|
|
TFF_DECL_SPECIFIERS | TFF_RETURN_TYPE));
|
|
|
|
location = p->locus;
|
|
p = p->next;
|
|
}
|
|
}
|
|
|
|
print_instantiation_partial_context (context, p, location);
|
|
}
|
|
|
|
/* Same as above but less verbose. */
|
|
static void
|
|
print_instantiation_partial_context (diagnostic_context *context,
|
|
struct tinst_level *t, location_t loc)
|
|
{
|
|
expanded_location xloc;
|
|
const char *str;
|
|
for (; ; t = t->next)
|
|
{
|
|
xloc = expand_location (loc);
|
|
if (t == NULL)
|
|
break;
|
|
str = decl_as_string_translate (t->decl,
|
|
TFF_DECL_SPECIFIERS | TFF_RETURN_TYPE);
|
|
if (flag_show_column)
|
|
pp_verbatim (context->printer,
|
|
_("%s:%d:%d: instantiated from %qs\n"),
|
|
xloc.file, xloc.line, xloc.column, str);
|
|
else
|
|
pp_verbatim (context->printer,
|
|
_("%s:%d: instantiated from %qs\n"),
|
|
xloc.file, xloc.line, str);
|
|
loc = t->locus;
|
|
}
|
|
if (flag_show_column)
|
|
pp_verbatim (context->printer, _("%s:%d:%d: instantiated from here"),
|
|
xloc.file, xloc.line, xloc.column);
|
|
else
|
|
pp_verbatim (context->printer, _("%s:%d: instantiated from here"),
|
|
xloc.file, xloc.line);
|
|
pp_base_newline (context->printer);
|
|
}
|
|
|
|
/* Called from cp_thing to print the template context for an error. */
|
|
static void
|
|
maybe_print_instantiation_context (diagnostic_context *context)
|
|
{
|
|
if (!problematic_instantiation_changed () || current_instantiation () == 0)
|
|
return;
|
|
|
|
record_last_problematic_instantiation ();
|
|
print_instantiation_full_context (context);
|
|
}
|
|
|
|
/* Report the bare minimum context of a template instantiation. */
|
|
void
|
|
print_instantiation_context (void)
|
|
{
|
|
print_instantiation_partial_context
|
|
(global_dc, current_instantiation (), input_location);
|
|
diagnostic_flush_buffer (global_dc);
|
|
}
|
|
|
|
/* Called from output_format -- during diagnostic message processing --
|
|
to handle C++ specific format specifier with the following meanings:
|
|
%A function argument-list.
|
|
%C tree code.
|
|
%D declaration.
|
|
%E expression.
|
|
%F function declaration.
|
|
%L language as used in extern "lang".
|
|
%O binary operator.
|
|
%P function parameter whose position is indicated by an integer.
|
|
%Q assignment operator.
|
|
%T type.
|
|
%V cv-qualifier. */
|
|
static bool
|
|
cp_printer (pretty_printer *pp, text_info *text, const char *spec,
|
|
int precision, bool wide, bool set_locus, bool verbose)
|
|
{
|
|
const char *result;
|
|
tree t = NULL;
|
|
#define next_tree (t = va_arg (*text->args_ptr, tree))
|
|
#define next_tcode ((enum tree_code) va_arg (*text->args_ptr, int))
|
|
#define next_lang ((enum languages) va_arg (*text->args_ptr, int))
|
|
#define next_int va_arg (*text->args_ptr, int)
|
|
|
|
if (precision != 0 || wide)
|
|
return false;
|
|
|
|
if (text->locus == NULL)
|
|
set_locus = false;
|
|
|
|
switch (*spec)
|
|
{
|
|
case 'A': result = args_to_string (next_tree, verbose); break;
|
|
case 'C': result = code_to_string (next_tcode); break;
|
|
case 'D':
|
|
{
|
|
tree temp = next_tree;
|
|
if (DECL_P (temp)
|
|
&& DECL_DEBUG_EXPR_IS_FROM (temp) && DECL_DEBUG_EXPR (temp))
|
|
{
|
|
temp = DECL_DEBUG_EXPR (temp);
|
|
if (!DECL_P (temp))
|
|
{
|
|
result = expr_to_string (temp);
|
|
break;
|
|
}
|
|
}
|
|
result = decl_to_string (temp, verbose);
|
|
}
|
|
break;
|
|
case 'E': result = expr_to_string (next_tree); break;
|
|
case 'F': result = fndecl_to_string (next_tree, verbose); break;
|
|
case 'L': result = language_to_string (next_lang); break;
|
|
case 'O': result = op_to_string (next_tcode); break;
|
|
case 'P': result = parm_to_string (next_int); break;
|
|
case 'Q': result = assop_to_string (next_tcode); break;
|
|
case 'T': result = type_to_string (next_tree, verbose); break;
|
|
case 'V': result = cv_to_string (next_tree, verbose); break;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
pp_base_string (pp, result);
|
|
if (set_locus && t != NULL)
|
|
*text->locus = location_of (t);
|
|
return true;
|
|
#undef next_tree
|
|
#undef next_tcode
|
|
#undef next_lang
|
|
#undef next_int
|
|
}
|
|
|
|
/* Warn about the use of C++0x features when appropriate. */
|
|
void
|
|
maybe_warn_cpp0x (const char* str)
|
|
{
|
|
if ((cxx_dialect == cxx98) && !in_system_header)
|
|
/* We really want to suppress this warning in system headers,
|
|
because libstdc++ uses variadic templates even when we aren't
|
|
in C++0x mode. */
|
|
pedwarn (input_location, 0, "%s only available with -std=c++0x or -std=gnu++0x", str);
|
|
}
|
|
|
|
/* Warn about the use of variadic templates when appropriate. */
|
|
void
|
|
maybe_warn_variadic_templates (void)
|
|
{
|
|
maybe_warn_cpp0x ("variadic templates");
|
|
}
|
|
|
|
|
|
/* Issue an ISO C++98 pedantic warning at LOCATION, conditional on
|
|
option OPT with text GMSGID. Use this function to report
|
|
diagnostics for constructs that are invalid C++98, but valid
|
|
C++0x. */
|
|
bool
|
|
pedwarn_cxx98 (location_t location, int opt, const char *gmsgid, ...)
|
|
{
|
|
diagnostic_info diagnostic;
|
|
va_list ap;
|
|
|
|
va_start (ap, gmsgid);
|
|
diagnostic_set_info (&diagnostic, gmsgid, &ap, location,
|
|
(cxx_dialect == cxx98) ? DK_PEDWARN : DK_WARNING);
|
|
diagnostic.option_index = opt;
|
|
va_end (ap);
|
|
return report_diagnostic (&diagnostic);
|
|
}
|