flags.h: Add flag_eliminate_unused_debug_types.
* flags.h: Add flag_eliminate_unused_debug_types. * toplev.c: Add flag_eliminate_unused_debug_types. (f_options): Add -feliminate-unused-debug-types. * dwarf2out.c (struct file_table): Add emitted member. (splice_child_die): Fix the parent pointer for the child being spliced. (lookup_filename): Maintain file_table.emitted array. Don't output .file directive here. (maybe_emit_file): (new) (init_file_table): Set up file_table.emitted. (dwarf2out_source_line): Use maybe_emit_file. (dwarf2out_start_source_file): Use maybe_emit_file. (dwarf2out_init): Use maybe_emit_file. (prune_unused_types_walk_attribs): (new) (prune_unused_types_mark): (new) (prune_unused_types_walk): (new) (prune_unused_types_prune): (new) (prune_unused_types): (new) (dwarf2out_finish): Call prune_unused_types if flag_eliminate_unused_debug_types is set. * doc/invoke.texi (Option Summary): Add -feliminate-unused-debug-types. (Debugging Options): Likewise. From-SVN: r63588
This commit is contained in:
parent
d8fad4ea49
commit
73c68f614d
@ -1,3 +1,29 @@
|
|||||||
|
2003-02-28 scott snyder <snyder@fnal.gov>
|
||||||
|
|
||||||
|
* flags.h: Add flag_eliminate_unused_debug_types.
|
||||||
|
* toplev.c: Add flag_eliminate_unused_debug_types.
|
||||||
|
(f_options): Add -feliminate-unused-debug-types.
|
||||||
|
* dwarf2out.c (struct file_table): Add emitted member.
|
||||||
|
(splice_child_die): Fix the parent pointer for the child being
|
||||||
|
spliced.
|
||||||
|
(lookup_filename): Maintain file_table.emitted array. Don't
|
||||||
|
output .file directive here.
|
||||||
|
(maybe_emit_file): (new)
|
||||||
|
(init_file_table): Set up file_table.emitted.
|
||||||
|
(dwarf2out_source_line): Use maybe_emit_file.
|
||||||
|
(dwarf2out_start_source_file): Use maybe_emit_file.
|
||||||
|
(dwarf2out_init): Use maybe_emit_file.
|
||||||
|
(prune_unused_types_walk_attribs): (new)
|
||||||
|
(prune_unused_types_mark): (new)
|
||||||
|
(prune_unused_types_walk): (new)
|
||||||
|
(prune_unused_types_prune): (new)
|
||||||
|
(prune_unused_types): (new)
|
||||||
|
(dwarf2out_finish): Call prune_unused_types if
|
||||||
|
flag_eliminate_unused_debug_types is set.
|
||||||
|
* doc/invoke.texi (Option Summary): Add
|
||||||
|
-feliminate-unused-debug-types.
|
||||||
|
(Debugging Options): Likewise.
|
||||||
|
|
||||||
2003-02-28 Geoffrey Keating <geoffk@apple.com>
|
2003-02-28 Geoffrey Keating <geoffk@apple.com>
|
||||||
|
|
||||||
* doc/invoke.texi: Change .pch to .gch.
|
* doc/invoke.texi: Change .pch to .gch.
|
||||||
|
@ -258,6 +258,7 @@ in the following sections.
|
|||||||
-p -pg -print-file-name=@var{library} -print-libgcc-file-name @gol
|
-p -pg -print-file-name=@var{library} -print-libgcc-file-name @gol
|
||||||
-print-multi-directory -print-multi-lib @gol
|
-print-multi-directory -print-multi-lib @gol
|
||||||
-print-prog-name=@var{program} -print-search-dirs -Q @gol
|
-print-prog-name=@var{program} -print-search-dirs -Q @gol
|
||||||
|
-feliminate-unused-debug-types @gol
|
||||||
-save-temps -time}
|
-save-temps -time}
|
||||||
|
|
||||||
@item Optimization Options
|
@item Optimization Options
|
||||||
@ -3412,6 +3413,18 @@ anything else.
|
|||||||
@opindex dumpspecs
|
@opindex dumpspecs
|
||||||
Print the compiler's built-in specs---and don't do anything else. (This
|
Print the compiler's built-in specs---and don't do anything else. (This
|
||||||
is used when GCC itself is being built.) @xref{Spec Files}.
|
is used when GCC itself is being built.) @xref{Spec Files}.
|
||||||
|
|
||||||
|
@item -feliminate-unused-debug-types
|
||||||
|
@opindex feliminate-unused-debug-types
|
||||||
|
Normally, when producing DWARF2 output, GCC will emit debugging
|
||||||
|
information for all types declared in a compilation
|
||||||
|
unit, regardless of whether or not they are actually used
|
||||||
|
in that compilation unit. Sometimes this is useful, such as
|
||||||
|
if, in the debugger, you want to cast a value to a type that is
|
||||||
|
not actually used in your program (but is declared). More often,
|
||||||
|
however, this results in a significant amount of wasted space.
|
||||||
|
With this option, GCC will avoid producing debug symbol output
|
||||||
|
for types that are nowhere used in the source file being compiled.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@node Optimize Options
|
@node Optimize Options
|
||||||
|
257
gcc/dwarf2out.c
257
gcc/dwarf2out.c
@ -3458,6 +3458,7 @@ static GTY(()) limbo_die_node *limbo_die_list;
|
|||||||
|
|
||||||
/* Filenames referenced by this compilation unit. */
|
/* Filenames referenced by this compilation unit. */
|
||||||
static GTY(()) varray_type file_table;
|
static GTY(()) varray_type file_table;
|
||||||
|
static GTY(()) varray_type file_table_emitted;
|
||||||
static GTY(()) size_t file_table_last_lookup_index;
|
static GTY(()) size_t file_table_last_lookup_index;
|
||||||
|
|
||||||
/* A pointer to the base of a table of references to DIE's that describe
|
/* A pointer to the base of a table of references to DIE's that describe
|
||||||
@ -3844,6 +3845,14 @@ static void add_loc_descr_to_loc_list PARAMS ((dw_loc_list_ref *,
|
|||||||
static void output_loc_list PARAMS ((dw_loc_list_ref));
|
static void output_loc_list PARAMS ((dw_loc_list_ref));
|
||||||
static char *gen_internal_sym PARAMS ((const char *));
|
static char *gen_internal_sym PARAMS ((const char *));
|
||||||
|
|
||||||
|
static void prune_unmark_dies PARAMS ((dw_die_ref));
|
||||||
|
static void prune_unused_types_mark PARAMS ((dw_die_ref, int));
|
||||||
|
static void prune_unused_types_walk PARAMS ((dw_die_ref));
|
||||||
|
static void prune_unused_types_walk_attribs PARAMS ((dw_die_ref));
|
||||||
|
static void prune_unused_types_prune PARAMS ((dw_die_ref));
|
||||||
|
static void prune_unused_types PARAMS ((void));
|
||||||
|
static int maybe_emit_file PARAMS ((int));
|
||||||
|
|
||||||
/* Section names used to hold DWARF debugging information. */
|
/* Section names used to hold DWARF debugging information. */
|
||||||
#ifndef DEBUG_INFO_SECTION
|
#ifndef DEBUG_INFO_SECTION
|
||||||
#define DEBUG_INFO_SECTION ".debug_info"
|
#define DEBUG_INFO_SECTION ".debug_info"
|
||||||
@ -5217,6 +5226,7 @@ splice_child_die (parent, child)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
child->die_parent = parent;
|
||||||
child->die_sib = parent->die_child;
|
child->die_sib = parent->die_child;
|
||||||
parent->die_child = child;
|
parent->die_child = child;
|
||||||
}
|
}
|
||||||
@ -12352,25 +12362,43 @@ lookup_filename (file_name)
|
|||||||
file_table_last_lookup_index = n;
|
file_table_last_lookup_index = n;
|
||||||
save_file_name = (char *) ggc_strdup (file_name);
|
save_file_name = (char *) ggc_strdup (file_name);
|
||||||
VARRAY_PUSH_CHAR_PTR (file_table, save_file_name);
|
VARRAY_PUSH_CHAR_PTR (file_table, save_file_name);
|
||||||
|
VARRAY_PUSH_UINT (file_table_emitted, 0);
|
||||||
if (DWARF2_ASM_LINE_DEBUG_INFO)
|
|
||||||
{
|
|
||||||
fprintf (asm_out_file, "\t.file %lu ", (unsigned long) i);
|
|
||||||
output_quoted_string (asm_out_file, file_name);
|
|
||||||
fputc ('\n', asm_out_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
maybe_emit_file (fileno)
|
||||||
|
int fileno;
|
||||||
|
{
|
||||||
|
static int emitcount = 0;
|
||||||
|
if (DWARF2_ASM_LINE_DEBUG_INFO && fileno > 0)
|
||||||
|
{
|
||||||
|
if (!VARRAY_UINT (file_table_emitted, fileno))
|
||||||
|
{
|
||||||
|
VARRAY_UINT (file_table_emitted, fileno) = ++emitcount;
|
||||||
|
fprintf (asm_out_file, "\t.file %u ",
|
||||||
|
VARRAY_UINT (file_table_emitted, fileno));
|
||||||
|
output_quoted_string (asm_out_file,
|
||||||
|
VARRAY_CHAR_PTR (file_table, fileno));
|
||||||
|
fputc ('\n', asm_out_file);
|
||||||
|
}
|
||||||
|
return VARRAY_UINT (file_table_emitted, fileno);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return fileno;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
init_file_table ()
|
init_file_table ()
|
||||||
{
|
{
|
||||||
/* Allocate the initial hunk of the file_table. */
|
/* Allocate the initial hunk of the file_table. */
|
||||||
VARRAY_CHAR_PTR_INIT (file_table, 64, "file_table");
|
VARRAY_CHAR_PTR_INIT (file_table, 64, "file_table");
|
||||||
|
VARRAY_UINT_INIT (file_table_emitted, 64, "file_table_emitted");
|
||||||
|
|
||||||
/* Skip the first entry - file numbers begin at 1. */
|
/* Skip the first entry - file numbers begin at 1. */
|
||||||
VARRAY_PUSH_CHAR_PTR (file_table, NULL);
|
VARRAY_PUSH_CHAR_PTR (file_table, NULL);
|
||||||
|
VARRAY_PUSH_UINT (file_table_emitted, 0);
|
||||||
file_table_last_lookup_index = 0;
|
file_table_last_lookup_index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12396,6 +12424,8 @@ dwarf2out_source_line (line, filename)
|
|||||||
{
|
{
|
||||||
unsigned file_num = lookup_filename (filename);
|
unsigned file_num = lookup_filename (filename);
|
||||||
|
|
||||||
|
file_num = maybe_emit_file (file_num);
|
||||||
|
|
||||||
/* Emit the .loc directive understood by GNU as. */
|
/* Emit the .loc directive understood by GNU as. */
|
||||||
fprintf (asm_out_file, "\t.loc %d %d 0\n", file_num, line);
|
fprintf (asm_out_file, "\t.loc %d %d 0\n", file_num, line);
|
||||||
|
|
||||||
@ -12487,6 +12517,7 @@ dwarf2out_start_source_file (lineno, filename)
|
|||||||
dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
|
dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
|
||||||
dw2_asm_output_data_uleb128 (lineno, "Included from line number %d",
|
dw2_asm_output_data_uleb128 (lineno, "Included from line number %d",
|
||||||
lineno);
|
lineno);
|
||||||
|
maybe_emit_file (lookup_filename (filename));
|
||||||
dw2_asm_output_data_uleb128 (lookup_filename (filename),
|
dw2_asm_output_data_uleb128 (lookup_filename (filename),
|
||||||
"Filename we just started");
|
"Filename we just started");
|
||||||
}
|
}
|
||||||
@ -12646,6 +12677,215 @@ output_indirect_string (h, v)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Clear the marks for a die and its children.
|
||||||
|
Be cool if the mark isn't set. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
prune_unmark_dies (die)
|
||||||
|
dw_die_ref die;
|
||||||
|
{
|
||||||
|
dw_die_ref c;
|
||||||
|
die->die_mark = 0;
|
||||||
|
for (c = die->die_child; c; c = c->die_sib)
|
||||||
|
prune_unmark_dies (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Given DIE that we're marking as used, find any other dies
|
||||||
|
it references as attributes and mark them as used. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
prune_unused_types_walk_attribs (die)
|
||||||
|
dw_die_ref die;
|
||||||
|
{
|
||||||
|
dw_attr_ref a;
|
||||||
|
|
||||||
|
for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
|
||||||
|
{
|
||||||
|
if (a->dw_attr_val.val_class == dw_val_class_die_ref)
|
||||||
|
{
|
||||||
|
/* A reference to another DIE.
|
||||||
|
Make sure that it will get emitted. */
|
||||||
|
prune_unused_types_mark (a->dw_attr_val.v.val_die_ref.die, 1);
|
||||||
|
}
|
||||||
|
else if (a->dw_attr == DW_AT_decl_file)
|
||||||
|
{
|
||||||
|
/* A reference to a file. Make sure the file name is emitted. */
|
||||||
|
a->dw_attr_val.v.val_unsigned =
|
||||||
|
maybe_emit_file (a->dw_attr_val.v.val_unsigned);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Mark DIE as being used. If DOKIDS is true, then walk down
|
||||||
|
to DIE's children. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
prune_unused_types_mark (die, dokids)
|
||||||
|
dw_die_ref die;
|
||||||
|
int dokids;
|
||||||
|
{
|
||||||
|
dw_die_ref c;
|
||||||
|
|
||||||
|
if (die->die_mark == 0)
|
||||||
|
{
|
||||||
|
/* We haven't done this node yet. Mark it as used. */
|
||||||
|
die->die_mark = 1;
|
||||||
|
|
||||||
|
/* We also have to mark its parents as used.
|
||||||
|
(But we don't want to mark our parents' kids due to this.) */
|
||||||
|
if (die->die_parent)
|
||||||
|
prune_unused_types_mark (die->die_parent, 0);
|
||||||
|
|
||||||
|
/* Mark any referenced nodes. */
|
||||||
|
prune_unused_types_walk_attribs (die);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dokids && die->die_mark != 2)
|
||||||
|
{
|
||||||
|
/* We need to walk the children, but haven't done so yet.
|
||||||
|
Remember that we've walked the kids. */
|
||||||
|
die->die_mark = 2;
|
||||||
|
|
||||||
|
/* Walk them. */
|
||||||
|
for (c = die->die_child; c; c = c->die_sib)
|
||||||
|
{
|
||||||
|
/* If this is an array type, we need to make sure our
|
||||||
|
kids get marked, even if they're types. */
|
||||||
|
if (die->die_tag == DW_TAG_array_type)
|
||||||
|
prune_unused_types_mark (c, 1);
|
||||||
|
else
|
||||||
|
prune_unused_types_walk (c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Walk the tree DIE and mark types that we actually use. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
prune_unused_types_walk (die)
|
||||||
|
dw_die_ref die;
|
||||||
|
{
|
||||||
|
dw_die_ref c;
|
||||||
|
|
||||||
|
/* Don't do anything if this node is already marked. */
|
||||||
|
if (die->die_mark)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (die->die_tag) {
|
||||||
|
case DW_TAG_const_type:
|
||||||
|
case DW_TAG_packed_type:
|
||||||
|
case DW_TAG_pointer_type:
|
||||||
|
case DW_TAG_reference_type:
|
||||||
|
case DW_TAG_volatile_type:
|
||||||
|
case DW_TAG_typedef:
|
||||||
|
case DW_TAG_array_type:
|
||||||
|
case DW_TAG_structure_type:
|
||||||
|
case DW_TAG_union_type:
|
||||||
|
case DW_TAG_class_type:
|
||||||
|
case DW_TAG_friend:
|
||||||
|
case DW_TAG_variant_part:
|
||||||
|
case DW_TAG_enumeration_type:
|
||||||
|
case DW_TAG_subroutine_type:
|
||||||
|
case DW_TAG_string_type:
|
||||||
|
case DW_TAG_set_type:
|
||||||
|
case DW_TAG_subrange_type:
|
||||||
|
case DW_TAG_ptr_to_member_type:
|
||||||
|
case DW_TAG_file_type:
|
||||||
|
/* It's a type node --- don't mark it. */
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Mark everything else. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
die->die_mark = 1;
|
||||||
|
|
||||||
|
/* Now, mark any dies referenced from here. */
|
||||||
|
prune_unused_types_walk_attribs (die);
|
||||||
|
|
||||||
|
/* Mark children. */
|
||||||
|
for (c = die->die_child; c; c = c->die_sib)
|
||||||
|
prune_unused_types_walk (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Remove from the tree DIE any dies that aren't marked. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
prune_unused_types_prune (die)
|
||||||
|
dw_die_ref die;
|
||||||
|
{
|
||||||
|
dw_die_ref c, p, n;
|
||||||
|
if (!die->die_mark)
|
||||||
|
abort();
|
||||||
|
|
||||||
|
p = NULL;
|
||||||
|
for (c = die->die_child; c; c = n)
|
||||||
|
{
|
||||||
|
n = c->die_sib;
|
||||||
|
if (c->die_mark)
|
||||||
|
{
|
||||||
|
prune_unused_types_prune (c);
|
||||||
|
p = c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (p)
|
||||||
|
p->die_sib = n;
|
||||||
|
else
|
||||||
|
die->die_child = n;
|
||||||
|
free_die (c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Remove dies representing declarations that we never use. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
prune_unused_types ()
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
limbo_die_node *node;
|
||||||
|
|
||||||
|
/* Clear all the marks. */
|
||||||
|
prune_unmark_dies (comp_unit_die);
|
||||||
|
for (node = limbo_die_list; node; node = node->next)
|
||||||
|
prune_unmark_dies (node->die);
|
||||||
|
|
||||||
|
/* Set the mark on nodes that are actually used. */
|
||||||
|
prune_unused_types_walk (comp_unit_die);
|
||||||
|
for (node = limbo_die_list; node; node = node->next)
|
||||||
|
prune_unused_types_walk (node->die);
|
||||||
|
|
||||||
|
/* Also set the mark on nodes referenced from the
|
||||||
|
pubname_table or arange_table. */
|
||||||
|
for (i=0; i < pubname_table_in_use; i++)
|
||||||
|
{
|
||||||
|
prune_unused_types_mark (pubname_table[i].die, 1);
|
||||||
|
}
|
||||||
|
for (i=0; i < arange_table_in_use; i++)
|
||||||
|
{
|
||||||
|
prune_unused_types_mark (arange_table[i], 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get rid of nodes that aren't marked. */
|
||||||
|
prune_unused_types_prune (comp_unit_die);
|
||||||
|
for (node = limbo_die_list; node; node = node->next)
|
||||||
|
prune_unused_types_prune (node->die);
|
||||||
|
|
||||||
|
/* Leave the marks clear. */
|
||||||
|
prune_unmark_dies (comp_unit_die);
|
||||||
|
for (node = limbo_die_list; node; node = node->next)
|
||||||
|
prune_unmark_dies (node->die);
|
||||||
|
}
|
||||||
|
|
||||||
/* Output stuff that dwarf requires at the end of every file,
|
/* Output stuff that dwarf requires at the end of every file,
|
||||||
and generate the DWARF-2 debugging info. */
|
and generate the DWARF-2 debugging info. */
|
||||||
|
|
||||||
@ -12740,6 +12980,9 @@ dwarf2out_finish (input_filename)
|
|||||||
if (flag_eliminate_dwarf2_dups)
|
if (flag_eliminate_dwarf2_dups)
|
||||||
break_out_includes (comp_unit_die);
|
break_out_includes (comp_unit_die);
|
||||||
|
|
||||||
|
if (flag_eliminate_unused_debug_types)
|
||||||
|
prune_unused_types ();
|
||||||
|
|
||||||
/* Traverse the DIE's and add add sibling attributes to those DIE's
|
/* Traverse the DIE's and add add sibling attributes to those DIE's
|
||||||
that have children. */
|
that have children. */
|
||||||
add_sibling_attributes (comp_unit_die);
|
add_sibling_attributes (comp_unit_die);
|
||||||
|
@ -641,6 +641,10 @@ extern int flag_gcse_sm;
|
|||||||
|
|
||||||
extern int flag_eliminate_dwarf2_dups;
|
extern int flag_eliminate_dwarf2_dups;
|
||||||
|
|
||||||
|
/* Nonzero means we should do unused type elimination. */
|
||||||
|
|
||||||
|
extern int flag_eliminate_unused_debug_types;
|
||||||
|
|
||||||
/* Nonzero means to collect statistics which might be expensive
|
/* Nonzero means to collect statistics which might be expensive
|
||||||
and to print them when we are done. */
|
and to print them when we are done. */
|
||||||
extern int flag_detailed_statistics;
|
extern int flag_detailed_statistics;
|
||||||
|
@ -378,6 +378,10 @@ tree current_function_func_begin_label;
|
|||||||
|
|
||||||
int flag_eliminate_dwarf2_dups = 0;
|
int flag_eliminate_dwarf2_dups = 0;
|
||||||
|
|
||||||
|
/* Nonzero if doing unused type elimination. */
|
||||||
|
|
||||||
|
int flag_eliminate_unused_debug_types = 0;
|
||||||
|
|
||||||
/* Nonzero if generating code to do profiling. */
|
/* Nonzero if generating code to do profiling. */
|
||||||
|
|
||||||
int profile_flag = 0;
|
int profile_flag = 0;
|
||||||
@ -999,6 +1003,8 @@ static const lang_independent_options f_options[] =
|
|||||||
{
|
{
|
||||||
{"eliminate-dwarf2-dups", &flag_eliminate_dwarf2_dups, 1,
|
{"eliminate-dwarf2-dups", &flag_eliminate_dwarf2_dups, 1,
|
||||||
N_("Perform DWARF2 duplicate elimination") },
|
N_("Perform DWARF2 duplicate elimination") },
|
||||||
|
{"eliminate-unused-debug-types", &flag_eliminate_unused_debug_types, 1,
|
||||||
|
N_("Perform unused type elimination in debug info") },
|
||||||
{"float-store", &flag_float_store, 1,
|
{"float-store", &flag_float_store, 1,
|
||||||
N_("Do not store floats in registers") },
|
N_("Do not store floats in registers") },
|
||||||
{"defer-pop", &flag_defer_pop, 1,
|
{"defer-pop", &flag_defer_pop, 1,
|
||||||
|
Loading…
Reference in New Issue
Block a user