bool
type_base::traverse(ir_node_visitor& v)
{
+ if (v.type_node_has_been_visited(this))
+ return true;
+
v.visit_begin(this);
- return v.visit_end(this);
+ bool result = v.visit_end(this);
+ v.mark_type_node_as_visited(this);
+
+ return result;
}
type_base::~type_base()
bool
type_decl::traverse(ir_node_visitor& v)
{
+ if (v.type_node_has_been_visited(this))
+ return true;
+
v.visit_begin(this);
+ bool result = v.visit_end(this);
+ v.mark_type_node_as_visited(this);
- return v.visit_end(this);
+ return result;
}
type_decl::~type_decl()
if (visiting())
return true;
+ if (v.type_node_has_been_visited(this))
+ return true;
+
if (v.visit_begin(this))
{
visiting(true);
visiting(false);
}
- return v.visit_end(this);
+ bool result = v.visit_end(this);
+ v.mark_type_node_as_visited(this);
+
+ return result;
}
scope_type_decl::~scope_type_decl()
bool
qualified_type_def::traverse(ir_node_visitor& v)
{
+ if (v.type_node_has_been_visited(this))
+ return true;
+
if (visiting())
return true;
t->traverse(v);
visiting(false);
}
- return v.visit_end(this);
+ bool result = v.visit_end(this);
+ v.mark_type_node_as_visited(this);
+ return result;
}
qualified_type_def::~qualified_type_def()
bool
pointer_type_def::traverse(ir_node_visitor& v)
{
+ if (v.type_node_has_been_visited(this))
+ return true;
+
if (visiting())
return true;
t->traverse(v);
visiting(false);
}
- return v.visit_end(this);
+
+ bool result = v.visit_end(this);
+ v.mark_type_node_as_visited(this);
+ return result;
}
pointer_type_def::~pointer_type_def()
bool
reference_type_def::traverse(ir_node_visitor& v)
{
+ if (v.type_node_has_been_visited(this))
+ return true;
+
if (visiting())
return true;
t->traverse(v);
visiting(false);
}
- return v.visit_end(this);
+
+ bool result = v.visit_end(this);
+ v.mark_type_node_as_visited(this);
+ return result;
}
reference_type_def::~reference_type_def()
bool
array_type_def::subrange_type::traverse(ir_node_visitor& v)
{
+ if (v.type_node_has_been_visited(this))
+ return true;
+
if (v.visit_begin(this))
{
visiting(true);
visiting(false);
}
- return v.visit_end(this);
+ bool result = v.visit_end(this);
+ v.mark_type_node_as_visited(this);
+ return result;
}
// </array_type_def::subrange_type>
bool
array_type_def::traverse(ir_node_visitor& v)
{
+ if (v.type_node_has_been_visited(this))
+ return true;
+
if (visiting())
return true;
t->traverse(v);
visiting(false);
}
- return v.visit_end(this);
+
+ bool result = v.visit_end(this);
+ v.mark_type_node_as_visited(this);
+ return result;
}
const location&
bool
enum_type_decl::traverse(ir_node_visitor &v)
{
+ if (v.type_node_has_been_visited(this))
+ return true;
+
if (visiting())
return true;
t->traverse(v);
visiting(false);
}
- return v.visit_end(this);
+
+ bool result = v.visit_end(this);
+ v.mark_type_node_as_visited(this);
+ return result;
}
/// Destructor for the enum type declaration.
bool
typedef_decl::traverse(ir_node_visitor& v)
{
+ if (v.type_node_has_been_visited(this))
+ return true;
+
if (visiting())
return true;
t->traverse(v);
visiting(false);
}
- return v.visit_end(this);
+
+ bool result = v.visit_end(this);
+ v.mark_type_node_as_visited(this);
+ return result;
}
typedef_decl::~typedef_decl()
bool
function_type::traverse(ir_node_visitor& v)
{
+ // TODO: should we allow the walker to avoid visiting function type
+ // twice? I think that if we do, then ir_node_visitor needs an
+ // option to specifically disallow this feature for function types.
+
if (visiting())
return true;
bool
class_or_union::traverse(ir_node_visitor& v)
{
+ if (v.type_node_has_been_visited(this))
+ return true;
+
if (visiting())
return true;
visiting(false);
}
- return v.visit_end(this);
+ bool result = v.visit_end(this);
+ v.mark_type_node_as_visited(this);
+ return result;
}
/// Destrcutor of the @ref class_or_union type.
get_base_class()->traverse(v);
visiting(false);
}
+
return v.visit_end(this);
}
bool
class_decl::traverse(ir_node_visitor& v)
{
+ if (v.type_node_has_been_visited(this))
+ return true;
+
if (visiting())
return true;
visiting(false);
}
- return v.visit_end(this);
+ bool result = v.visit_end(this);
+ v.mark_type_node_as_visited(this);
+ return result;
}
/// Destructor of the @ref class_decl type.
bool
union_decl::traverse(ir_node_visitor& v)
{
+ if (v.type_node_has_been_visited(this))
+ return true;
+
if (visiting())
return true;
visiting(false);
}
- return v.visit_end(this);
+ bool result = v.visit_end(this);
+ v.mark_type_node_as_visited(this);
+ return result;
}
/// Destructor of the @ref union_decl type.
ir_traversable_base::traverse(ir_node_visitor&)
{return true;}
+// <ir_node_visitor stuff>
+
+/// The private data structure of the ir_node_visitor type.
+struct ir_node_visitor::priv
+{
+ pointer_set visited_ir_nodes;
+ bool allow_visiting_already_visited_type_node;
+
+ priv()
+ : allow_visiting_already_visited_type_node(true)
+ {}
+}; // end struct ir_node_visitory::priv
+
+/// Default Constructor of the ir_node_visitor type.
+ir_node_visitor::ir_node_visitor()
+ : priv_(new priv)
+{}
+
+/// Set if the walker using this visitor is allowed to re-visit a type
+/// node that was previously visited or not.
+///
+/// @param f if true, then the walker using this visitor is allowed to
+/// re-visit a type node that was previously visited.
+void
+ir_node_visitor::allow_visiting_already_visited_type_node(bool f)
+{priv_->allow_visiting_already_visited_type_node = f;}
+
+/// Get if the walker using this visitor is allowed to re-visit a type
+/// node that was previously visited or not.
+///
+/// @return true iff the walker using this visitor is allowed to
+/// re-visit a type node that was previously visited.
+bool
+ir_node_visitor::allow_visiting_already_visited_type_node() const
+{return priv_->allow_visiting_already_visited_type_node;}
+
+/// Mark a given type node as having been visited.
+///
+/// Note that for this function to work, the type node must have been
+/// canonicalized. Otherwise the process is aborted.
+///
+/// @param p the type to mark as having been visited.
+void
+ir_node_visitor::mark_type_node_as_visited(type_base *p)
+{
+ if (allow_visiting_already_visited_type_node())
+ return;
+
+ if (p == 0 || type_node_has_been_visited(p))
+ return;
+
+ type_base* canonical_type = p->get_naked_canonical_type();
+ assert(canonical_type);
+
+ size_t canonical_ptr_value = reinterpret_cast<size_t>(canonical_type);
+ priv_->visited_ir_nodes.insert(canonical_ptr_value);
+}
+
+/// Un-mark all visited type nodes.
+///
+/// That is, no type node is going to be considered as having been
+/// visited anymore.
+///
+/// In other words, after invoking this funciton,
+/// ir_node_visitor::type_node_has_been_visited() is going to return
+/// false on all type nodes.
+void
+ir_node_visitor::forget_visited_type_nodes()
+{priv_->visited_ir_nodes.clear();}
+
+/// Test if a given type node has been marked as visited.
+///
+/// @param p the type node to consider.
+///
+/// @return true iff the type node @p p has been marked as visited by
+/// the function ir_node_visitor::mark_type_node_as_visited.
+bool
+ir_node_visitor::type_node_has_been_visited(type_base* p) const
+{
+ if (allow_visiting_already_visited_type_node())
+ return false;
+
+ if (p == 0)
+ return false;
+
+ type_base *canonical_type = p->get_naked_canonical_type();
+ assert(canonical_type);
+
+ size_t ptr_value = reinterpret_cast<size_t>(canonical_type);
+ pointer_set::iterator it = priv_->visited_ir_nodes.find(ptr_value);
+ if (it == priv_->visited_ir_nodes.end())
+ return false;
+
+ return true;
+}
+
bool
ir_node_visitor::visit_begin(decl_base*)
{return true;}
ir_node_visitor::visit_end(member_class_template* d)
{return visit_end(static_cast<decl_base*>(d));}
+// </ir_node_visitor stuff>
+
// <debugging facilities>
/// Generate a different string at each invocation.