sym = e;
}
+ void visit_autocast_op (autocast_op* e)
+ {
+ sym = e;
+ }
+
void throwone (const token* t)
{
if (t->type == tok_operator && t->content == ".") // guess someone misused . in $foo->bar.baz expression
void visit_target_symbol (target_symbol* e);
void visit_atvar_op (atvar_op* e);
void visit_cast_op (cast_op* e);
+ void visit_autocast_op (autocast_op* e);
void visit_defined_op (defined_op* e);
// these are a bit hairy to grok due to the intricacies of indexables and
void visit_pre_crement (pre_crement* e) { provide (e); }
void visit_post_crement (post_crement* e) { provide (e); }
void visit_assignment (assignment* e) { provide (e); }
+
+private:
+ void reduce_target_symbol (target_symbol* e, expression* operand=NULL);
};
}
void
-void_statement_reducer::visit_atvar_op (atvar_op* e)
+void_statement_reducer::reduce_target_symbol (target_symbol* e,
+ expression* operand)
{
- visit_target_symbol (e);
-}
-
-void
-void_statement_reducer::visit_target_symbol (target_symbol* e)
-{
- // When target_symbol isn't needed, it's just as good to
- // evaluate any array indexes directly
+ // When the result of any target_symbol isn't needed, it's just as good to
+ // evaluate the operand and any array indexes directly
block *b = new block;
b->tok = e->tok;
+ if (operand)
+ {
+ expr_statement *es = new expr_statement;
+ es->value = operand;
+ es->tok = es->value->tok;
+ b->statements.push_back(es);
+ }
+
for (unsigned i=0; i<e->components.size(); i++ )
{
if (e->components[i].type != target_symbol::comp_expression_array_index)
b->statements.push_back(es);
}
- if (b->statements.empty())
- {
- delete b;
- provide (e);
- return;
- }
-
- if (session.verbose>2)
- clog << _("Eliding unused target symbol ") << *e->tok << endl;
-
b->visit(this);
relaxed_p = false;
e = 0;
}
void
-void_statement_reducer::visit_cast_op (cast_op* e)
+void_statement_reducer::visit_atvar_op (atvar_op* e)
{
- // When the result of a cast operation isn't needed, it's just as good to
- // evaluate the operand and any array indexes directly
-
- block *b = new block;
- b->tok = e->tok;
-
- expr_statement *es = new expr_statement;
- es->value = e->operand;
- es->tok = es->value->tok;
- b->statements.push_back(es);
-
- for (unsigned i=0; i<e->components.size(); i++ )
- {
- if (e->components[i].type != target_symbol::comp_expression_array_index)
- continue;
+ if (session.verbose>2)
+ clog << _("Eliding unused target symbol ") << *e->tok << endl;
+ reduce_target_symbol (e);
+}
- es = new expr_statement;
- es->value = e->components[i].expr_index;
- es->tok = es->value->tok;
- b->statements.push_back(es);
- }
+void
+void_statement_reducer::visit_target_symbol (target_symbol* e)
+{
+ if (session.verbose>2)
+ clog << _("Eliding unused target symbol ") << *e->tok << endl;
+ reduce_target_symbol (e);
+}
+void
+void_statement_reducer::visit_cast_op (cast_op* e)
+{
if (session.verbose>2)
clog << _("Eliding unused typecast ") << *e->tok << endl;
+ reduce_target_symbol (e, e->operand);
+}
- b->visit(this);
- relaxed_p = false;
- e = 0;
- provide (e);
+void
+void_statement_reducer::visit_autocast_op (autocast_op* e)
+{
+ if (session.verbose>2)
+ clog << _("Eliding unused autocast ") << *e->tok << endl;
+ reduce_target_symbol (e, e->operand);
}
}
+void
+typeresolution_info::visit_autocast_op (autocast_op* e)
+{
+ // Like cast_op, a implicit autocast_op shouldn't survive this far
+ // unless it was not resolved and its value is really needed.
+ if (e->saved_conversion_error)
+ throw (* (e->saved_conversion_error));
+ else
+ throw SEMANTIC_ERROR(_("unknown type in dereference"), e->tok);
+}
+
+
void
typeresolution_info::visit_perf_op (perf_op* e)
{
void visit_stat_op (stat_op* e);
void visit_hist_op (hist_op* e);
void visit_cast_op (cast_op* e);
+ void visit_autocast_op (autocast_op* e);
void visit_atvar_op (atvar_op* e);
void visit_defined_op (defined_op* e);
void visit_entry_op (entry_op* e);
target_symbol* tsym = NULL;
// With '&' we'll definitely be making a target symbol of some sort
- bool addressof = false;
- if (peek_op ("&"))
- {
- swallow ();
- addressof = true;
- }
+ const token* addrtok = peek_op ("&") ? next () : NULL;
+ bool addressof = (addrtok != NULL);
// First try target_symbol types: $var, @cast, and @var.
const token* t = peek ();
if (!tsym && (addressof || peek_target_symbol_components ())
&& strverscmp(session.compatible.c_str(), "2.6") >= 0)
{
- cast_op *cop = new cast_op;
- cop->tok = expr->tok;
+ autocast_op *cop = new autocast_op;
+ cop->tok = addrtok ?: peek ();
cop->operand = expr;
expr = tsym = cop;
}
if (addressof)
o << "&";
o << name << '(' << *operand;
- if (type_name.length() > 0)
o << ", " << lex_cast_qstring (type_name);
if (module.length() > 0)
o << ", " << lex_cast_qstring (module);
}
+void autocast_op::print (ostream& o) const
+{
+ if (addressof)
+ o << "&";
+ o << '(' << *operand << ')';
+ for (unsigned i = 0; i < components.size(); ++i)
+ o << components[i];
+}
+
+
void defined_op::print (ostream& o) const
{
o << "@defined(" << *operand << ")";
}
+void
+autocast_op::visit (visitor* u)
+{
+ u->visit_autocast_op(this);
+}
+
+
void
atvar_op::visit (visitor* u)
{
e->visit_components (this);
}
+void
+traversing_visitor::visit_autocast_op (autocast_op* e)
+{
+ e->operand->visit (this);
+ e->visit_components (this);
+}
+
void
traversing_visitor::visit_atvar_op (atvar_op* e)
{
functioncall_traversing_visitor::visit_cast_op (e);
}
+void
+varuse_collecting_visitor::visit_autocast_op (autocast_op *e)
+{
+ // As with target_symbols, unresolved cast assignments need to preserved
+ // for later error handling.
+ if (is_active_lvalue (e))
+ embedded_seen = true;
+
+ functioncall_traversing_visitor::visit_autocast_op (e);
+}
+
void
varuse_collecting_visitor::visit_defined_op (defined_op *e)
{
throwone (e->tok);
}
+void
+throwing_visitor::visit_autocast_op (autocast_op* e)
+{
+ throwone (e->tok);
+}
+
void
throwing_visitor::visit_defined_op (defined_op* e)
{
provide (e);
}
+void
+update_visitor::visit_autocast_op (autocast_op* e)
+{
+ replace (e->operand);
+ e->visit_components (this);
+ provide (e);
+}
+
void
update_visitor::visit_atvar_op (atvar_op* e)
{
update_visitor::visit_cast_op(new cast_op(*e));
}
+void
+deep_copy_visitor::visit_autocast_op (autocast_op* e)
+{
+ update_visitor::visit_autocast_op(new autocast_op(*e));
+}
+
void
deep_copy_visitor::visit_atvar_op (atvar_op* e)
{
void visit (visitor* u);
};
+// An autocast is like an implicit @cast on any expression, like
+// (expr)->foo->var[baz], and the type is gleaned from the expr.
+struct autocast_op: public target_symbol
+{
+ expression *operand;
+ void print (std::ostream& o) const;
+ void visit (visitor* u);
+};
+
struct atvar_op: public target_symbol
{
std::string target_name, cu_name, module;
virtual void visit_stat_op (stat_op* e) = 0;
virtual void visit_hist_op (hist_op* e) = 0;
virtual void visit_cast_op (cast_op* e) = 0;
+ virtual void visit_autocast_op (autocast_op* e) = 0;
virtual void visit_atvar_op (atvar_op* e) = 0;
virtual void visit_defined_op (defined_op* e) = 0;
virtual void visit_entry_op (entry_op* e) = 0;
void visit_stat_op (stat_op* e);
void visit_hist_op (hist_op* e);
void visit_cast_op (cast_op* e);
+ void visit_autocast_op (autocast_op* e);
void visit_atvar_op (atvar_op* e);
void visit_defined_op (defined_op* e);
void visit_entry_op (entry_op* e);
void visit_post_crement (post_crement *e);
void visit_foreach_loop (foreach_loop *s);
void visit_cast_op (cast_op* e);
+ void visit_autocast_op (autocast_op* e);
void visit_atvar_op (atvar_op *e);
void visit_defined_op (defined_op* e);
void visit_entry_op (entry_op* e);
void visit_stat_op (stat_op* e);
void visit_hist_op (hist_op* e);
void visit_cast_op (cast_op* e);
+ void visit_autocast_op (autocast_op* e);
void visit_atvar_op (atvar_op* e);
void visit_defined_op (defined_op* e);
void visit_entry_op (entry_op* e);
virtual void visit_stat_op (stat_op* e);
virtual void visit_hist_op (hist_op* e);
virtual void visit_cast_op (cast_op* e);
+ virtual void visit_autocast_op (autocast_op* e);
virtual void visit_atvar_op (atvar_op* e);
virtual void visit_defined_op (defined_op* e);
virtual void visit_entry_op (entry_op* e);
virtual void visit_stat_op (stat_op* e);
virtual void visit_hist_op (hist_op* e);
virtual void visit_cast_op (cast_op* e);
+ virtual void visit_autocast_op (autocast_op* e);
virtual void visit_atvar_op (atvar_op* e);
virtual void visit_defined_op (defined_op* e);
virtual void visit_entry_op (entry_op* e);
}
+struct dwarf_autocast_expanding_visitor: public var_expanding_visitor
+{
+ systemtap_session& s;
+
+ dwarf_autocast_expanding_visitor(systemtap_session& s): s(s) {}
+ void visit_autocast_op (autocast_op* e);
+};
+
+
+void
+dwarf_autocast_expanding_visitor::visit_autocast_op (autocast_op* e)
+{
+ // TODO PR13664, glean the type from e->operand, then expand like @cast.
+
+ var_expanding_visitor::visit_autocast_op (e);
+}
+
+
struct dwarf_atvar_expanding_visitor: public var_expanding_visitor
{
systemtap_session& s;
filter = new dwarf_atvar_expanding_visitor(s, *dw);
s.code_filters.push_back(filter);
+ // NB: visit autocast last, so it can use types resolved from @cast/@var
+ filter = new dwarf_autocast_expanding_visitor(s);
+ s.code_filters.push_back(filter);
+
register_function_and_statement_variants(s, root->bind(TOK_KERNEL), dw, pr_privileged);
register_function_and_statement_variants(s, root->bind_str(TOK_MODULE), dw, pr_privileged);
root->bind(TOK_KERNEL)->bind_num(TOK_STATEMENT)->bind(TOK_ABSOLUTE)
void visit_stat_op (stat_op* e);
void visit_hist_op (hist_op* e);
void visit_cast_op (cast_op* e);
+ void visit_autocast_op (autocast_op* e);
void visit_atvar_op (atvar_op* e);
void visit_defined_op (defined_op* e);
void visit_entry_op (entry_op* e);
}
+void
+c_unparser::visit_autocast_op (autocast_op* e)
+{
+ throw SEMANTIC_ERROR(_("cannot translate general dereference expression"), e->tok);
+}
+
+
void
c_unparser::visit_defined_op (defined_op* e)
{