Commit 07250f0e by Jan Hubicka Committed by Jan Hubicka

tree.h (alias_diag_flags): Remove.


	* tree.h (alias_diag_flags): Remove.
	(alias_pair): Remove emitted_diags.
	(finish_aliases_1, finish_aliases_2, remove_unreachable_alias_pairs,
	symbol_alias_set_t, symbol_alias_set_destroy,
	symbol_alias_set_contains, propagate_aliases_backward): Remove.
	* toplev.c (compile_file): Do not call finish_aliases_2
	* cgraphunit.c (cgraph_process_new_functions): Do not call finish_aliases_1.
	(handle_alias_pairs): Output diagnostics about aliases to externals.
	(assemble_thunks_and_aliases): Use do_assemble_alias.
	(output_weakrefs): Likewise.
	(finalize_compilation_unit): Do not call finish_aliases_1.
	* ipa.c (symtab_remove_unreachable_nodes): De not call remove_unreachable_alias_pairs.
	* varasm.c (do_assemble_alias): Export.
	(symbol_alias_set_create, symbol_alias_set_destroy, symbol_alias_set_contains,
	symbol_alias_set_insert, propagate_aliases_forward, propagate_aliases_backward,
	propagate_aliases_backward, trivially_visible_alias, trivially_defined_alias,
	remove_unreachable_alias_pairs, finish_aliases_1, finish_aliases_2, 
	assemble_alias): Remove.
	* output.h (do_assemble_alias): Declare.
	* varpool.c (varpool_remove_unreferenced_decls): Do not call finish_aliases_1.

From-SVN: r187823
parent 0f4fb41f
2012-05-23 Jan Hubicka <jh@suse.cz>
* tree.h (alias_diag_flags): Remove.
(alias_pair): Remove emitted_diags.
(finish_aliases_1, finish_aliases_2, remove_unreachable_alias_pairs,
symbol_alias_set_t, symbol_alias_set_destroy,
symbol_alias_set_contains, propagate_aliases_backward): Remove.
* toplev.c (compile_file): Do not call finish_aliases_2
* cgraphunit.c (cgraph_process_new_functions): Do not call finish_aliases_1.
(handle_alias_pairs): Output diagnostics about aliases to externals.
(assemble_thunks_and_aliases): Use do_assemble_alias.
(output_weakrefs): Likewise.
(finalize_compilation_unit): Do not call finish_aliases_1.
* ipa.c (symtab_remove_unreachable_nodes): De not call remove_unreachable_alias_pairs.
* varasm.c (do_assemble_alias): Export.
(symbol_alias_set_create, symbol_alias_set_destroy, symbol_alias_set_contains,
symbol_alias_set_insert, propagate_aliases_forward, propagate_aliases_backward,
propagate_aliases_backward, trivially_visible_alias, trivially_defined_alias,
remove_unreachable_alias_pairs, finish_aliases_1, finish_aliases_2,
assemble_alias): Remove.
* output.h (do_assemble_alias): Declare.
* varpool.c (varpool_remove_unreferenced_decls): Do not call finish_aliases_1.
2012-05-23 Martin Jambor <mjambor@suse.cz> 2012-05-23 Martin Jambor <mjambor@suse.cz>
* ipa-inline-analysis.c (inline_merge_summary): Free operand_map. * ipa-inline-analysis.c (inline_merge_summary): Free operand_map.
......
...@@ -285,7 +285,6 @@ cgraph_process_new_functions (void) ...@@ -285,7 +285,6 @@ cgraph_process_new_functions (void)
if (!cgraph_new_nodes) if (!cgraph_new_nodes)
return false; return false;
finish_aliases_1 ();
handle_alias_pairs (); handle_alias_pairs ();
/* Note that this queue may grow as its being processed, as the new /* Note that this queue may grow as its being processed, as the new
functions may generate new ones. */ functions may generate new ones. */
...@@ -1068,6 +1067,18 @@ handle_alias_pairs (void) ...@@ -1068,6 +1067,18 @@ handle_alias_pairs (void)
= lookup_attribute ("weakref", = lookup_attribute ("weakref",
DECL_ATTRIBUTES (p->decl)) != NULL; DECL_ATTRIBUTES (p->decl)) != NULL;
if (DECL_EXTERNAL (target_node->symbol.decl)
/* We use local aliases for C++ thunks to force the tailcall
to bind locally. This is a hack - to keep it working do
the following (which is not strictly correct). */
&& (! TREE_CODE (target_node->symbol.decl) == FUNCTION_DECL
|| ! DECL_VIRTUAL_P (target_node->symbol.decl))
&& ! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)))
{
error ("%q+D aliased to external symbol %qE",
p->decl, p->target);
}
if (TREE_CODE (p->decl) == FUNCTION_DECL if (TREE_CODE (p->decl) == FUNCTION_DECL
&& target_node && symtab_function_p (target_node)) && target_node && symtab_function_p (target_node))
{ {
...@@ -1185,6 +1196,7 @@ mark_functions_to_output (void) ...@@ -1185,6 +1196,7 @@ mark_functions_to_output (void)
end up not removing the body since we no longer have an end up not removing the body since we no longer have an
analyzed node pointing to it. */ analyzed node pointing to it. */
&& !node->symbol.in_other_partition && !node->symbol.in_other_partition
&& !node->clones
&& !DECL_EXTERNAL (decl)) && !DECL_EXTERNAL (decl))
{ {
dump_cgraph_node (stderr, node); dump_cgraph_node (stderr, node);
...@@ -1552,8 +1564,8 @@ assemble_thunks_and_aliases (struct cgraph_node *node) ...@@ -1552,8 +1564,8 @@ assemble_thunks_and_aliases (struct cgraph_node *node)
/* Force assemble_alias to really output the alias this time instead /* Force assemble_alias to really output the alias this time instead
of buffering it in same alias pairs. */ of buffering it in same alias pairs. */
TREE_ASM_WRITTEN (alias->thunk.alias) = 1; TREE_ASM_WRITTEN (alias->thunk.alias) = 1;
assemble_alias (alias->symbol.decl, do_assemble_alias (alias->symbol.decl,
DECL_ASSEMBLER_NAME (alias->thunk.alias)); DECL_ASSEMBLER_NAME (alias->thunk.alias));
assemble_thunks_and_aliases (alias); assemble_thunks_and_aliases (alias);
TREE_ASM_WRITTEN (alias->thunk.alias) = saved_written; TREE_ASM_WRITTEN (alias->thunk.alias) = saved_written;
} }
...@@ -1902,16 +1914,16 @@ output_weakrefs (void) ...@@ -1902,16 +1914,16 @@ output_weakrefs (void)
if (node->alias && DECL_EXTERNAL (node->symbol.decl) if (node->alias && DECL_EXTERNAL (node->symbol.decl)
&& !TREE_ASM_WRITTEN (node->symbol.decl) && !TREE_ASM_WRITTEN (node->symbol.decl)
&& lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl))) && lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl)))
assemble_alias (node->symbol.decl, do_assemble_alias (node->symbol.decl,
node->thunk.alias ? DECL_ASSEMBLER_NAME (node->thunk.alias) node->thunk.alias ? DECL_ASSEMBLER_NAME (node->thunk.alias)
: get_alias_symbol (node->symbol.decl)); : get_alias_symbol (node->symbol.decl));
FOR_EACH_VARIABLE (vnode) FOR_EACH_VARIABLE (vnode)
if (vnode->alias && DECL_EXTERNAL (vnode->symbol.decl) if (vnode->alias && DECL_EXTERNAL (vnode->symbol.decl)
&& !TREE_ASM_WRITTEN (vnode->symbol.decl) && !TREE_ASM_WRITTEN (vnode->symbol.decl)
&& lookup_attribute ("weakref", DECL_ATTRIBUTES (vnode->symbol.decl))) && lookup_attribute ("weakref", DECL_ATTRIBUTES (vnode->symbol.decl)))
assemble_alias (vnode->symbol.decl, do_assemble_alias (vnode->symbol.decl,
vnode->alias_of ? DECL_ASSEMBLER_NAME (vnode->alias_of) vnode->alias_of ? DECL_ASSEMBLER_NAME (vnode->alias_of)
: get_alias_symbol (vnode->symbol.decl)); : get_alias_symbol (vnode->symbol.decl));
} }
/* Initialize callgraph dump file. */ /* Initialize callgraph dump file. */
...@@ -1995,7 +2007,6 @@ compile (void) ...@@ -1995,7 +2007,6 @@ compile (void)
#endif #endif
bitmap_obstack_release (NULL); bitmap_obstack_release (NULL);
mark_functions_to_output (); mark_functions_to_output ();
output_weakrefs ();
cgraph_state = CGRAPH_STATE_EXPANSION; cgraph_state = CGRAPH_STATE_EXPANSION;
if (!flag_toplevel_reorder) if (!flag_toplevel_reorder)
...@@ -2010,6 +2021,7 @@ compile (void) ...@@ -2010,6 +2021,7 @@ compile (void)
cgraph_process_new_functions (); cgraph_process_new_functions ();
cgraph_state = CGRAPH_STATE_FINISHED; cgraph_state = CGRAPH_STATE_FINISHED;
output_weakrefs ();
if (cgraph_dump_file) if (cgraph_dump_file)
{ {
...@@ -2058,7 +2070,6 @@ finalize_compilation_unit (void) ...@@ -2058,7 +2070,6 @@ finalize_compilation_unit (void)
finalize_size_functions (); finalize_size_functions ();
/* Mark alias targets necessary and emit diagnostics. */ /* Mark alias targets necessary and emit diagnostics. */
finish_aliases_1 ();
handle_alias_pairs (); handle_alias_pairs ();
if (!quiet_flag) if (!quiet_flag)
...@@ -2075,7 +2086,6 @@ finalize_compilation_unit (void) ...@@ -2075,7 +2086,6 @@ finalize_compilation_unit (void)
cgraph_analyze_functions (); cgraph_analyze_functions ();
/* Mark alias targets necessary and emit diagnostics. */ /* Mark alias targets necessary and emit diagnostics. */
finish_aliases_1 ();
handle_alias_pairs (); handle_alias_pairs ();
/* Gimplify and lower thunks. */ /* Gimplify and lower thunks. */
......
...@@ -454,10 +454,6 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file) ...@@ -454,10 +454,6 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
FOR_EACH_DEFINED_FUNCTION (node) FOR_EACH_DEFINED_FUNCTION (node)
cgraph_propagate_frequency (node); cgraph_propagate_frequency (node);
/* Reclaim alias pairs for functions that have disappeared from the
call graph. */
remove_unreachable_alias_pairs ();
return changed; return changed;
} }
......
...@@ -187,6 +187,7 @@ extern int decode_reg_name (const char *); ...@@ -187,6 +187,7 @@ extern int decode_reg_name (const char *);
extern int decode_reg_name_and_count (const char *, int *); extern int decode_reg_name_and_count (const char *, int *);
extern void assemble_alias (tree, tree); extern void assemble_alias (tree, tree);
extern void do_assemble_alias (tree, tree);
extern void default_assemble_visibility (tree, int); extern void default_assemble_visibility (tree, int);
......
...@@ -577,8 +577,6 @@ compile_file (void) ...@@ -577,8 +577,6 @@ compile_file (void)
basically finished. */ basically finished. */
if (in_lto_p || !flag_lto || flag_fat_lto_objects) if (in_lto_p || !flag_lto || flag_fat_lto_objects)
{ {
finish_aliases_2 ();
/* Likewise for mudflap static object registrations. */ /* Likewise for mudflap static object registrations. */
if (flag_mudflap) if (flag_mudflap)
mudflap_finish_file (); mudflap_finish_file ();
......
...@@ -239,25 +239,14 @@ extern const unsigned char tree_code_length[]; ...@@ -239,25 +239,14 @@ extern const unsigned char tree_code_length[];
extern const char *const tree_code_name[]; extern const char *const tree_code_name[];
/* We have to be able to tell cgraph about the needed-ness of the target /* When procesing aliases on symtab level, we need the declaration of target.
of an alias. This requires that the decl have been defined. Aliases For this reason we need to queue aliases and process them after all declarations
that precede their definition have to be queued for later processing. */ has been produced. */
/* The deferred processing proceeds in several passes. We memorize the
diagnostics emitted for a pair to prevent repeating messages when the
queue gets re-scanned after possible updates. */
typedef enum {
ALIAS_DIAG_NONE = 0x0,
ALIAS_DIAG_TO_UNDEF = 0x1,
ALIAS_DIAG_TO_EXTERN = 0x2
} alias_diag_flags;
typedef struct GTY(()) alias_pair typedef struct GTY(()) alias_pair
{ {
tree decl; tree decl;
tree target; tree target;
int emitted_diags; /* alias_diags already emitted for this pair. */
} alias_pair; } alias_pair;
/* Define gc'd vector type. */ /* Define gc'd vector type. */
...@@ -5691,24 +5680,8 @@ extern void mark_decl_referenced (tree); ...@@ -5691,24 +5680,8 @@ extern void mark_decl_referenced (tree);
extern void notice_global_symbol (tree); extern void notice_global_symbol (tree);
extern void set_user_assembler_name (tree, const char *); extern void set_user_assembler_name (tree, const char *);
extern void process_pending_assemble_externals (void); extern void process_pending_assemble_externals (void);
extern void finish_aliases_1 (void);
extern void finish_aliases_2 (void);
extern void remove_unreachable_alias_pairs (void);
extern bool decl_replaceable_p (tree); extern bool decl_replaceable_p (tree);
extern bool decl_binds_to_current_def_p (tree); extern bool decl_binds_to_current_def_p (tree);
/* Derived type for use by compute_visible_aliases and callers. A symbol
alias set is a pointer set into which we enter IDENTIFIER_NODES bearing
the canonicalised assembler-level symbol names corresponding to decls
and their aliases. */
typedef struct pointer_set_t symbol_alias_set_t;
extern void symbol_alias_set_destroy (symbol_alias_set_t *);
extern int symbol_alias_set_contains (const symbol_alias_set_t *, tree);
extern symbol_alias_set_t * propagate_aliases_backward (bool (*)
(tree, tree, void *),
void *);
/* In stmt.c */ /* In stmt.c */
extern void expand_computed_goto (tree); extern void expand_computed_goto (tree);
extern bool parse_output_constraint (const char **, int, int, int, extern bool parse_output_constraint (const char **, int, int, int,
......
...@@ -5435,7 +5435,7 @@ VEC(alias_pair,gc) *alias_pairs; ...@@ -5435,7 +5435,7 @@ VEC(alias_pair,gc) *alias_pairs;
or ASM_OUTPUT_DEF_FROM_DECLS. The function defines the symbol whose or ASM_OUTPUT_DEF_FROM_DECLS. The function defines the symbol whose
tree node is DECL to have the value of the tree node TARGET. */ tree node is DECL to have the value of the tree node TARGET. */
static void void
do_assemble_alias (tree decl, tree target) do_assemble_alias (tree decl, tree target)
{ {
/* Emulated TLS had better not get this var. */ /* Emulated TLS had better not get this var. */
...@@ -5535,255 +5535,6 @@ do_assemble_alias (tree decl, tree target) ...@@ -5535,255 +5535,6 @@ do_assemble_alias (tree decl, tree target)
#endif #endif
} }
/* Allocate and construct a symbol alias set. */
static symbol_alias_set_t *
symbol_alias_set_create (void)
{
return pointer_set_create ();
}
/* Destruct and free a symbol alias set. */
void
symbol_alias_set_destroy (symbol_alias_set_t *aset)
{
pointer_set_destroy (aset);
}
/* Test if a symbol alias set contains a given name. */
int
symbol_alias_set_contains (const symbol_alias_set_t *aset, tree t)
{
/* We accept either a DECL or an IDENTIFIER directly. */
if (TREE_CODE (t) != IDENTIFIER_NODE)
t = DECL_ASSEMBLER_NAME (t);
t = targetm.asm_out.mangle_assembler_name (IDENTIFIER_POINTER (t));
return pointer_set_contains (aset, t);
}
/* Enter a new name into a symbol alias set. */
static int
symbol_alias_set_insert (symbol_alias_set_t *aset, tree t)
{
/* We accept either a DECL or an IDENTIFIER directly. */
if (TREE_CODE (t) != IDENTIFIER_NODE)
t = DECL_ASSEMBLER_NAME (t);
t = targetm.asm_out.mangle_assembler_name (IDENTIFIER_POINTER (t));
return pointer_set_insert (aset, t);
}
/* IN_SET_P is a predicate function assuming to be taken
alias_pair->decl, alias_pair->target and DATA arguments.
Compute set of aliases by including everything where TRIVIALLY_VISIBLE
predeicate is true and propagate across aliases such that when
alias DECL is included, its TARGET is included too. */
static symbol_alias_set_t *
propagate_aliases_forward (bool (*in_set_p)
(tree decl, tree target, void *data),
void *data)
{
symbol_alias_set_t *set;
unsigned i;
alias_pair *p;
bool changed;
set = symbol_alias_set_create ();
for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ++i)
if (in_set_p (p->decl, p->target, data))
symbol_alias_set_insert (set, p->decl);
do
{
changed = false;
for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ++i)
if (symbol_alias_set_contains (set, p->decl)
&& !symbol_alias_set_insert (set, p->target))
changed = true;
}
while (changed);
return set;
}
/* Like propagate_aliases_forward but do backward propagation. */
symbol_alias_set_t *
propagate_aliases_backward (bool (*in_set_p)
(tree decl, tree target, void *data),
void *data)
{
symbol_alias_set_t *set;
unsigned i;
alias_pair *p;
bool changed;
/* We have to compute the set of set nodes including aliases
themselves. */
set = symbol_alias_set_create ();
for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ++i)
if (in_set_p (p->decl, p->target, data))
symbol_alias_set_insert (set, p->target);
do
{
changed = false;
for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ++i)
if (symbol_alias_set_contains (set, p->target)
&& !symbol_alias_set_insert (set, p->decl))
changed = true;
}
while (changed);
return set;
}
/* See if the alias is trivially visible. This means
1) alias is expoerted from the unit or
2) alias is used in the code.
We assume that unused cgraph/varpool nodes has been
removed.
Used as callback for propagate_aliases. */
static bool
trivially_visible_alias (tree decl, tree target ATTRIBUTE_UNUSED,
void *data ATTRIBUTE_UNUSED)
{
struct cgraph_node *fnode = NULL;
struct varpool_node *vnode = NULL;
if (!TREE_PUBLIC (decl))
{
if (TREE_CODE (decl) == FUNCTION_DECL)
fnode = cgraph_get_node (decl);
else
vnode = varpool_get_node (decl);
return vnode || fnode;
}
else
return true;
}
/* See if the target of alias is defined in this unit.
Used as callback for propagate_aliases. */
static bool
trivially_defined_alias (tree decl ATTRIBUTE_UNUSED,
tree target,
void *data ATTRIBUTE_UNUSED)
{
struct cgraph_node *fnode = NULL;
struct varpool_node *vnode = NULL;
fnode = cgraph_node_for_asm (target);
vnode = (fnode == NULL) ? varpool_node_for_asm (target) : NULL;
return (fnode && fnode->analyzed) || (vnode && vnode->finalized);
}
/* Remove the alias pairing for functions that are no longer in the call
graph. */
void
remove_unreachable_alias_pairs (void)
{
symbol_alias_set_t *visible;
unsigned i;
alias_pair *p;
if (alias_pairs == NULL)
return;
/* We have to compute the set of visible nodes including aliases
themselves. */
visible = propagate_aliases_forward (trivially_visible_alias, NULL);
for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); )
{
if (!DECL_EXTERNAL (p->decl)
&& !symbol_alias_set_contains (visible, p->decl))
{
VEC_unordered_remove (alias_pair, alias_pairs, i);
continue;
}
i++;
}
symbol_alias_set_destroy (visible);
}
/* First pass of completing pending aliases. Make sure that cgraph knows
which symbols will be required. */
void
finish_aliases_1 (void)
{
symbol_alias_set_t *defined;
unsigned i;
alias_pair *p;
if (alias_pairs == NULL)
return;
/* We have to compute the set of defined nodes including aliases
themselves. */
defined = propagate_aliases_backward (trivially_defined_alias, NULL);
FOR_EACH_VEC_ELT (alias_pair, alias_pairs, i, p)
{
tree target_decl;
target_decl = find_decl (p->target);
if (target_decl == NULL)
{
if (symbol_alias_set_contains (defined, p->target))
continue;
if (! (p->emitted_diags & ALIAS_DIAG_TO_UNDEF)
&& ! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)))
{
error ("%q+D aliased to undefined symbol %qE",
p->decl, p->target);
p->emitted_diags |= ALIAS_DIAG_TO_UNDEF;
}
}
else if (! (p->emitted_diags & ALIAS_DIAG_TO_EXTERN)
&& DECL_EXTERNAL (target_decl)
/* We use local aliases for C++ thunks to force the tailcall
to bind locally. This is a hack - to keep it working do
the following (which is not strictly correct). */
&& (! TREE_CODE (target_decl) == FUNCTION_DECL
|| ! DECL_VIRTUAL_P (target_decl))
&& ! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)))
{
error ("%q+D aliased to external symbol %qE",
p->decl, p->target);
p->emitted_diags |= ALIAS_DIAG_TO_EXTERN;
}
}
symbol_alias_set_destroy (defined);
}
/* Second pass of completing pending aliases. Emit the actual assembly.
This happens at the end of compilation and thus it is assured that the
target symbol has been emitted. */
void
finish_aliases_2 (void)
{
unsigned i;
alias_pair *p;
FOR_EACH_VEC_ELT (alias_pair, alias_pairs, i, p)
do_assemble_alias (p->decl, p->target);
VEC_truncate (alias_pair, alias_pairs, 0);
}
/* Emit an assembler directive to make the symbol for DECL an alias to /* Emit an assembler directive to make the symbol for DECL an alias to
the symbol for TARGET. */ the symbol for TARGET. */
...@@ -5845,14 +5596,14 @@ assemble_alias (tree decl, tree target) ...@@ -5845,14 +5596,14 @@ assemble_alias (tree decl, tree target)
target_decl = find_decl (target); target_decl = find_decl (target);
else else
target_decl= NULL; target_decl= NULL;
if (target_decl && TREE_ASM_WRITTEN (target_decl)) if ((target_decl && TREE_ASM_WRITTEN (target_decl))
|| cgraph_state >= CGRAPH_STATE_EXPANSION)
do_assemble_alias (decl, target); do_assemble_alias (decl, target);
else else
{ {
alias_pair *p = VEC_safe_push (alias_pair, gc, alias_pairs, NULL); alias_pair *p = VEC_safe_push (alias_pair, gc, alias_pairs, NULL);
p->decl = decl; p->decl = decl;
p->target = target; p->target = target;
p->emitted_diags = ALIAS_DIAG_NONE;
} }
} }
......
...@@ -270,7 +270,7 @@ assemble_aliases (struct varpool_node *node) ...@@ -270,7 +270,7 @@ assemble_aliases (struct varpool_node *node)
if (ref->use == IPA_REF_ALIAS) if (ref->use == IPA_REF_ALIAS)
{ {
struct varpool_node *alias = ipa_ref_referring_varpool_node (ref); struct varpool_node *alias = ipa_ref_referring_varpool_node (ref);
assemble_alias (alias->symbol.decl, do_assemble_alias (alias->symbol.decl,
DECL_ASSEMBLER_NAME (alias->alias_of)); DECL_ASSEMBLER_NAME (alias->alias_of));
assemble_aliases (alias); assemble_aliases (alias);
} }
...@@ -349,7 +349,6 @@ varpool_remove_unreferenced_decls (void) ...@@ -349,7 +349,6 @@ varpool_remove_unreferenced_decls (void)
if (cgraph_dump_file) if (cgraph_dump_file)
fprintf (cgraph_dump_file, "Trivially needed variables:"); fprintf (cgraph_dump_file, "Trivially needed variables:");
finish_aliases_1 ();
FOR_EACH_DEFINED_VARIABLE (node) FOR_EACH_DEFINED_VARIABLE (node)
{ {
if (node->analyzed if (node->analyzed
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment