void fini_walk_dominator_tree (struct dom_walk_data *walk_data) { if (walk_data->initialize_block_local_data) { while (VEC_length (void_p, walk_data->free_block_data) > 0) free (VEC_pop (void_p, walk_data->free_block_data)); } VEC_free (void_p, heap, walk_data->free_block_data); VEC_free (void_p, heap, walk_data->block_data_stack); }
static void emit_mfence_after_loop (struct loop *loop) { VEC (edge, heap) *exits = get_loop_exit_edges (loop); edge exit; gimple call; gimple_stmt_iterator bsi; unsigned i; for (i = 0; VEC_iterate (edge, exits, i, exit); i++) { call = gimple_build_call (FENCE_FOLLOWING_MOVNT, 0); if (!single_pred_p (exit->dest) /* If possible, we prefer not to insert the fence on other paths in cfg. */ && !(exit->flags & EDGE_ABNORMAL)) split_loop_exit_edge (exit); bsi = gsi_after_labels (exit->dest); gsi_insert_before (&bsi, call, GSI_NEW_STMT); mark_virtual_ops_for_renaming (call); } VEC_free (edge, heap, exits); update_ssa (TODO_update_ssa_only_virtuals); }
static bool may_use_storent_in_loop_p (struct loop *loop) { bool ret = true; if (loop->inner != NULL) return false; /* If we must issue a mfence insn after using storent, check that there is a suitable place for it at each of the loop exits. */ if (FENCE_FOLLOWING_MOVNT != NULL_TREE) { VEC (edge, heap) *exits = get_loop_exit_edges (loop); unsigned i; edge exit; for (i = 0; VEC_iterate (edge, exits, i, exit); i++) if ((exit->flags & EDGE_ABNORMAL) && exit->dest == EXIT_BLOCK_PTR) ret = false; VEC_free (edge, heap, exits); } return ret; }
static bool reachable_at_most_once (basic_block va_arg_bb, basic_block va_start_bb) { VEC (edge, heap) *stack = NULL; edge e; edge_iterator ei; sbitmap visited; bool ret; if (va_arg_bb == va_start_bb) return true; if (! dominated_by_p (CDI_DOMINATORS, va_arg_bb, va_start_bb)) return false; visited = sbitmap_alloc (last_basic_block); sbitmap_zero (visited); ret = true; FOR_EACH_EDGE (e, ei, va_arg_bb->preds) VEC_safe_push (edge, heap, stack, e); while (! VEC_empty (edge, stack)) { basic_block src; e = VEC_pop (edge, stack); src = e->src; if (e->flags & EDGE_COMPLEX) { ret = false; break; } if (src == va_start_bb) continue; /* va_arg_bb can be executed more times than va_start_bb. */ if (src == va_arg_bb) { ret = false; break; } gcc_assert (src != ENTRY_BLOCK_PTR); if (! TEST_BIT (visited, src->index)) { SET_BIT (visited, src->index); FOR_EACH_EDGE (e, ei, src->preds) VEC_safe_push (edge, heap, stack, e); } } VEC_free (edge, heap, stack); sbitmap_free (visited); return ret; }
void fini_ssa_operands (void) { struct ssa_operand_memory_d *ptr; if (!--n_initialized) { VEC_free (tree, heap, build_defs); VEC_free (tree, heap, build_uses); build_vdef = NULL_TREE; build_vuse = NULL_TREE; } gimple_ssa_operands (cfun)->free_defs = NULL; gimple_ssa_operands (cfun)->free_uses = NULL; while ((ptr = gimple_ssa_operands (cfun)->operand_memory) != NULL) { gimple_ssa_operands (cfun)->operand_memory = gimple_ssa_operands (cfun)->operand_memory->next; ggc_free (ptr); } gimple_ssa_operands (cfun)->ops_active = false; if (!n_initialized) bitmap_obstack_release (&operands_bitmap_obstack); cfun->gimple_df->vop = NULL_TREE; if (dump_file && (dump_flags & TDF_STATS)) { fprintf (dump_file, "Original clobbered vars: %d\n", clobber_stats.clobbered_vars); fprintf (dump_file, "Static write clobbers avoided: %d\n", clobber_stats.static_write_clobbers_avoided); fprintf (dump_file, "Static read clobbers avoided: %d\n", clobber_stats.static_read_clobbers_avoided); fprintf (dump_file, "Unescapable clobbers avoided: %d\n", clobber_stats.unescapable_clobbers_avoided); fprintf (dump_file, "Original read-only clobbers: %d\n", clobber_stats.readonly_clobbers); fprintf (dump_file, "Static read-only clobbers avoided: %d\n", clobber_stats.static_readonly_clobbers_avoided); } }
static void cli_uiout_dtor (struct ui_out *ui_out) { cli_out_data *data = ui_out_data (ui_out); VEC_free (ui_filep, data->streams); xfree (data); }
static bool ipa_set_param_cannot_devirtualize (struct ipa_node_params *info, int i) { bool ret = info->params[i].cannot_devirtualize; info->params[i].cannot_devirtualize = true; if (info->params[i].types) VEC_free (tree, heap, info->params[i].types); return ret; }
static void signal_catchpoint_dtor (struct breakpoint *b) { struct signal_catchpoint *c = (struct signal_catchpoint *) b; VEC_free (gdb_signal_type, c->signals_to_be_caught); base_breakpoint_ops.dtor (b); }
void streamer_tree_cache_delete (struct streamer_tree_cache_d *c) { if (c == NULL) return; pointer_map_destroy (c->node_map); VEC_free (tree, heap, c->nodes); free (c); }
void invalidate_target_mem_regions (void) { if (!target_mem_regions_valid) return; target_mem_regions_valid = 0; VEC_free (mem_region_s, target_mem_region_list); if (mem_use_target) mem_region_list = NULL; }
void btrace_data_fini (struct btrace_data *data) { switch (data->format) { case BTRACE_FORMAT_NONE: /* Nothing to do. */ return; case BTRACE_FORMAT_BTS: VEC_free (btrace_block_s, data->variant.bts.blocks); return; } internal_error (__FILE__, __LINE__, _("Unkown branch trace format.")); }
void pbb_remove_duplicate_pdrs (poly_bb_p pbb) { int i, j; poly_dr_p pdr1, pdr2; unsigned n = VEC_length (poly_dr_p, PBB_DRS (pbb)); VEC (poly_dr_p, heap) *collapsed = VEC_alloc (poly_dr_p, heap, n); for (i = 0; VEC_iterate (poly_dr_p, PBB_DRS (pbb), i, pdr1); i++) for (j = 0; VEC_iterate (poly_dr_p, collapsed, j, pdr2); j++) if (!can_collapse_pdrs (pdr1, pdr2)) VEC_quick_push (poly_dr_p, collapsed, pdr1); VEC_free (poly_dr_p, heap, collapsed); PBB_PDR_DUPLICATES_REMOVED (pbb) = true; }
static void lto_symtab_merge_decls_2 (void **slot, bool diagnosed_p) { lto_symtab_entry_t prevailing, e; VEC(tree, heap) *mismatches = NULL; unsigned i; tree decl; /* Nothing to do for a single entry. */ prevailing = (lto_symtab_entry_t) *slot; if (!prevailing->next) return; /* Try to merge each entry with the prevailing one. */ for (e = prevailing->next; e; e = e->next) { if (!lto_symtab_merge (prevailing, e) && !diagnosed_p) VEC_safe_push (tree, heap, mismatches, e->decl); } if (VEC_empty (tree, mismatches)) return; /* Diagnose all mismatched re-declarations. */ FOR_EACH_VEC_ELT (tree, mismatches, i, decl) { if (!types_compatible_p (TREE_TYPE (prevailing->decl), TREE_TYPE (decl))) diagnosed_p |= warning_at (DECL_SOURCE_LOCATION (decl), 0, "type of %qD does not match original " "declaration", decl); else if ((DECL_USER_ALIGN (prevailing->decl) && DECL_USER_ALIGN (decl)) && DECL_ALIGN (prevailing->decl) < DECL_ALIGN (decl)) { diagnosed_p |= warning_at (DECL_SOURCE_LOCATION (decl), 0, "alignment of %qD is bigger than " "original declaration", decl); } } if (diagnosed_p) inform (DECL_SOURCE_LOCATION (prevailing->decl), "previously declared here"); VEC_free (tree, heap, mismatches); }
void redirect_edge_var_map_clear (edge e) { void **slot; edge_var_map_vector head; if (!edge_var_maps) return; slot = pointer_map_contains (edge_var_maps, e); if (slot) { head = (edge_var_map_vector) *slot; VEC_free (edge_var_map, heap, head); *slot = NULL; } }
/* Return SSA names that are unused to GGC memory and compact the SSA version namespace. This is used to keep footprint of compiler during interprocedural optimization. */ static unsigned int release_dead_ssa_names (void) { tree t; unsigned i, j; int n = VEC_length (tree, FREE_SSANAMES (cfun)); referenced_var_iterator rvi; /* Current defs point to various dead SSA names that in turn point to eventually dead variables so a bunch of memory is held live. */ FOR_EACH_REFERENCED_VAR (cfun, t, rvi) set_current_def (t, NULL); /* Now release the freelist. */ VEC_free (tree, gc, FREE_SSANAMES (cfun)); FREE_SSANAMES (cfun) = NULL; /* And compact the SSA number space. We make sure to not change the relative order of SSA versions. */ for (i = 1, j = 1; i < VEC_length (tree, cfun->gimple_df->ssa_names); ++i) { tree name = ssa_name (i); if (name) { if (i != j) { SSA_NAME_VERSION (name) = j; VEC_replace (tree, cfun->gimple_df->ssa_names, j, name); } j++; } } VEC_truncate (tree, cfun->gimple_df->ssa_names, j); statistics_counter_event (cfun, "SSA names released", n); statistics_counter_event (cfun, "SSA name holes removed", i - j); if (dump_file) fprintf (dump_file, "Released %i names, %.2f%%, removed %i holes\n", n, n * 100.0 / num_ssa_names, i - j); return 0; }
static inline gimple allocate_phi_node (size_t len) { gimple phi; size_t bucket = NUM_BUCKETS - 2; size_t size = sizeof (struct gimple_statement_phi) + (len - 1) * sizeof (struct phi_arg_d); if (free_phinode_count) for (bucket = len - 2; bucket < NUM_BUCKETS - 2; bucket++) if (free_phinodes[bucket]) break; /* If our free list has an element, then use it. */ if (bucket < NUM_BUCKETS - 2 && gimple_phi_capacity (VEC_index (gimple, free_phinodes[bucket], 0)) >= len) { free_phinode_count--; phi = VEC_pop (gimple, free_phinodes[bucket]); if (VEC_empty (gimple, free_phinodes[bucket])) VEC_free (gimple, gc, free_phinodes[bucket]); #ifdef GATHER_STATISTICS phi_nodes_reused++; #endif } else { phi = (gimple) ggc_alloc (size); #ifdef GATHER_STATISTICS phi_nodes_created++; { enum gimple_alloc_kind kind = gimple_alloc_kind (GIMPLE_PHI); gimple_alloc_counts[(int) kind]++; gimple_alloc_sizes[(int) kind] += size; } #endif } return phi; }
void fini_ssanames (void) { VEC_free (tree, gc, SSANAMES (cfun)); VEC_free (tree, gc, FREE_SSANAMES (cfun)); }
static void varobj_update_one (struct varobj *var, enum print_values print_values, int is_explicit) { struct ui_out *uiout = current_uiout; VEC (varobj_update_result) *changes; varobj_update_result *r; int i; changes = varobj_update (&var, is_explicit); for (i = 0; VEC_iterate (varobj_update_result, changes, i, r); ++i) { char *display_hint; int from, to; struct cleanup *cleanup = make_cleanup (null_cleanup, NULL); if (mi_version (uiout) > 1) make_cleanup_ui_out_tuple_begin_end (uiout, NULL); ui_out_field_string (uiout, "name", varobj_get_objname (r->varobj)); switch (r->status) { case VAROBJ_IN_SCOPE: if (mi_print_value_p (r->varobj, print_values)) { char *val = varobj_get_value (r->varobj); ui_out_field_string (uiout, "value", val); xfree (val); } ui_out_field_string (uiout, "in_scope", "true"); break; case VAROBJ_NOT_IN_SCOPE: ui_out_field_string (uiout, "in_scope", "false"); break; case VAROBJ_INVALID: ui_out_field_string (uiout, "in_scope", "invalid"); break; } if (r->status != VAROBJ_INVALID) { if (r->type_changed) ui_out_field_string (uiout, "type_changed", "true"); else ui_out_field_string (uiout, "type_changed", "false"); } if (r->type_changed) { char *type_name = varobj_get_type (r->varobj); ui_out_field_string (uiout, "new_type", type_name); xfree (type_name); } if (r->type_changed || r->children_changed) ui_out_field_int (uiout, "new_num_children", varobj_get_num_children (r->varobj)); display_hint = varobj_get_display_hint (r->varobj); if (display_hint) { ui_out_field_string (uiout, "displayhint", display_hint); xfree (display_hint); } if (varobj_is_dynamic_p (r->varobj)) ui_out_field_int (uiout, "dynamic", 1); varobj_get_child_range (r->varobj, &from, &to); ui_out_field_int (uiout, "has_more", varobj_has_more (r->varobj, to)); if (r->newobj) { int j; varobj_p child; struct cleanup *cleanup; cleanup = make_cleanup_ui_out_list_begin_end (uiout, "new_children"); for (j = 0; VEC_iterate (varobj_p, r->newobj, j, child); ++j) { struct cleanup *cleanup_child; cleanup_child = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); print_varobj (child, print_values, 1 /* print_expression */); do_cleanups (cleanup_child); } do_cleanups (cleanup); VEC_free (varobj_p, r->newobj); r->newobj = NULL; /* Paranoia. */ } do_cleanups (cleanup); } VEC_free (varobj_update_result, changes); }
void fini_ssanames (void) { VEC_free (tree, gc, ssa_names); free_ssanames = NULL; }
void gcc_cp_genericize (tree fndecl) { register_src_file(fndecl); tree t; struct cp_genericize_data wtd; /* Fix up the types of parms passed by invisible reference. */ for (t = DECL_ARGUMENTS (fndecl); t; t = DECL_CHAIN (t)) if (TREE_ADDRESSABLE (TREE_TYPE (t))) { /* If a function's arguments are copied to create a thunk, then DECL_BY_REFERENCE will be set -- but the type of the argument will be a pointer type, so we will never get here. */ gcc_assert (!DECL_BY_REFERENCE (t)); gcc_assert (DECL_ARG_TYPE (t) != TREE_TYPE (t)); TREE_TYPE (t) = DECL_ARG_TYPE (t); DECL_BY_REFERENCE (t) = 1; TREE_ADDRESSABLE (t) = 0; relayout_decl (t); } /* Do the same for the return value. */ if (TREE_ADDRESSABLE (TREE_TYPE (DECL_RESULT (fndecl)))) { t = DECL_RESULT (fndecl); TREE_TYPE (t) = build_reference_type (TREE_TYPE (t)); DECL_BY_REFERENCE (t) = 1; TREE_ADDRESSABLE (t) = 0; relayout_decl (t); if (DECL_NAME (t)) { /* Adjust DECL_VALUE_EXPR of the original var. */ tree outer = outer_curly_brace_block (current_function_decl); tree var; if (outer) for (var = BLOCK_VARS (outer); var; var = DECL_CHAIN (var)) if (DECL_NAME (t) == DECL_NAME (var) && DECL_HAS_VALUE_EXPR_P (var) && DECL_VALUE_EXPR (var) == t) { tree val = convert_from_reference (t); SET_DECL_VALUE_EXPR (var, val); break; } } } /* If we're a clone, the body is already GIMPLE. */ if (DECL_CLONED_FUNCTION_P (fndecl)) return; /* We do want to see every occurrence of the parms, so we can't just use walk_tree's hash functionality. */ wtd.p_set = pointer_set_create (); wtd.bind_expr_stack = NULL; cp_walk_tree (&DECL_SAVED_TREE (fndecl), cp_genericize_r, &wtd, NULL); pointer_set_destroy (wtd.p_set); VEC_free (tree, heap, wtd.bind_expr_stack); /* Do everything else. */ gcc_genericize (fndecl); gcc_assert (bc_label[bc_break] == NULL); gcc_assert (bc_label[bc_continue] == NULL); }
unsigned int execute_fixup_cfg (void) { basic_block bb; gimple_stmt_iterator gsi; int todo = gimple_in_ssa_p (cfun) ? TODO_verify_ssa : 0; gcov_type count_scale; edge e; edge_iterator ei; if (ENTRY_BLOCK_PTR->count) count_scale = (cgraph_node (current_function_decl)->count * REG_BR_PROB_BASE + ENTRY_BLOCK_PTR->count / 2) / ENTRY_BLOCK_PTR->count; else count_scale = REG_BR_PROB_BASE; ENTRY_BLOCK_PTR->count = cgraph_node (current_function_decl)->count; EXIT_BLOCK_PTR->count = (EXIT_BLOCK_PTR->count * count_scale + REG_BR_PROB_BASE / 2) / REG_BR_PROB_BASE; FOR_EACH_BB (bb) { bb->count = (bb->count * count_scale + REG_BR_PROB_BASE / 2) / REG_BR_PROB_BASE; for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple stmt = gsi_stmt (gsi); tree decl = is_gimple_call (stmt) ? gimple_call_fndecl (stmt) : NULL; if (decl) { int flags = gimple_call_flags (stmt); if (flags & (ECF_CONST | ECF_PURE | ECF_LOOPING_CONST_OR_PURE)) { if (gimple_in_ssa_p (cfun)) { todo |= TODO_update_ssa | TODO_cleanup_cfg; mark_symbols_for_renaming (stmt); update_stmt (stmt); } } if (flags & ECF_NORETURN && fixup_noreturn_call (stmt)) todo |= TODO_cleanup_cfg; } maybe_clean_eh_stmt (stmt); } if (gimple_purge_dead_eh_edges (bb)) todo |= TODO_cleanup_cfg; FOR_EACH_EDGE (e, ei, bb->succs) e->count = (e->count * count_scale + REG_BR_PROB_BASE / 2) / REG_BR_PROB_BASE; } if (count_scale != REG_BR_PROB_BASE) compute_function_frequency (); /* We just processed all calls. */ if (cfun->gimple_df) { VEC_free (gimple, gc, MODIFIED_NORETURN_CALLS (cfun)); MODIFIED_NORETURN_CALLS (cfun) = NULL; } /* Dump a textual representation of the flowgraph. */ if (dump_file) gimple_dump_cfg (dump_file, dump_flags); return todo; }
/* Propagate the constant parameters found by ipcp_iterate_stage() to the function's code. */ static void ipcp_insert_stage (void) { struct cgraph_node *node, *node1 = NULL; int i; VEC (cgraph_edge_p, heap) * redirect_callers; VEC (ipa_replace_map_p,gc)* replace_trees; int node_callers, count; tree parm_tree; struct ipa_replace_map *replace_param; fibheap_t heap; long overall_size = 0, new_size = 0; long max_new_size; ipa_check_create_node_params (); ipa_check_create_edge_args (); if (dump_file) fprintf (dump_file, "\nIPA insert stage:\n\n"); dead_nodes = BITMAP_ALLOC (NULL); for (node = cgraph_nodes; node; node = node->next) if (node->analyzed) { if (node->count > max_count) max_count = node->count; overall_size += node->local.inline_summary.self_size; } max_new_size = overall_size; if (max_new_size < PARAM_VALUE (PARAM_LARGE_UNIT_INSNS)) max_new_size = PARAM_VALUE (PARAM_LARGE_UNIT_INSNS); max_new_size = max_new_size * PARAM_VALUE (PARAM_IPCP_UNIT_GROWTH) / 100 + 1; /* First collect all functions we proved to have constant arguments to heap. */ heap = fibheap_new (); for (node = cgraph_nodes; node; node = node->next) { struct ipa_node_params *info; /* Propagation of the constant is forbidden in certain conditions. */ if (!node->analyzed || !ipcp_node_modifiable_p (node)) continue; info = IPA_NODE_REF (node); if (ipa_is_called_with_var_arguments (info)) continue; if (ipcp_const_param_count (node)) node->aux = fibheap_insert (heap, ipcp_estimate_cloning_cost (node), node); } /* Now clone in priority order until code size growth limits are met or heap is emptied. */ while (!fibheap_empty (heap)) { struct ipa_node_params *info; int growth = 0; bitmap args_to_skip; struct cgraph_edge *cs; node = (struct cgraph_node *)fibheap_extract_min (heap); node->aux = NULL; if (dump_file) fprintf (dump_file, "considering function %s\n", cgraph_node_name (node)); growth = ipcp_estimate_growth (node); if (new_size + growth > max_new_size) break; if (growth && optimize_function_for_size_p (DECL_STRUCT_FUNCTION (node->decl))) { if (dump_file) fprintf (dump_file, "Not versioning, cold code would grow"); continue; } info = IPA_NODE_REF (node); count = ipa_get_param_count (info); replace_trees = VEC_alloc (ipa_replace_map_p, gc, 1); if (node->local.can_change_signature) args_to_skip = BITMAP_GGC_ALLOC (); else args_to_skip = NULL; for (i = 0; i < count; i++) { struct ipcp_lattice *lat = ipcp_get_lattice (info, i); parm_tree = ipa_get_param (info, i); /* We can proactively remove obviously unused arguments. */ if (!ipa_is_param_used (info, i)) { if (args_to_skip) bitmap_set_bit (args_to_skip, i); continue; } if (lat->type == IPA_CONST_VALUE) { replace_param = ipcp_create_replace_map (parm_tree, lat); if (replace_param == NULL) break; VEC_safe_push (ipa_replace_map_p, gc, replace_trees, replace_param); if (args_to_skip) bitmap_set_bit (args_to_skip, i); } } if (i < count) { if (dump_file) fprintf (dump_file, "Not versioning, some parameters couldn't be replaced"); continue; } new_size += growth; /* Look if original function becomes dead after cloning. */ for (cs = node->callers; cs != NULL; cs = cs->next_caller) if (cs->caller == node || ipcp_need_redirect_p (cs)) break; if (!cs && cgraph_will_be_removed_from_program_if_no_direct_calls (node)) bitmap_set_bit (dead_nodes, node->uid); /* Compute how many callers node has. */ node_callers = 0; for (cs = node->callers; cs != NULL; cs = cs->next_caller) node_callers++; redirect_callers = VEC_alloc (cgraph_edge_p, heap, node_callers); for (cs = node->callers; cs != NULL; cs = cs->next_caller) if (!cs->indirect_inlining_edge) VEC_quick_push (cgraph_edge_p, redirect_callers, cs); /* Redirecting all the callers of the node to the new versioned node. */ node1 = cgraph_create_virtual_clone (node, redirect_callers, replace_trees, args_to_skip, "constprop"); args_to_skip = NULL; VEC_free (cgraph_edge_p, heap, redirect_callers); replace_trees = NULL; if (node1 == NULL) continue; ipcp_process_devirtualization_opportunities (node1); if (dump_file) fprintf (dump_file, "versioned function %s with growth %i, overall %i\n", cgraph_node_name (node), (int)growth, (int)new_size); ipcp_init_cloned_node (node, node1); info = IPA_NODE_REF (node); for (i = 0; i < count; i++) { struct ipcp_lattice *lat = ipcp_get_lattice (info, i); if (lat->type == IPA_CONST_VALUE) ipcp_discover_new_direct_edges (node1, i, lat->constant); } if (dump_file) dump_function_to_file (node1->decl, dump_file, dump_flags); for (cs = node->callees; cs; cs = cs->next_callee) if (cs->callee->aux) { fibheap_delete_node (heap, (fibnode_t) cs->callee->aux); cs->callee->aux = fibheap_insert (heap, ipcp_estimate_cloning_cost (cs->callee), cs->callee); } } while (!fibheap_empty (heap)) { if (dump_file) fprintf (dump_file, "skipping function %s\n", cgraph_node_name (node)); node = (struct cgraph_node *) fibheap_extract_min (heap); node->aux = NULL; } fibheap_delete (heap); BITMAP_FREE (dead_nodes); ipcp_update_callgraph (); ipcp_update_profiling (); }
/* Free the per SSA_NAME value-handle array. */ void threadedge_finalize_values (void) { VEC_free(tree, heap, ssa_name_values); }
VEC (char_ptr) * location_completer (struct cmd_list_element *ignore, const char *text, const char *word) { int n_syms, n_files, ix; VEC (char_ptr) *fn_list = NULL; VEC (char_ptr) *list = NULL; const char *p; int quote_found = 0; int quoted = *text == '\'' || *text == '"'; int quote_char = '\0'; const char *colon = NULL; char *file_to_match = NULL; const char *symbol_start = text; const char *orig_text = text; size_t text_len; /* Do we have an unquoted colon, as in "break foo.c:bar"? */ for (p = text; *p != '\0'; ++p) { if (*p == '\\' && p[1] == '\'') p++; else if (*p == '\'' || *p == '"') { quote_found = *p; quote_char = *p++; while (*p != '\0' && *p != quote_found) { if (*p == '\\' && p[1] == quote_found) p++; p++; } if (*p == quote_found) quote_found = 0; else break; /* Hit the end of text. */ } #if HAVE_DOS_BASED_FILE_SYSTEM /* If we have a DOS-style absolute file name at the beginning of TEXT, and the colon after the drive letter is the only colon we found, pretend the colon is not there. */ else if (p < text + 3 && *p == ':' && p == text + 1 + quoted) ; #endif else if (*p == ':' && !colon) { colon = p; symbol_start = p + 1; } else if (strchr (current_language->la_word_break_characters(), *p)) symbol_start = p + 1; } if (quoted) text++; text_len = strlen (text); /* Where is the file name? */ if (colon) { char *s; file_to_match = (char *) xmalloc (colon - text + 1); strncpy (file_to_match, text, colon - text + 1); /* Remove trailing colons and quotes from the file name. */ for (s = file_to_match + (colon - text); s > file_to_match; s--) if (*s == ':' || *s == quote_char) *s = '\0'; } /* If the text includes a colon, they want completion only on a symbol name after the colon. Otherwise, we need to complete on symbols as well as on files. */ if (colon) { list = make_file_symbol_completion_list (symbol_start, word, file_to_match); xfree (file_to_match); } else { list = make_symbol_completion_list (symbol_start, word); /* If text includes characters which cannot appear in a file name, they cannot be asking for completion on files. */ if (strcspn (text, gdb_completer_file_name_break_characters) == text_len) fn_list = make_source_files_completion_list (text, text); } n_syms = VEC_length (char_ptr, list); n_files = VEC_length (char_ptr, fn_list); /* Catenate fn_list[] onto the end of list[]. */ if (!n_syms) { VEC_free (char_ptr, list); /* Paranoia. */ list = fn_list; fn_list = NULL; } else { char *fn; for (ix = 0; VEC_iterate (char_ptr, fn_list, ix, fn); ++ix) VEC_safe_push (char_ptr, list, fn); VEC_free (char_ptr, fn_list); } if (n_syms && n_files) { /* Nothing. */ } else if (n_files) { char *fn; /* If we only have file names as possible completion, we should bring them in sync with what rl_complete expects. The problem is that if the user types "break /foo/b TAB", and the possible completions are "/foo/bar" and "/foo/baz" rl_complete expects us to return "bar" and "baz", without the leading directories, as possible completions, because `word' starts at the "b". But we ignore the value of `word' when we call make_source_files_completion_list above (because that would not DTRT when the completion results in both symbols and file names), so make_source_files_completion_list returns the full "/foo/bar" and "/foo/baz" strings. This produces wrong results when, e.g., there's only one possible completion, because rl_complete will prepend "/foo/" to each candidate completion. The loop below removes that leading part. */ for (ix = 0; VEC_iterate (char_ptr, list, ix, fn); ++ix) { memmove (fn, fn + (word - text), strlen (fn) + 1 - (word - text)); } } else if (!n_syms) { /* No completions at all. As the final resort, try completing on the entire text as a symbol. */ list = make_symbol_completion_list (orig_text, word); } return list; }
static void mem_clear (void) { VEC_free (mem_region_s, mem_region_list); }