diff options
-rw-r--r-- | ChangeLog | 15 | ||||
-rw-r--r-- | elaborate.cxx | 31 | ||||
-rw-r--r-- | elaborate.h | 1 | ||||
-rw-r--r-- | parse.cxx | 49 | ||||
-rw-r--r-- | staptree.cxx | 64 | ||||
-rw-r--r-- | staptree.h | 15 | ||||
-rw-r--r-- | translate.cxx | 8 |
7 files changed, 182 insertions, 1 deletions
@@ -1,3 +1,18 @@ +2009-02-11 Josh Stone <jistone@redhat.com> + + * staptree.h (struct cast_op, visitor::visit_cast_op): New. + * staptree.cxx (cast_op::print/visit, various visitor::visit_cast_op's): + Incorporate cast_op into the basic tree operations. + * parse.cxx (parser::parse_symbol): Parse @cast operator with an + expression operand, type string, and optional module string. + * translate.cxx (c_unparser::visit_cast_op): Error out if a @cast + survives to translation. + * elaborate.cxx (typeresolution_info::visit_cast_op): Error out if a + @cast survives to type resolution. + (symbol_fetcher::visit_cast_op): treat @casts as a symbol target + (void_statement_reducer::visit_cast_op): unused @casts can be discarded, + but the operand should still be evaluated. + 2009-02-11 Dave Brolley <brolley@redhat.com> * stap-client: s/jar/zip/. diff --git a/elaborate.cxx b/elaborate.cxx index ba50defb..981fc7c7 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -701,6 +701,11 @@ struct symbol_fetcher e->base->visit_indexable (this); } + void visit_cast_op (cast_op* e) + { + sym = e; + } + void throwone (const token* t) { throw semantic_error ("Expecting symbol or array index expression", t); @@ -2505,6 +2510,7 @@ struct void_statement_reducer: public update_visitor void visit_concatenation (concatenation* e); void visit_functioncall (functioncall* e); void visit_print_format (print_format* e); + void visit_cast_op (cast_op* e); // these are a bit hairy to grok due to the intricacies of indexables and // stats, so I'm chickening out and skipping them... @@ -2772,6 +2778,19 @@ void_statement_reducer::visit_print_format (print_format* e) provide (e); } +void +void_statement_reducer::visit_cast_op (cast_op* e) +{ + // When the result of a cast operation isn't needed, it's just as good to + // evaluate the operand directly + + if (session.verbose>2) + clog << "Eliding unused typecast " << *e->tok << endl; + + relaxed_p = false; + e->operand->visit(this); +} + void semantic_pass_opt5 (systemtap_session& s, bool& relaxed_p) { @@ -3399,6 +3418,18 @@ typeresolution_info::visit_target_symbol (target_symbol* e) void +typeresolution_info::visit_cast_op (cast_op* e) +{ + // Like target_symbol, a cast_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("unresolved cast expression", e->tok); +} + + +void typeresolution_info::visit_arrayindex (arrayindex* e) { diff --git a/elaborate.h b/elaborate.h index c8697595..9cc4cbda 100644 --- a/elaborate.h +++ b/elaborate.h @@ -95,6 +95,7 @@ struct typeresolution_info: public visitor void visit_print_format (print_format* e); void visit_stat_op (stat_op* e); void visit_hist_op (hist_op* e); + void visit_cast_op (cast_op* e); }; @@ -2331,7 +2331,54 @@ parser::parse_symbol () bool pf_stream, pf_format, pf_delim, pf_newline, pf_char; - if (name.size() > 0 && name[0] == '@') + if (name == "@cast") + { + // type-punning time + cast_op *cop = new cast_op; + cop->tok = t; + cop->base_name = name; + expect_op("("); + cop->operand = parse_expression (); + expect_op(","); + expect_unknown(tok_string, cop->type); + if (peek_op (",")) + { + next(); + expect_unknown(tok_string, cop->module); + } + expect_op(")"); + while (true) + { + string c; + if (peek_op ("->")) + { + next(); + expect_ident_or_keyword (c); + cop->components.push_back + (make_pair (target_symbol::comp_struct_member, c)); + } + else if (peek_op ("[")) + { + next(); + expect_unknown (tok_number, c); + expect_op ("]"); + cop->components.push_back + (make_pair (target_symbol::comp_literal_array_index, c)); + } + else + break; + } + // if there aren't any dereferences, then the cast is pointless + if (cop->components.empty()) + { + expression *op = cop->operand; + delete cop; + return op; + } + return cop; + } + + else if (name.size() > 0 && name[0] == '@') { stat_op *sop = new stat_op; if (name == "@avg") diff --git a/staptree.cxx b/staptree.cxx index 9ffbaf09..d6586d86 100644 --- a/staptree.cxx +++ b/staptree.cxx @@ -277,6 +277,28 @@ void target_symbol::print (std::ostream& o) const } +void cast_op::print (std::ostream& o) const +{ + o << base_name << '(' << *operand; + o << ", " << lex_cast_qstring (type); + if (module.length() > 0) + o << ", " << lex_cast_qstring (module); + o << ')'; + for (unsigned i = 0; i < components.size(); ++i) + { + switch (components[i].first) + { + case comp_literal_array_index: + o << '[' << components[i].second << ']'; + break; + case comp_struct_member: + o << "->" << components[i].second; + break; + } + } +} + + void vardecl::print (ostream& o) const { o << name; @@ -1220,6 +1242,12 @@ target_symbol::visit (visitor* u) } void +cast_op::visit (visitor* u) +{ + u->visit_cast_op(this); +} + +void arrayindex::visit (visitor* u) { u->visit_arrayindex (this); @@ -1586,6 +1614,12 @@ traversing_visitor::visit_target_symbol (target_symbol*) } void +traversing_visitor::visit_cast_op (cast_op* e) +{ + e->operand->visit (this); +} + +void traversing_visitor::visit_arrayindex (arrayindex* e) { for (unsigned i=0; i<e->indexes.size(); i++) @@ -1680,6 +1714,17 @@ varuse_collecting_visitor::visit_target_symbol (target_symbol *e) } void +varuse_collecting_visitor::visit_cast_op (cast_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_cast_op (e); +} + +void varuse_collecting_visitor::visit_print_format (print_format* e) { // NB: Instead of being top-level statements, "print" and "printf" @@ -2064,6 +2109,12 @@ throwing_visitor::visit_target_symbol (target_symbol* e) } void +throwing_visitor::visit_cast_op (cast_op* e) +{ + throwone (e->tok); +} + +void throwing_visitor::visit_arrayindex (arrayindex* e) { throwone (e->tok); @@ -2297,6 +2348,13 @@ update_visitor::visit_target_symbol (target_symbol* e) } void +update_visitor::visit_cast_op (cast_op* e) +{ + e->operand = require (e->operand); + provide (e); +} + +void update_visitor::visit_arrayindex (arrayindex* e) { e->base = require (e->base); @@ -2528,6 +2586,12 @@ deep_copy_visitor::visit_target_symbol (target_symbol* e) } void +deep_copy_visitor::visit_cast_op (cast_op* e) +{ + update_visitor::visit_cast_op(new cast_op(*e)); +} + +void deep_copy_visitor::visit_arrayindex (arrayindex* e) { update_visitor::visit_arrayindex(new arrayindex(*e)); @@ -238,6 +238,15 @@ struct target_symbol: public symbol }; +struct cast_op: public target_symbol +{ + expression *operand; + std::string type, module; + void print (std::ostream& o) const; + void visit (visitor* u); +}; + + struct arrayindex: public expression { std::vector<expression*> indexes; @@ -680,6 +689,7 @@ struct visitor virtual void visit_print_format (print_format* e) = 0; 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; }; @@ -720,6 +730,7 @@ struct traversing_visitor: public visitor void visit_print_format (print_format* e); void visit_stat_op (stat_op* e); void visit_hist_op (hist_op* e); + void visit_cast_op (cast_op* e); }; @@ -759,6 +770,7 @@ struct varuse_collecting_visitor: public functioncall_traversing_visitor void visit_pre_crement (pre_crement *e); void visit_post_crement (post_crement *e); void visit_foreach_loop (foreach_loop *s); + void visit_cast_op (cast_op* e); bool side_effect_free (); bool side_effect_free_wrt (const std::set<vardecl*>& vars); @@ -808,6 +820,7 @@ struct throwing_visitor: public visitor void visit_print_format (print_format* e); void visit_stat_op (stat_op* e); void visit_hist_op (hist_op* e); + void visit_cast_op (cast_op* e); }; // A visitor similar to a traversing_visitor, but with the ability to rewrite @@ -868,6 +881,7 @@ struct update_visitor: public visitor virtual void visit_print_format (print_format* 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); private: std::stack<void *> targets; @@ -922,6 +936,7 @@ struct deep_copy_visitor: public update_visitor virtual void visit_print_format (print_format* 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); }; #endif // STAPTREE_H diff --git a/translate.cxx b/translate.cxx index 0d430ea3..da647722 100644 --- a/translate.cxx +++ b/translate.cxx @@ -150,6 +150,7 @@ struct c_unparser: public unparser, public visitor void visit_print_format (print_format* e); void visit_stat_op (stat_op* e); void visit_hist_op (hist_op* e); + void visit_cast_op (cast_op* e); }; // A shadow visitor, meant to generate temporary variable declarations @@ -3488,6 +3489,13 @@ c_unparser::visit_target_symbol (target_symbol* e) void +c_unparser::visit_cast_op (cast_op* e) +{ + throw semantic_error("cannot translate general cast expression", e->tok); +} + + +void c_tmpcounter::load_map_indices(arrayindex *e) { symbol *array; |